diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 015095aa6..52fd7f2f8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -52,7 +52,7 @@ feat: add new feature Before you start, please make the clone based on the `canary` branch, since the `main` branch is the source of truth and should always reflect the latest stable release, also the PRs will be merged to the `canary` branch. -We use Node v20.9.0 +We use Node v20.9.0 and recommend this specific version. If you have nvm installed, you can run `nvm install 20.9.0 && nvm use` in the root directory. ```bash git clone https://github.com/dokploy/dokploy.git @@ -87,6 +87,8 @@ pnpm run dokploy:dev Go to http://localhost:3000 to see the development server +Note: this project uses Biome. If your editor is configured to use another formatter such as Prettier, it's recommended to either change it to use Biome or turn it off. + ## Build ```bash diff --git a/apps/dokploy/components/dashboard/database/backups/restore-backup.tsx b/apps/dokploy/components/dashboard/database/backups/restore-backup.tsx index 10ebbe083..797e1ca81 100644 --- a/apps/dokploy/components/dashboard/database/backups/restore-backup.tsx +++ b/apps/dokploy/components/dashboard/database/backups/restore-backup.tsx @@ -84,6 +84,7 @@ export const RestoreBackup = ({ }: Props) => { const [isOpen, setIsOpen] = useState(false); const [search, setSearch] = useState(""); + const [debouncedSearchTerm, setDebouncedSearchTerm] = useState(""); const { data: destinations = [] } = api.destination.all.useQuery(); @@ -99,13 +100,18 @@ export const RestoreBackup = ({ const destionationId = form.watch("destinationId"); const debouncedSetSearch = debounce((value: string) => { + setDebouncedSearchTerm(value); + }, 150); + + const handleSearchChange = (value: string) => { setSearch(value); - }, 300); + debouncedSetSearch(value); + }; const { data: files = [], isLoading } = api.backup.listBackupFiles.useQuery( { destinationId: destionationId, - search, + search: debouncedSearchTerm, serverId: serverId ?? "", }, { @@ -284,7 +290,8 @@ export const RestoreBackup = ({ {isLoading ? ( @@ -308,6 +315,8 @@ export const RestoreBackup = ({ key={file} onSelect={() => { form.setValue("backupFile", file); + setSearch(file); + setDebouncedSearchTerm(file); }} >
diff --git a/apps/dokploy/components/dashboard/settings/git/gitlab/add-gitlab-provider.tsx b/apps/dokploy/components/dashboard/settings/git/gitlab/add-gitlab-provider.tsx index 4dd7da93c..023e46ed2 100644 --- a/apps/dokploy/components/dashboard/settings/git/gitlab/add-gitlab-provider.tsx +++ b/apps/dokploy/components/dashboard/settings/git/gitlab/add-gitlab-provider.tsx @@ -248,7 +248,9 @@ export const AddGitlabProvider = () => { name="groupName" render={({ field }) => ( - Group Name (Optional) + + Group Name (Optional, Comma-Separated List) + { name="groupName" render={({ field }) => ( - Group Name (Optional) + + Group Name (Optional, Comma-Separated List) + { const [isDialogOpen, setIsDialogOpen] = useState(false); const [step, setStep] = useState<"password" | "verify">("password"); const [isPasswordLoading, setIsPasswordLoading] = useState(false); + const [otpValue, setOtpValue] = useState(""); - const handlePasswordSubmit = async (formData: PasswordForm) => { - setIsPasswordLoading(true); - try { - const { data: enableData, error } = await authClient.twoFactor.enable({ - password: formData.password, - issuer: formData.issuer, - }); - - if (!enableData) { - throw new Error(error?.message || "Error enabling 2FA"); - } - - if (enableData.backupCodes) { - setBackupCodes(enableData.backupCodes); - } - - if (enableData.totpURI) { - const qrCodeUrl = await QRCode.toDataURL(enableData.totpURI); - - setData({ - qrCodeUrl, - secret: enableData.totpURI.split("secret=")[1]?.split("&")[0] || "", - totpURI: enableData.totpURI, - }); - - setStep("verify"); - toast.success("Scan the QR code with your authenticator app"); - } else { - throw new Error("No TOTP URI received from server"); - } - } catch (error) { - toast.error( - error instanceof Error ? error.message : "Error setting up 2FA", - ); - passwordForm.setError("password", { - message: - error instanceof Error ? error.message : "Error setting up 2FA", - }); - } finally { - setIsPasswordLoading(false); - } - }; - - const handleVerifySubmit = async (formData: PinForm) => { + const handleVerifySubmit = async (e: React.FormEvent) => { + e.preventDefault(); try { const result = await authClient.twoFactor.verifyTotp({ - code: formData.pin, + code: otpValue, }); if (result.error) { if (result.error.code === "INVALID_TWO_FACTOR_AUTHENTICATION") { - pinForm.setError("pin", { - message: "Invalid code. Please try again.", - }); toast.error("Invalid verification code"); return; } @@ -137,15 +93,11 @@ export const Enable2FA = () => { ? "Connection error. Please check your internet connection." : error.message; - pinForm.setError("pin", { - message: errorMessage, - }); toast.error(errorMessage); } else { - pinForm.setError("pin", { - message: "Error verifying code", + toast.error("Error verifying 2FA code", { + description: error instanceof Error ? error.message : "Unknown error", }); - toast.error("Error verifying 2FA code"); } } }; @@ -169,10 +121,62 @@ export const Enable2FA = () => { setStep("password"); setData(null); setBackupCodes([]); - passwordForm.reset(); - pinForm.reset(); + setOtpValue(""); + passwordForm.reset({ + password: "", + issuer: "", + }); } - }, [isDialogOpen, passwordForm, pinForm]); + }, [isDialogOpen, passwordForm]); + + useEffect(() => { + if (step === "verify") { + setOtpValue(""); + } + }, [step]); + + const handlePasswordSubmit = async (formData: PasswordForm) => { + setIsPasswordLoading(true); + try { + const { data: enableData, error } = await authClient.twoFactor.enable({ + password: formData.password, + issuer: formData.issuer, + }); + + if (!enableData) { + throw new Error(error?.message || "Error enabling 2FA"); + } + + if (enableData.backupCodes) { + setBackupCodes(enableData.backupCodes); + } + + if (enableData.totpURI) { + const qrCodeUrl = await QRCode.toDataURL(enableData.totpURI); + + setData({ + qrCodeUrl, + secret: enableData.totpURI.split("secret=")[1]?.split("&")[0] || "", + totpURI: enableData.totpURI, + }); + + setStep("verify"); + toast.success("Scan the QR code with your authenticator app"); + } else { + throw new Error("No TOTP URI received from server"); + } + } catch (error) { + toast.error( + error instanceof Error ? error.message : "Error setting up 2FA", + ); + passwordForm.setError("password", { + message: + error instanceof Error ? error.message : "Error setting up 2FA", + }); + } finally { + setIsPasswordLoading(false); + } + }; return ( @@ -233,7 +237,8 @@ export const Enable2FA = () => { /> - Enter your password to enable 2FA + Use a custom issuer to identify the service you're + authenticating with. @@ -250,11 +255,7 @@ export const Enable2FA = () => { ) : (
- +
{data?.qrCodeUrl ? ( <> @@ -306,36 +307,33 @@ export const Enable2FA = () => { )}
- ( - - Verification Code - - - - - - - - - - - - - - Enter the 6-digit code from your authenticator app - - - - )} - /> +
+ Verification Code + + + + + + + + + + + + Enter the 6-digit code from your authenticator app + +
diff --git a/apps/dokploy/lib/languages.ts b/apps/dokploy/lib/languages.ts index a19c95893..7a4d54fa5 100644 --- a/apps/dokploy/lib/languages.ts +++ b/apps/dokploy/lib/languages.ts @@ -1,23 +1,27 @@ +/** + * Sorted list based off of population of the country / speakers of the language. + */ export const Languages = { english: { code: "en", name: "English" }, - polish: { code: "pl", name: "Polski" }, - ukrainian: { code: "uk", name: "Українська" }, + spanish: { code: "es", name: "Español" }, + chineseSimplified: { code: "zh-Hans", name: "简体中文" }, + chineseTraditional: { code: "zh-Hant", name: "繁體中文" }, + portuguese: { code: "pt-br", name: "Português" }, russian: { code: "ru", name: "Русский" }, - french: { code: "fr", name: "Français" }, + japanese: { code: "ja", name: "日本語" }, german: { code: "de", name: "Deutsch" }, - chineseTraditional: { code: "zh-Hant", name: "繁體中文" }, - chineseSimplified: { code: "zh-Hans", name: "简体中文" }, - turkish: { code: "tr", name: "Türkçe" }, - kazakh: { code: "kz", name: "Қазақ" }, - persian: { code: "fa", name: "فارسی" }, korean: { code: "ko", name: "한국어" }, - portuguese: { code: "pt-br", name: "Português" }, + french: { code: "fr", name: "Français" }, + turkish: { code: "tr", name: "Türkçe" }, italian: { code: "it", name: "Italiano" }, - japanese: { code: "ja", name: "日本語" }, - spanish: { code: "es", name: "Español" }, + polish: { code: "pl", name: "Polski" }, + ukrainian: { code: "uk", name: "Українська" }, + persian: { code: "fa", name: "فارسی" }, + dutch: { code: "nl", name: "Nederlands" }, + indonesian: { code: "id", name: "Bahasa Indonesia" }, + kazakh: { code: "kz", name: "Қазақ" }, norwegian: { code: "no", name: "Norsk" }, azerbaijani: { code: "az", name: "Azərbaycan" }, - indonesian: { code: "id", name: "Bahasa Indonesia" }, malayalam: { code: "ml", name: "മലയാളം" }, }; diff --git a/apps/dokploy/package.json b/apps/dokploy/package.json index 7a8cc891d..7836ff308 100644 --- a/apps/dokploy/package.json +++ b/apps/dokploy/package.json @@ -1,6 +1,6 @@ { "name": "dokploy", - "version": "v0.21.6", + "version": "v0.21.7", "private": true, "license": "Apache-2.0", "type": "module", diff --git a/apps/dokploy/public/locales/nl/common.json b/apps/dokploy/public/locales/nl/common.json index 69a88e3b6..0967ef424 100644 --- a/apps/dokploy/public/locales/nl/common.json +++ b/apps/dokploy/public/locales/nl/common.json @@ -1 +1 @@ -{} +{} diff --git a/apps/dokploy/public/locales/nl/settings.json b/apps/dokploy/public/locales/nl/settings.json index 34c492ec8..c76d9bb9b 100644 --- a/apps/dokploy/public/locales/nl/settings.json +++ b/apps/dokploy/public/locales/nl/settings.json @@ -1,58 +1,58 @@ -{ - "settings.common.save": "Opslaan", - "settings.common.enterTerminal": "Terminal", - "settings.server.domain.title": "Server Domein", - "settings.server.domain.description": "Voeg een domein toe aan jouw server applicatie.", - "settings.server.domain.form.domain": "Domein", - "settings.server.domain.form.letsEncryptEmail": "Let's Encrypt Email", - "settings.server.domain.form.certificate.label": "Certificaat Aanbieder", - "settings.server.domain.form.certificate.placeholder": "Select een certificaat", - "settings.server.domain.form.certificateOptions.none": "Geen", - "settings.server.domain.form.certificateOptions.letsencrypt": "Let's Encrypt", - - "settings.server.webServer.title": "Web Server", - "settings.server.webServer.description": "Herlaad of maak de web server schoon.", - "settings.server.webServer.actions": "Acties", - "settings.server.webServer.reload": "Herladen", - "settings.server.webServer.watchLogs": "Bekijk Logs", - "settings.server.webServer.updateServerIp": "Update de Server IP", - "settings.server.webServer.server.label": "Server", - "settings.server.webServer.traefik.label": "Traefik", - "settings.server.webServer.traefik.modifyEnv": "Bewerk Omgeving", - "settings.server.webServer.traefik.managePorts": "Extra Poort Mappings", - "settings.server.webServer.traefik.managePortsDescription": "Bewerk extra Poorten voor Traefik", - "settings.server.webServer.traefik.targetPort": "Doel Poort", - "settings.server.webServer.traefik.publishedPort": "Gepubliceerde Poort", - "settings.server.webServer.traefik.addPort": "Voeg Poort toe", - "settings.server.webServer.traefik.portsUpdated": "Poorten succesvol aangepast", - "settings.server.webServer.traefik.portsUpdateError": "Poorten niet succesvol aangepast", - "settings.server.webServer.traefik.publishMode": "Publiceer Mode", - "settings.server.webServer.storage.label": "Opslag", - "settings.server.webServer.storage.cleanUnusedImages": "Maak ongebruikte images schoon", - "settings.server.webServer.storage.cleanUnusedVolumes": "Maak ongebruikte volumes schoon", - "settings.server.webServer.storage.cleanStoppedContainers": "Maak gestopte containers schoon", - "settings.server.webServer.storage.cleanDockerBuilder": "Maak Docker Builder & Systeem schoon", - "settings.server.webServer.storage.cleanMonitoring": "Maak monitoor schoon", - "settings.server.webServer.storage.cleanAll": "Maak alles schoon", - - "settings.profile.title": "Account", - "settings.profile.description": "Veramder details van account.", - "settings.profile.email": "Email", - "settings.profile.password": "Wachtwoord", - "settings.profile.avatar": "Profiel Icoon", - - "settings.appearance.title": "Uiterlijk", - "settings.appearance.description": "Verander het thema van je dashboard.", - "settings.appearance.theme": "Thema", - "settings.appearance.themeDescription": "Selecteer een thema voor je dashboard.", - "settings.appearance.themes.light": "Licht", - "settings.appearance.themes.dark": "Donker", - "settings.appearance.themes.system": "Systeem", - "settings.appearance.language": "Taal", - "settings.appearance.languageDescription": "Selecteer een taal voor je dashboard.", - - "settings.terminal.connectionSettings": "Verbindings instellingen", - "settings.terminal.ipAddress": "IP Address", - "settings.terminal.port": "Poort", - "settings.terminal.username": "Gebruikersnaam" -} +{ + "settings.common.save": "Opslaan", + "settings.common.enterTerminal": "Terminal", + "settings.server.domain.title": "Server Domein", + "settings.server.domain.description": "Voeg een domein toe aan jouw server applicatie.", + "settings.server.domain.form.domain": "Domein", + "settings.server.domain.form.letsEncryptEmail": "Let's Encrypt Email", + "settings.server.domain.form.certificate.label": "Certificaat Aanbieder", + "settings.server.domain.form.certificate.placeholder": "Select een certificaat", + "settings.server.domain.form.certificateOptions.none": "Geen", + "settings.server.domain.form.certificateOptions.letsencrypt": "Let's Encrypt", + + "settings.server.webServer.title": "Web Server", + "settings.server.webServer.description": "Herlaad of maak de web server schoon.", + "settings.server.webServer.actions": "Acties", + "settings.server.webServer.reload": "Herladen", + "settings.server.webServer.watchLogs": "Bekijk Logs", + "settings.server.webServer.updateServerIp": "Update de Server IP", + "settings.server.webServer.server.label": "Server", + "settings.server.webServer.traefik.label": "Traefik", + "settings.server.webServer.traefik.modifyEnv": "Bewerk Omgeving", + "settings.server.webServer.traefik.managePorts": "Extra Poort Mappings", + "settings.server.webServer.traefik.managePortsDescription": "Bewerk extra Poorten voor Traefik", + "settings.server.webServer.traefik.targetPort": "Doel Poort", + "settings.server.webServer.traefik.publishedPort": "Gepubliceerde Poort", + "settings.server.webServer.traefik.addPort": "Voeg Poort toe", + "settings.server.webServer.traefik.portsUpdated": "Poorten succesvol aangepast", + "settings.server.webServer.traefik.portsUpdateError": "Poorten niet succesvol aangepast", + "settings.server.webServer.traefik.publishMode": "Publiceer Mode", + "settings.server.webServer.storage.label": "Opslag", + "settings.server.webServer.storage.cleanUnusedImages": "Maak ongebruikte images schoon", + "settings.server.webServer.storage.cleanUnusedVolumes": "Maak ongebruikte volumes schoon", + "settings.server.webServer.storage.cleanStoppedContainers": "Maak gestopte containers schoon", + "settings.server.webServer.storage.cleanDockerBuilder": "Maak Docker Builder & Systeem schoon", + "settings.server.webServer.storage.cleanMonitoring": "Maak monitoor schoon", + "settings.server.webServer.storage.cleanAll": "Maak alles schoon", + + "settings.profile.title": "Account", + "settings.profile.description": "Veramder details van account.", + "settings.profile.email": "Email", + "settings.profile.password": "Wachtwoord", + "settings.profile.avatar": "Profiel Icoon", + + "settings.appearance.title": "Uiterlijk", + "settings.appearance.description": "Verander het thema van je dashboard.", + "settings.appearance.theme": "Thema", + "settings.appearance.themeDescription": "Selecteer een thema voor je dashboard.", + "settings.appearance.themes.light": "Licht", + "settings.appearance.themes.dark": "Donker", + "settings.appearance.themes.system": "Systeem", + "settings.appearance.language": "Taal", + "settings.appearance.languageDescription": "Selecteer een taal voor je dashboard.", + + "settings.terminal.connectionSettings": "Verbindings instellingen", + "settings.terminal.ipAddress": "IP Address", + "settings.terminal.port": "Poort", + "settings.terminal.username": "Gebruikersnaam" +} diff --git a/apps/dokploy/public/locales/zh-Hans/common.json b/apps/dokploy/public/locales/zh-Hans/common.json index 0967ef424..91af07ff2 100644 --- a/apps/dokploy/public/locales/zh-Hans/common.json +++ b/apps/dokploy/public/locales/zh-Hans/common.json @@ -1 +1,78 @@ -{} +{ + "dashboard.title": "仪表盘", + "dashboard.overview": "概览", + "dashboard.projects": "项目", + "dashboard.servers": "服务器", + "dashboard.docker": "Docker", + "dashboard.monitoring": "监控", + "dashboard.settings": "设置", + "dashboard.logout": "退出登录", + "dashboard.profile": "个人资料", + "dashboard.terminal": "终端", + "dashboard.containers": "容器", + "dashboard.images": "镜像", + "dashboard.volumes": "卷", + "dashboard.networks": "网络", + "button.create": "创建", + "button.edit": "编辑", + "button.delete": "删除", + "button.cancel": "取消", + "button.save": "保存", + "button.confirm": "确认", + "button.back": "返回", + "button.next": "下一步", + "button.finish": "完成", + "status.running": "运行中", + "status.stopped": "已停止", + "status.error": "错误", + "status.pending": "等待中", + "status.success": "成功", + "status.failed": "失败", + "form.required": "必填", + "form.invalid": "无效", + "form.submit": "提交", + "form.reset": "重置", + "notification.success": "操作成功", + "notification.error": "操作失败", + "notification.warning": "警告", + "notification.info": "信息", + "time.now": "刚刚", + "time.minutes": "分钟前", + "time.hours": "小时前", + "time.days": "天前", + "filter.all": "全部", + "filter.active": "活跃", + "filter.inactive": "不活跃", + "sort.asc": "升序", + "sort.desc": "降序", + "search.placeholder": "搜索...", + "search.noResults": "无结果", + "pagination.prev": "上一页", + "pagination.next": "下一页", + "pagination.of": "共 {0} 页", + "error.notFound": "未找到", + "error.serverError": "服务器错误", + "error.unauthorized": "未授权", + "error.forbidden": "禁止访问", + "loading": "加载中...", + "empty": "暂无数据", + "more": "更多", + "less": "收起", + "project.create": "创建项目", + "project.edit": "编辑项目", + "project.delete": "删除项目", + "project.name": "项目名称", + "project.description": "项目描述", + "service.create": "创建服务", + "service.edit": "编辑服务", + "service.delete": "删除服务", + "service.name": "服务名称", + "service.type": "服务类型", + "domain.add": "添加域名", + "domain.remove": "移除域名", + "environment.variables": "环境变量", + "environment.add": "添加环境变量", + "environment.edit": "编辑环境变量", + "environment.name": "变量名", + "environment.value": "变量值" +} diff --git a/apps/dokploy/public/locales/zh-Hans/settings.json b/apps/dokploy/public/locales/zh-Hans/settings.json index c74fb21f8..d70676d6a 100644 --- a/apps/dokploy/public/locales/zh-Hans/settings.json +++ b/apps/dokploy/public/locales/zh-Hans/settings.json @@ -1,17 +1,16 @@ { "settings.common.save": "保存", - "settings.common.enterTerminal": "进入终端", - "settings.server.domain.title": "域名设置", - "settings.server.domain.description": "添加域名到服务器", + "settings.common.enterTerminal": "终端", + "settings.server.domain.title": "服务器域名", + "settings.server.domain.description": "为您的服务器应用添加域名。", "settings.server.domain.form.domain": "域名", "settings.server.domain.form.letsEncryptEmail": "Let's Encrypt 邮箱", - "settings.server.domain.form.certificate.label": "证书", - "settings.server.domain.form.certificate.placeholder": "选择一个证书", + "settings.server.domain.form.certificate.label": "证书提供商", + "settings.server.domain.form.certificate.placeholder": "选择证书", "settings.server.domain.form.certificateOptions.none": "无", "settings.server.domain.form.certificateOptions.letsencrypt": "Let's Encrypt", - - "settings.server.webServer.title": "服务器设置", - "settings.server.webServer.description": "管理服务器", + "settings.server.webServer.title": "Web 服务器", + "settings.server.webServer.description": "重载或清理 Web 服务器。", "settings.server.webServer.actions": "操作", "settings.server.webServer.reload": "重新加载", "settings.server.webServer.watchLogs": "查看日志", @@ -19,40 +18,50 @@ "settings.server.webServer.server.label": "服务器", "settings.server.webServer.traefik.label": "Traefik", "settings.server.webServer.traefik.modifyEnv": "修改环境变量", - "settings.server.webServer.traefik.managePorts": "端口转发", - "settings.server.webServer.traefik.managePortsDescription": "添加或删除 Traefik 的其他端口", + "settings.server.webServer.traefik.managePorts": "额外端口映射", + "settings.server.webServer.traefik.managePortsDescription": "为 Traefik 添加或删除额外端口", "settings.server.webServer.traefik.targetPort": "目标端口", - "settings.server.webServer.traefik.publishedPort": "对外端口", + "settings.server.webServer.traefik.publishedPort": "发布端口", "settings.server.webServer.traefik.addPort": "添加端口", "settings.server.webServer.traefik.portsUpdated": "端口更新成功", "settings.server.webServer.traefik.portsUpdateError": "端口更新失败", - "settings.server.webServer.traefik.publishMode": "端口映射", + "settings.server.webServer.traefik.publishMode": "发布模式", "settings.server.webServer.storage.label": "存储空间", "settings.server.webServer.storage.cleanUnusedImages": "清理未使用的镜像", "settings.server.webServer.storage.cleanUnusedVolumes": "清理未使用的卷", "settings.server.webServer.storage.cleanStoppedContainers": "清理已停止的容器", - "settings.server.webServer.storage.cleanDockerBuilder": "清理 Docker Builder 与 系统缓存", + "settings.server.webServer.storage.cleanDockerBuilder": "清理 Docker Builder 和系统", "settings.server.webServer.storage.cleanMonitoring": "清理监控数据", "settings.server.webServer.storage.cleanAll": "清理所有内容", - "settings.profile.title": "账户", - "settings.profile.description": "更改您的个人资料", + "settings.profile.description": "在此更改您的个人资料详情。", "settings.profile.email": "邮箱", "settings.profile.password": "密码", "settings.profile.avatar": "头像", - "settings.appearance.title": "外观", - "settings.appearance.description": "自定义面板主题", + "settings.appearance.description": "自定义您的仪表盘主题。", "settings.appearance.theme": "主题", - "settings.appearance.themeDescription": "选择面板主题", + "settings.appearance.themeDescription": "为您的仪表盘选择主题", "settings.appearance.themes.light": "明亮", - "settings.appearance.themes.dark": "黑暗", - "settings.appearance.themes.system": "系统主题", + "settings.appearance.themes.dark": "暗黑", + "settings.appearance.themes.system": "跟随系统", "settings.appearance.language": "语言", - "settings.appearance.languageDescription": "选择面板语言", - - "settings.terminal.connectionSettings": "终端设置", - "settings.terminal.ipAddress": "IP", + "settings.appearance.languageDescription": "为您的仪表盘选择语言", + "settings.terminal.connectionSettings": "连接设置", + "settings.terminal.ipAddress": "IP 地址", "settings.terminal.port": "端口", - "settings.terminal.username": "用户名" + "settings.terminal.username": "用户名", + "settings.settings": "设置", + "settings.general": "通用设置", + "settings.security": "安全", + "settings.users": "用户管理", + "settings.roles": "角色管理", + "settings.permissions": "权限", + "settings.api": "API设置", + "settings.certificates": "证书管理", + "settings.ssh": "SSH密钥", + "settings.backups": "备份", + "settings.logs": "日志", + "settings.updates": "更新", + "settings.network": "网络" } diff --git a/packages/server/src/utils/backups/web-server.ts b/packages/server/src/utils/backups/web-server.ts index a7d48a2fa..ef2249d0a 100644 --- a/packages/server/src/utils/backups/web-server.ts +++ b/packages/server/src/utils/backups/web-server.ts @@ -23,7 +23,17 @@ export const runWebServerBackup = async (backup: BackupSchedule) => { try { await execAsync(`mkdir -p ${tempDir}/filesystem`); - const postgresCommand = `docker exec $(docker ps --filter "name=dokploy-postgres" -q) pg_dump -v -Fc -U dokploy -d dokploy > ${tempDir}/database.sql`; + // First get the container ID + const { stdout: containerId } = await execAsync( + "docker ps --filter 'name=dokploy-postgres' -q", + ); + + if (!containerId) { + throw new Error("PostgreSQL container not found"); + } + + // Then run pg_dump with the container ID + const postgresCommand = `docker exec ${containerId.trim()} pg_dump -v -Fc -U dokploy -d dokploy > '${tempDir}/database.sql'`; await execAsync(postgresCommand); await execAsync(`cp -r ${BASE_PATH}/* ${tempDir}/filesystem/`); diff --git a/packages/server/src/utils/providers/gitlab.ts b/packages/server/src/utils/providers/gitlab.ts index facdeb596..d01cc4004 100644 --- a/packages/server/src/utils/providers/gitlab.ts +++ b/packages/server/src/utils/providers/gitlab.ts @@ -264,7 +264,11 @@ export const getGitlabRepositories = async (gitlabId?: string) => { const groupName = gitlabProvider.groupName?.toLowerCase(); if (groupName) { - return full_path.toLowerCase().includes(groupName) && kind === "group"; + const isIncluded = groupName + .split(",") + .some((name) => full_path.toLowerCase().includes(name)); + + return isIncluded && kind === "group"; } return kind === "user"; }); @@ -431,7 +435,9 @@ export const testGitlabConnection = async ( const { full_path, kind } = repo.namespace; if (groupName) { - return full_path.toLowerCase().includes(groupName) && kind === "group"; + return groupName + .split(",") + .some((name) => full_path.toLowerCase().includes(name)); } return kind === "user"; });