refactor: make command globally available

This commit is contained in:
djknaeckebrot
2024-12-10 14:15:39 +01:00
parent 029cbf4498
commit 54b6a850b7
3 changed files with 111 additions and 112 deletions

View File

@@ -36,7 +36,6 @@ import { Fragment } from "react";
import { toast } from "sonner"; import { toast } from "sonner";
import { ProjectEnviroment } from "./project-enviroment"; import { ProjectEnviroment } from "./project-enviroment";
import { UpdateProject } from "./update"; import { UpdateProject } from "./update";
import { SearchCommand } from "@/components/dashboard/search-command";
export const ShowProjects = () => { export const ShowProjects = () => {
const utils = api.useUtils(); const utils = api.useUtils();
@@ -54,9 +53,6 @@ export const ShowProjects = () => {
return ( return (
<> <>
{/*@ts-expect-error Type mismatch*/}
<SearchCommand data={data} />
{data?.length === 0 && ( {data?.length === 0 && (
<div className="mt-6 flex h-[50vh] w-full flex-col items-center justify-center space-y-4"> <div className="mt-6 flex h-[50vh] w-full flex-col items-center justify-center space-y-4">
<FolderInput className="size-10 md:size-28 text-muted-foreground" /> <FolderInput className="size-10 md:size-28 text-muted-foreground" />

View File

@@ -25,17 +25,17 @@ import {
PostgresqlIcon, PostgresqlIcon,
RedisIcon, RedisIcon,
} from "@/components/icons/data-tools-icons"; } from "@/components/icons/data-tools-icons";
import { api } from "@/utils/api";
import { truncate } from "lodash";
type Project = Awaited<ReturnType<typeof findProjectById>>; type Project = Awaited<ReturnType<typeof findProjectById>>;
interface Props { export const SearchCommand = () => {
data: Project[];
}
export const SearchCommand = ({ data }: Props) => {
const router = useRouter(); const router = useRouter();
const [open, setOpen] = React.useState(false); const [open, setOpen] = React.useState(false);
const { data } = api.project.all.useQuery();
React.useEffect(() => { React.useEffect(() => {
const down = (e: KeyboardEvent) => { const down = (e: KeyboardEvent) => {
if (e.key === "j" && (e.metaKey || e.ctrlKey)) { if (e.key === "j" && (e.metaKey || e.ctrlKey)) {
@@ -53,61 +53,11 @@ export const SearchCommand = ({ data }: Props) => {
return ( return (
<div> <div>
<CommandDialog open={open} onOpenChange={setOpen}> <CommandDialog open={open} onOpenChange={setOpen}>
<CommandInput placeholder={"Search projects"} /> <CommandInput placeholder={"Search projects or settings"} />
<CommandList> <CommandList>
<CommandEmpty> <CommandEmpty>
No projects added yet. Click on Create project. No projects added yet. Click on Create project.
</CommandEmpty> </CommandEmpty>
<CommandGroup heading={"Application"}>
<CommandItem
onSelect={() => {
router.push("/dashboard/projects");
setOpen(false);
}}
>
Projects
</CommandItem>
<CommandItem
onSelect={() => {
router.push("/dashboard/monitoring");
setOpen(false);
}}
>
Monitoring
</CommandItem>
<CommandItem
onSelect={() => {
router.push("/dashboard/traefik");
setOpen(false);
}}
>
Treafik
</CommandItem>
<CommandItem
onSelect={() => {
router.push("/dashboard/docker");
setOpen(false);
}}
>
Docker
</CommandItem>
<CommandItem
onSelect={() => {
router.push("/dashboard/requests");
setOpen(false);
}}
>
Requests
</CommandItem>
<CommandItem
onSelect={() => {
router.push("/dashboard/profile");
setOpen(false);
}}
>
Settings
</CommandItem>
</CommandGroup>
<CommandGroup heading={"Projects"}> <CommandGroup heading={"Projects"}>
<CommandList> <CommandList>
{data?.map((project) => ( {data?.map((project) => (
@@ -162,6 +112,57 @@ export const SearchCommand = ({ data }: Props) => {
})} })}
</CommandList> </CommandList>
</CommandGroup> </CommandGroup>
<CommandSeparator />
<CommandGroup heading={"Application"} hidden={true}>
<CommandItem
onSelect={() => {
router.push("/dashboard/projects");
setOpen(false);
}}
>
Projects
</CommandItem>
<CommandItem
onSelect={() => {
router.push("/dashboard/monitoring");
setOpen(false);
}}
>
Monitoring
</CommandItem>
<CommandItem
onSelect={() => {
router.push("/dashboard/traefik");
setOpen(false);
}}
>
Traefik
</CommandItem>
<CommandItem
onSelect={() => {
router.push("/dashboard/docker");
setOpen(false);
}}
>
Docker
</CommandItem>
<CommandItem
onSelect={() => {
router.push("/dashboard/requests");
setOpen(false);
}}
>
Requests
</CommandItem>
<CommandItem
onSelect={() => {
router.push("/dashboard/profile");
setOpen(false);
}}
>
Settings
</CommandItem>
</CommandGroup>
</CommandList> </CommandList>
</CommandDialog> </CommandDialog>
</div> </div>

View File

@@ -11,72 +11,74 @@ import { Inter } from "next/font/google";
import Head from "next/head"; import Head from "next/head";
import Script from "next/script"; import Script from "next/script";
import type { ReactElement, ReactNode } from "react"; import type { ReactElement, ReactNode } from "react";
import { SearchCommand } from "@/components/dashboard/search-command";
const inter = Inter({ subsets: ["latin"] }); const inter = Inter({ subsets: ["latin"] });
export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & { export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
getLayout?: (page: ReactElement) => ReactNode; getLayout?: (page: ReactElement) => ReactNode;
// session: Session | null; // session: Session | null;
theme?: string; theme?: string;
}; };
type AppPropsWithLayout = AppProps & { type AppPropsWithLayout = AppProps & {
Component: NextPageWithLayout; Component: NextPageWithLayout;
}; };
const MyApp = ({ const MyApp = ({
Component, Component,
pageProps: { ...pageProps }, pageProps: { ...pageProps },
}: AppPropsWithLayout) => { }: AppPropsWithLayout) => {
const getLayout = Component.getLayout ?? ((page) => page); const getLayout = Component.getLayout ?? ((page) => page);
return ( return (
<> <>
<style jsx global>{` <style jsx global>{`
:root { :root {
--font-inter: ${inter.style.fontFamily}; --font-inter: ${inter.style.fontFamily};
} }
`}</style> `}</style>
<Head> <Head>
<title>Dokploy</title> <title>Dokploy</title>
</Head> </Head>
{process.env.NEXT_PUBLIC_UMAMI_HOST && {process.env.NEXT_PUBLIC_UMAMI_HOST &&
process.env.NEXT_PUBLIC_UMAMI_WEBSITE_ID && ( process.env.NEXT_PUBLIC_UMAMI_WEBSITE_ID && (
<Script <Script
src={process.env.NEXT_PUBLIC_UMAMI_HOST} src={process.env.NEXT_PUBLIC_UMAMI_HOST}
data-website-id={process.env.NEXT_PUBLIC_UMAMI_WEBSITE_ID} data-website-id={process.env.NEXT_PUBLIC_UMAMI_WEBSITE_ID}
/> />
)} )}
<ThemeProvider <ThemeProvider
attribute="class" attribute="class"
defaultTheme="system" defaultTheme="system"
enableSystem enableSystem
disableTransitionOnChange disableTransitionOnChange
forcedTheme={Component.theme} forcedTheme={Component.theme}
> >
<Toaster richColors /> <Toaster richColors />
{getLayout(<Component {...pageProps} />)} <SearchCommand />
</ThemeProvider> {getLayout(<Component {...pageProps} />)}
</> </ThemeProvider>
); </>
);
}; };
export default api.withTRPC( export default api.withTRPC(
appWithTranslation( appWithTranslation(
MyApp, MyApp,
// keep this in sync with next-i18next.config.js // keep this in sync with next-i18next.config.js
// if you want to know why don't just import the config file, this because next-i18next.config.js must be a CJS, but the rest of the code is ESM. // if you want to know why don't just import the config file, this because next-i18next.config.js must be a CJS, but the rest of the code is ESM.
// Add the config here is due to the issue: https://github.com/i18next/next-i18next/issues/2259 // Add the config here is due to the issue: https://github.com/i18next/next-i18next/issues/2259
// if one day every page is translated, we can safely remove this config. // if one day every page is translated, we can safely remove this config.
{ {
i18n: { i18n: {
defaultLocale: "en", defaultLocale: "en",
locales: Object.values(Languages), locales: Object.values(Languages),
localeDetection: false, localeDetection: false,
}, },
fallbackLng: "en", fallbackLng: "en",
keySeparator: false, keySeparator: false,
}, }
), )
); );