diff --git a/web/src/lib/i18n/en.json b/web/src/lib/i18n/en.json index 9f877e4..dd1d5d3 100644 --- a/web/src/lib/i18n/en.json +++ b/web/src/lib/i18n/en.json @@ -248,6 +248,10 @@ "proxyNoneDesc": "No proxy — containers are accessed directly by port", "proxyNpm": "Nginx Proxy Manager", "proxyNpmDesc": "Routes managed via NPM API (configure credentials below)", + "npm": "Nginx Proxy Manager", + "traefik": "Traefik", + "traefikLabelsTitle": "Docker Labels Reference", + "traefikLabelsDesc": "These labels are automatically added to deployed containers. Shown here for reference.", "proxyTraefik": "Traefik", "proxyTraefikDesc": "Auto-discovery via Docker labels — no API calls needed", "proxyNoneWarning": "Switching to None does not remove existing proxy routes. You may need to clean them up manually.", diff --git a/web/src/lib/i18n/ru.json b/web/src/lib/i18n/ru.json index cbbe6a8..3676921 100644 --- a/web/src/lib/i18n/ru.json +++ b/web/src/lib/i18n/ru.json @@ -248,6 +248,10 @@ "proxyNoneDesc": "Без прокси — контейнеры доступны напрямую по порту", "proxyNpm": "Nginx Proxy Manager", "proxyNpmDesc": "Маршруты через NPM API (настройте учётные данные ниже)", + "npm": "Nginx Proxy Manager", + "traefik": "Traefik", + "traefikLabelsTitle": "Справка по Docker-меткам", + "traefikLabelsDesc": "Эти метки автоматически добавляются к развёрнутым контейнерам. Показаны для справки.", "proxyTraefik": "Traefik", "proxyTraefikDesc": "Автообнаружение через Docker-метки — без API-вызовов", "proxyNoneWarning": "Переключение на «Нет» не удаляет существующие прокси-маршруты. Возможно, потребуется очистить их вручную.", diff --git a/web/src/routes/+layout.svelte b/web/src/routes/+layout.svelte index 89c681a..8480805 100644 --- a/web/src/routes/+layout.svelte +++ b/web/src/routes/+layout.svelte @@ -6,7 +6,7 @@ import Toast from '$lib/components/Toast.svelte'; import ThemeToggle from '$lib/components/ThemeToggle.svelte'; import LocaleSwitcher from '$lib/components/LocaleSwitcher.svelte'; - import { IconDashboard, IconProjects, IconDeploy, IconSettings, IconMenu, IconX, IconLogout, IconChevronDown } from '$lib/components/icons'; + import { IconDashboard, IconProjects, IconDeploy, IconEvents, IconSettings, IconMenu, IconX, IconLogout, IconChevronDown } from '$lib/components/icons'; import { goto } from '$app/navigation'; import { connectGlobalEvents, type SSEConnection } from '$lib/sse'; import { instanceStatusStore } from '$lib/stores/instance-status'; @@ -26,6 +26,7 @@ { href: '/', labelKey: 'nav.dashboard', icon: 'dashboard' }, { href: '/projects', labelKey: 'nav.projects', icon: 'projects' }, { href: '/deploy', labelKey: 'nav.deploy', icon: 'deploy' }, + { href: '/events', labelKey: 'nav.events', icon: 'events' }, { href: '/settings', labelKey: 'nav.settings', icon: 'settings' } ] as const; @@ -169,6 +170,8 @@ {:else if item.icon === 'deploy'} + {:else if item.icon === 'events'} + {:else if item.icon === 'settings'} {/if} diff --git a/web/src/routes/settings/+layout.svelte b/web/src/routes/settings/+layout.svelte index 57aa225..a3291ae 100644 --- a/web/src/routes/settings/+layout.svelte +++ b/web/src/routes/settings/+layout.svelte @@ -1,23 +1,37 @@ @@ -130,118 +8,11 @@
-

{$t('settingsCredentials.title')}

-

{$t('settingsCredentials.description')}

+

{$t('settingsCredentials.registryTokens')}

+

+ {$t('settingsCredentials.registryTokensDesc')} + {$t('settingsCredentials.registriesLink')} + {$t('settingsCredentials.registryTokensSuffix')} +

- - {#if loading} -
- {:else} - {#if proxyProvider === 'npm'} - -
-
-
-

{$t('settingsCredentials.npm')}

-

{$t('settingsCredentials.npmDesc')}

-
- {#if npmHasCredentials && !editingNpm} - - - {$t('settingsCredentials.configured')} - - {/if} -
- - {#if !editingNpm && npmHasCredentials} -
- {#each [{ label: $t('settingsCredentials.npmUrl'), value: npmUrl }, { label: $t('settingsCredentials.email'), value: npmEmail }, { label: $t('settingsCredentials.password'), value: '--------' }] as item} -
-
-

{item.label}

-

{item.value || $t('settingsCredentials.notSet')}

-
-
- {/each} - -
- {:else} -
- - - -
- - {#if npmHasCredentials} - - {/if} -
-
- {/if} -
- - -
-
-
-

{$t('settingsGeneral.sslCertificate')}

-

{$t('settingsGeneral.sslCertificateHelp')}

-
- - {#if sslCertificateId > 0} - - {/if} -
-
-
-
- {/if} - -
-

{$t('settingsCredentials.registryTokens')}

-

- {$t('settingsCredentials.registryTokensDesc')} - {$t('settingsCredentials.registriesLink')} - {$t('settingsCredentials.registryTokensSuffix')} -

-
- {/if}
- - { certPickerOpen = false; }} -/> diff --git a/web/src/routes/settings/npm/+page.svelte b/web/src/routes/settings/npm/+page.svelte new file mode 100644 index 0000000..c8e46f4 --- /dev/null +++ b/web/src/routes/settings/npm/+page.svelte @@ -0,0 +1,204 @@ + + + + {$t('settings.npm')} - {$t('app.name')} + + +
+
+

{$t('settings.npm')}

+

{$t('settingsCredentials.npmDesc')}

+
+ + {#if loading} +
+ {:else} + +
+
+

{$t('settingsCredentials.npm')}

+ {#if npmHasCredentials && !editingNpm} + + + {$t('settingsCredentials.configured')} + + {/if} +
+ + {#if !editingNpm && npmHasCredentials} +
+ {#each [{ label: $t('settingsCredentials.npmUrl'), value: npmUrl }, { label: $t('settingsCredentials.email'), value: npmEmail }, { label: $t('settingsCredentials.password'), value: '--------' }] as item} +
+
+

{item.label}

+

{item.value || $t('settingsCredentials.notSet')}

+
+
+ {/each} + +
+ {:else} +
+ + + +
+ + {#if npmHasCredentials} + + {/if} +
+
+ {/if} +
+ + +
+
+
+

{$t('settingsGeneral.sslCertificate')}

+

{$t('settingsGeneral.sslCertificateHelp')}

+
+ + {#if sslCertificateId > 0} + + {/if} +
+
+
+
+ {/if} +
+ + { certPickerOpen = false; }} +/> diff --git a/web/src/routes/settings/traefik/+page.svelte b/web/src/routes/settings/traefik/+page.svelte new file mode 100644 index 0000000..7de8226 --- /dev/null +++ b/web/src/routes/settings/traefik/+page.svelte @@ -0,0 +1,87 @@ + + + + {$t('settings.traefik')} - {$t('app.name')} + + +
+
+

{$t('settings.traefik')}

+

{$t('settings.proxyTraefikDesc')}

+
+ + {#if loading} +
+ {:else} +
+
+ + + + +
+ + +
+ +
+

{$t('settings.traefikLabelsTitle')}

+

{$t('settings.traefikLabelsDesc')}

+
traefik.enable=true
+traefik.http.routers.<name>.rule=Host(`your-domain.com`)
+traefik.http.routers.<name>.entrypoints={traefikEntrypoint || 'websecure'}
+traefik.http.services.<name>.loadbalancer.server.port=<port>{#if traefikCertResolver}
+traefik.http.routers.<name>.tls.certresolver={traefikCertResolver}{/if}{#if traefikNetwork}
+traefik.docker.network={traefikNetwork}{/if}
+
+ {/if} +