diff --git a/apps/dokploy/components/dashboard/settings/appearance-form.tsx b/apps/dokploy/components/dashboard/settings/appearance-form.tsx index a10b0d051..9bafbedab 100644 --- a/apps/dokploy/components/dashboard/settings/appearance-form.tsx +++ b/apps/dokploy/components/dashboard/settings/appearance-form.tsx @@ -37,7 +37,7 @@ const appearanceFormSchema = z.object({ theme: z.enum(["light", "dark", "system"], { required_error: "Please select a theme.", }), - language: z.enum(["en", "zh-Hans"], { + language: z.enum(["en", "pl", "zh-Hans"], { required_error: "Please select a language.", }), }); @@ -174,6 +174,7 @@ export function AppearanceForm() { {[ { label: "English", value: "en" }, + { label: "Polski", value: "pl" }, { label: "简体中文", value: "zh-Hans" }, ].map((preset) => ( diff --git a/apps/dokploy/components/dashboard/settings/servers/actions/show-dokploy-actions.tsx b/apps/dokploy/components/dashboard/settings/servers/actions/show-dokploy-actions.tsx index 5f09e8fd6..ee749244e 100644 --- a/apps/dokploy/components/dashboard/settings/servers/actions/show-dokploy-actions.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/actions/show-dokploy-actions.tsx @@ -1,6 +1,7 @@ import { Button } from "@/components/ui/button"; import React from "react"; +import { UpdateServerIp } from "@/components/dashboard/settings/web-server/update-server-ip"; import { DropdownMenu, DropdownMenuContent, @@ -44,13 +45,27 @@ export const ShowDokployActions = () => { toast.success("Server Reloaded"); }); }} + className="cursor-pointer" > {t("settings.server.webServer.reload")} - {t("settings.server.webServer.watchLogs")} + e.preventDefault()} + > + {t("settings.server.webServer.watchLogs")} + + + e.preventDefault()} + > + {t("settings.server.webServer.updateServerIp")} + + diff --git a/apps/dokploy/components/dashboard/settings/servers/actions/show-server-actions.tsx b/apps/dokploy/components/dashboard/settings/servers/actions/show-server-actions.tsx index 1f7f2d146..fcc0e315f 100644 --- a/apps/dokploy/components/dashboard/settings/servers/actions/show-server-actions.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/actions/show-server-actions.tsx @@ -1,4 +1,3 @@ -import { CardDescription, CardTitle } from "@/components/ui/card"; import { Dialog, DialogContent, @@ -21,13 +20,13 @@ export const ShowServerActions = ({ serverId }: Props) => { e.preventDefault()} > View Actions - +
Web server settings Reload or clean the web server. diff --git a/apps/dokploy/components/dashboard/settings/servers/actions/show-traefik-actions.tsx b/apps/dokploy/components/dashboard/settings/servers/actions/show-traefik-actions.tsx index 5488712c7..4385dc6a3 100644 --- a/apps/dokploy/components/dashboard/settings/servers/actions/show-traefik-actions.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/actions/show-traefik-actions.tsx @@ -74,16 +74,22 @@ export const ShowTraefikActions = ({ serverId }: Props) => { toast.error("Error to reload the traefik"); }); }} + className="cursor-pointer" > {t("settings.server.webServer.reload")} - {t("settings.server.webServer.watchLogs")} + e.preventDefault()} + className="cursor-pointer" + > + {t("settings.server.webServer.watchLogs")} + e.preventDefault()} - className="w-full cursor-pointer space-x-3" + className="cursor-pointer" > {t("settings.server.webServer.traefik.modifyEnv")} diff --git a/apps/dokploy/components/dashboard/settings/web-server/show-modal-logs.tsx b/apps/dokploy/components/dashboard/settings/web-server/show-modal-logs.tsx index 607ff7b2f..2693f79c0 100644 --- a/apps/dokploy/components/dashboard/settings/web-server/show-modal-logs.tsx +++ b/apps/dokploy/components/dashboard/settings/web-server/show-modal-logs.tsx @@ -58,14 +58,7 @@ export const ShowModalLogs = ({ appName, children, serverId }: Props) => { }, [data]); return ( - - e.preventDefault()} - > - {children} - - + {children} View Logs diff --git a/apps/dokploy/components/dashboard/settings/web-server/update-server-ip.tsx b/apps/dokploy/components/dashboard/settings/web-server/update-server-ip.tsx new file mode 100644 index 000000000..264b10ac5 --- /dev/null +++ b/apps/dokploy/components/dashboard/settings/web-server/update-server-ip.tsx @@ -0,0 +1,161 @@ +import { AlertBlock } from "@/components/shared/alert-block"; +import { CodeEditor } from "@/components/shared/code-editor"; +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import { api } from "@/utils/api"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { RefreshCw } from "lucide-react"; +import { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import { toast } from "sonner"; +import { z } from "zod"; + +const schema = z.object({ + serverIp: z.string(), +}); + +type Schema = z.infer; + +interface Props { + children?: React.ReactNode; + serverId?: string; +} + +export const UpdateServerIp = ({ children, serverId }: Props) => { + const [isOpen, setIsOpen] = useState(false); + + const { data } = api.admin.one.useQuery(); + const { data: ip } = api.server.publicIp.useQuery(); + + const { mutateAsync, isLoading, error, isError } = + api.admin.update.useMutation(); + + const form = useForm({ + defaultValues: { + serverIp: data?.serverIp || "", + }, + resolver: zodResolver(schema), + }); + + useEffect(() => { + if (data) { + form.reset({ + serverIp: data.serverIp || "", + }); + } + }, [form, form.reset, data]); + + const utils = api.useUtils(); + + const setCurrentIp = () => { + if (!ip) return; + form.setValue("serverIp", ip); + }; + + const onSubmit = async (data: Schema) => { + await mutateAsync({ + serverIp: data.serverIp, + }) + .then(async () => { + toast.success("Server IP Updated"); + await utils.admin.one.invalidate(); + setIsOpen(false); + }) + .catch(() => { + toast.error("Error to update the IP of the server"); + }); + }; + + return ( + + {children} + + + Update Server IP + Update the IP of the server + + {isError && {error?.message}} + +
+ + ( + + Server IP + +
+ + + + + + + + +

Set current public IP

+
+
+
+
+
+
+										
+									
+
+ )} + /> + + + + + + +
+
+ ); +}; diff --git a/apps/dokploy/components/dashboard/settings/web-server/update-server.tsx b/apps/dokploy/components/dashboard/settings/web-server/update-server.tsx index 165918652..757c77955 100644 --- a/apps/dokploy/components/dashboard/settings/web-server/update-server.tsx +++ b/apps/dokploy/components/dashboard/settings/web-server/update-server.tsx @@ -87,7 +87,7 @@ export const UpdateServer = () => { }} isLoading={isLoading} > - Check updates + Check Updates )}
diff --git a/apps/dokploy/next-i18next.config.cjs b/apps/dokploy/next-i18next.config.cjs index 5c20bbea8..bac301cb4 100644 --- a/apps/dokploy/next-i18next.config.cjs +++ b/apps/dokploy/next-i18next.config.cjs @@ -2,7 +2,7 @@ module.exports = { i18n: { defaultLocale: "en", - locales: ["en", "zh-Hans"], + locales: ["en", "pl", "zh-Hans"], localeDetection: false, }, fallbackLng: "en", diff --git a/apps/dokploy/pages/_app.tsx b/apps/dokploy/pages/_app.tsx index b5fcb1319..18cb3e7e6 100644 --- a/apps/dokploy/pages/_app.tsx +++ b/apps/dokploy/pages/_app.tsx @@ -71,7 +71,7 @@ export default api.withTRPC( { i18n: { defaultLocale: "en", - locales: ["en", "zh-Hans"], + locales: ["en", "pl", "zh-Hans"], localeDetection: false, }, fallbackLng: "en", diff --git a/apps/dokploy/public/locales/en/settings.json b/apps/dokploy/public/locales/en/settings.json index 594323f4a..2103ecc00 100644 --- a/apps/dokploy/public/locales/en/settings.json +++ b/apps/dokploy/public/locales/en/settings.json @@ -14,6 +14,7 @@ "settings.server.webServer.actions": "Actions", "settings.server.webServer.reload": "Reload", "settings.server.webServer.watchLogs": "Watch logs", + "settings.server.webServer.updateServerIp": "Update Server IP", "settings.server.webServer.server.label": "Server", "settings.server.webServer.traefik.label": "Traefik", "settings.server.webServer.traefik.modifyEnv": "Modify Env", diff --git a/apps/dokploy/public/locales/pl/common.json b/apps/dokploy/public/locales/pl/common.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/apps/dokploy/public/locales/pl/common.json @@ -0,0 +1 @@ +{} diff --git a/apps/dokploy/public/locales/pl/settings.json b/apps/dokploy/public/locales/pl/settings.json new file mode 100644 index 000000000..48531e69a --- /dev/null +++ b/apps/dokploy/public/locales/pl/settings.json @@ -0,0 +1,44 @@ +{ + "settings.common.save": "Zapisz", + "settings.server.domain.title": "Domena", + "settings.server.domain.description": "Dodaj domenę do aplikacji", + "settings.server.domain.form.domain": "Domena", + "settings.server.domain.form.letsEncryptEmail": "Email Let's Encrypt", + "settings.server.domain.form.certificate.label": "Certyfikat", + "settings.server.domain.form.certificate.placeholder": "Wybierz certyfikat", + "settings.server.domain.form.certificateOptions.none": "Brak", + "settings.server.domain.form.certificateOptions.letsencrypt": "Let's Encrypt (Domyślny)", + + "settings.server.webServer.title": "Serwer", + "settings.server.webServer.description": "Przeładuj lub wyczyść serwer", + "settings.server.webServer.actions": "Akcje", + "settings.server.webServer.reload": "Przeładuj", + "settings.server.webServer.watchLogs": "Obserwuj logi", + "settings.server.webServer.updateServerIp": "Zaktualizuj IP serwera", + "settings.server.webServer.server.label": "Serwer", + "settings.server.webServer.traefik.label": "Traefik", + "settings.server.webServer.traefik.modifyEnv": "Zmodyfikuj środowisko", + "settings.server.webServer.storage.label": "Przestrzeń", + "settings.server.webServer.storage.cleanUnusedImages": "Wyczyść nieużywane obrazy", + "settings.server.webServer.storage.cleanUnusedVolumes": "Wyczyść nieużywane wolumeny", + "settings.server.webServer.storage.cleanStoppedContainers": "Wyczyść zatrzymane kontenery", + "settings.server.webServer.storage.cleanDockerBuilder": "Wyczyść Docker Builder i System", + "settings.server.webServer.storage.cleanMonitoring": "Wyczyść monitorowanie", + "settings.server.webServer.storage.cleanAll": "Wyczyść wszystko", + + "settings.profile.title": "Konto", + "settings.profile.description": "Zmień szczegóły swojego profilu", + "settings.profile.email": "Email", + "settings.profile.password": "Hasło", + "settings.profile.avatar": "Avatar", + + "settings.appearance.title": "Wygląd", + "settings.appearance.description": "Dostosuj motyw swojego pulpitu", + "settings.appearance.theme": "Motyw", + "settings.appearance.themeDescription": "Wybierz motyw swojego pulpitu", + "settings.appearance.themes.light": "Jasny", + "settings.appearance.themes.dark": "Ciemny", + "settings.appearance.themes.system": "System", + "settings.appearance.language": "Język", + "settings.appearance.languageDescription": "Wybierz język swojego pulpitu" +} diff --git a/apps/dokploy/server/api/routers/admin.ts b/apps/dokploy/server/api/routers/admin.ts index 42ce15bc0..6029c7136 100644 --- a/apps/dokploy/server/api/routers/admin.ts +++ b/apps/dokploy/server/api/routers/admin.ts @@ -4,6 +4,7 @@ import { apiCreateUserInvitation, apiFindOneToken, apiRemoveUser, + apiUpdateAdmin, users, } from "@/server/db/schema"; import { @@ -13,6 +14,7 @@ import { findUserById, getUserByToken, removeUserByAuthId, + updateAdmin, } from "@dokploy/server"; import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; @@ -26,6 +28,18 @@ export const adminRouter = createTRPCRouter({ ...rest, }; }), + update: adminProcedure + .input(apiUpdateAdmin) + .mutation(async ({ input, ctx }) => { + if (ctx.user.rol === "user") { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not allowed to update this admin", + }); + } + const { authId } = await findAdminById(ctx.user.adminId); + return updateAdmin(authId, input); + }), createUserInvitation: adminProcedure .input(apiCreateUserInvitation) .mutation(async ({ input, ctx }) => { diff --git a/apps/dokploy/server/api/routers/server.ts b/apps/dokploy/server/api/routers/server.ts index 6caaa9c8b..0d4ef87f3 100644 --- a/apps/dokploy/server/api/routers/server.ts +++ b/apps/dokploy/server/api/routers/server.ts @@ -22,6 +22,7 @@ import { findAdminById, findServerById, findServersByAdminId, + getPublicIpWithFallback, haveActiveServices, removeDeploymentsByServerId, serverSetup, @@ -181,4 +182,11 @@ export const serverRouter = createTRPCRouter({ throw error; } }), + publicIp: protectedProcedure.query(async ({ ctx }) => { + if (IS_CLOUD) { + return ""; + } + const ip = await getPublicIpWithFallback(); + return ip; + }), }); diff --git a/apps/dokploy/utils/hooks/use-locale.ts b/apps/dokploy/utils/hooks/use-locale.ts index f00e0df84..3c64f6438 100644 --- a/apps/dokploy/utils/hooks/use-locale.ts +++ b/apps/dokploy/utils/hooks/use-locale.ts @@ -1,6 +1,6 @@ import Cookies from "js-cookie"; -const SUPPORTED_LOCALES = ["en", "zh-Hans"] as const; +const SUPPORTED_LOCALES = ["en", "pl", "zh-Hans"] as const; type Locale = (typeof SUPPORTED_LOCALES)[number]; diff --git a/packages/server/src/db/schema/admin.ts b/packages/server/src/db/schema/admin.ts index cce611c24..222fb16c8 100644 --- a/packages/server/src/db/schema/admin.ts +++ b/packages/server/src/db/schema/admin.ts @@ -53,6 +53,8 @@ const createSchema = createInsertSchema(admins, { letsEncryptEmail: z.string().optional(), }); +export const apiUpdateAdmin = createSchema.partial(); + export const apiSaveSSHKey = createSchema .pick({ sshPrivateKey: true,