From fd0a9b8b585682519bf0f199e163a73c2f30b78c Mon Sep 17 00:00:00 2001 From: UndefinedPony Date: Sun, 22 Dec 2024 18:46:02 +0100 Subject: [PATCH] feat: add local server config, add local server support in terminal modal, add fixed terminal container height --- .../web-server/local-server-config.tsx | 154 ++++++++++++++++++ .../settings/web-server/terminal-modal.tsx | 26 ++- 2 files changed, 176 insertions(+), 4 deletions(-) create mode 100644 apps/dokploy/components/dashboard/settings/web-server/local-server-config.tsx diff --git a/apps/dokploy/components/dashboard/settings/web-server/local-server-config.tsx b/apps/dokploy/components/dashboard/settings/web-server/local-server-config.tsx new file mode 100644 index 00000000..fde03ffb --- /dev/null +++ b/apps/dokploy/components/dashboard/settings/web-server/local-server-config.tsx @@ -0,0 +1,154 @@ +import { Button, buttonVariants } from "@/components/ui/button"; +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from "@/components/ui/accordion"; +import { Input } from "@/components/ui/input"; +import { + FormControl, + FormLabel, + FormField, + FormMessage, + FormItem, + Form, +} from "@/components/ui/form"; +import { cn } from "@/lib/utils"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { Settings } from "lucide-react"; +import React from "react"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; +import { useTranslation } from "next-i18next"; + +const Schema = z.object({ + port: z.number().min(1, "Port must be higher than 0"), + username: z.string().min(1, "Username is required"), +}); + +type Schema = z.infer; + +const DEFAULT_LOCAL_SERVER_DATA: Schema = { + port: 22, + username: "root", +}; + +/** Returns local server data for use with local server terminal */ +export const getLocalServerData = () => { + try { + const localServerData = localStorage.getItem("localServerData"); + const parsedLocalServerData = localServerData + ? (JSON.parse(localServerData) as typeof DEFAULT_LOCAL_SERVER_DATA) + : DEFAULT_LOCAL_SERVER_DATA; + + return parsedLocalServerData; + } catch { + return DEFAULT_LOCAL_SERVER_DATA; + } +}; + +interface Props { + onSave: () => void; +} + +const LocalServerConfig = ({ onSave }: Props) => { + const { t } = useTranslation("settings"); + + const form = useForm({ + defaultValues: getLocalServerData(), + resolver: zodResolver(Schema), + }); + + const onSubmit = (data: Schema) => { + localStorage.setItem("localServerData", JSON.stringify(data)); + form.reset(data); + onSave(); + }; + + return ( + + + +
+
+ + + {t("settings.terminal.connectionSettings")} + +
+
+
+ + +
+ + ( + + {t("settings.terminal.port")} + + { + const value = e.target.value; + if (value === "") { + field.onChange(1); + } else { + const number = Number.parseInt(value, 10); + if (!Number.isNaN(number)) { + field.onChange(number); + } + } + }} + /> + + + + + )} + /> + + ( + + {t("settings.terminal.username")} + + + + + + + )} + /> + + + + +
+
+
+ ); +}; + +export default LocalServerConfig; diff --git a/apps/dokploy/components/dashboard/settings/web-server/terminal-modal.tsx b/apps/dokploy/components/dashboard/settings/web-server/terminal-modal.tsx index 5bdba8b8..2bfd00a0 100644 --- a/apps/dokploy/components/dashboard/settings/web-server/terminal-modal.tsx +++ b/apps/dokploy/components/dashboard/settings/web-server/terminal-modal.tsx @@ -10,24 +10,38 @@ import { DropdownMenuItem } from "@/components/ui/dropdown-menu"; import { api } from "@/utils/api"; import dynamic from "next/dynamic"; import type React from "react"; +import { useState } from "react"; +import LocalServerConfig from "./local-server-config"; const Terminal = dynamic(() => import("./terminal").then((e) => e.Terminal), { ssr: false, }); +const getTerminalKey = () => { + return `terminal-${Date.now()}`; +}; + interface Props { children?: React.ReactNode; serverId: string; } export const TerminalModal = ({ children, serverId }: Props) => { + const [terminalKey, setTerminalKey] = useState(getTerminalKey()); + const isLocalServer = serverId === "local"; + const { data } = api.server.one.useQuery( { serverId, }, - { enabled: !!serverId }, + { enabled: !!serverId && !isLocalServer }, ); + const handleLocalServerConfigSave = () => { + // Rerender Terminal component to reconnect using new component key when saving local server config + setTerminalKey(getTerminalKey()); + }; + return ( @@ -43,12 +57,16 @@ export const TerminalModal = ({ children, serverId }: Props) => { onEscapeKeyDown={(event) => event.preventDefault()} > - Terminal ({data?.name}) + Terminal ({data?.name ?? serverId}) Easy way to access the server -
- + {isLocalServer && ( + + )} + +
+