diff --git a/web/src/routes/projects/[id]/env/+page.svelte b/web/src/routes/projects/[id]/env/+page.svelte index 1a128d8..2fbb44d 100644 --- a/web/src/routes/projects/[id]/env/+page.svelte +++ b/web/src/routes/projects/[id]/env/+page.svelte @@ -8,6 +8,7 @@ import ToggleSwitch from '$lib/components/ToggleSwitch.svelte'; import Skeleton from '$lib/components/Skeleton.svelte'; import EmptyState from '$lib/components/EmptyState.svelte'; + import ConfirmDialog from '$lib/components/ConfirmDialog.svelte'; let stages = $state([]); let selectedStageId = $state(''); @@ -27,6 +28,8 @@ let editValue = $state(''); let editEncrypted = $state(false); + let envDeleteTarget = $state(null); + const projectId = $derived($page.params.id); async function loadProject() { @@ -290,7 +293,7 @@ - @@ -331,3 +334,17 @@ {/if} {/if} + + { + const envId = envDeleteTarget; + envDeleteTarget = null; + if (envId) await handleDelete(envId); + }} + oncancel={() => { envDeleteTarget = null; }} +/> diff --git a/web/src/routes/projects/[id]/volumes/+page.svelte b/web/src/routes/projects/[id]/volumes/+page.svelte index 3ceca97..2d34720 100644 --- a/web/src/routes/projects/[id]/volumes/+page.svelte +++ b/web/src/routes/projects/[id]/volumes/+page.svelte @@ -1,71 +1,37 @@ @@ -158,79 +108,51 @@

{$t('volumeEditor.title')}

-

{$t('volumeEditor.description')}

+

+ {$t('volumeEditor.description')} + {$t('volumeEditor.shared')} — {$t('volumeEditor.sharedDesc')} + {$t('volumeEditor.isolated')} — {$t('volumeEditor.isolatedDesc')} +

- - {#if scopeInfos.length > 0} -
- {#each scopeInfos as info} - {@const colors = scopeColor(info.scope)} -
-
- {info.scope} - {#if info.needs_name} - ({$t('volumeEditor.requiresName')}) - {/if} -
-

{info.description}

- {info.path_example} -
- {/each} -
- {/if} - {#if loading} - +
+ +
{:else if error}

{error}

-
{:else} -
- - + {#each volumes as vol (vol.id)} {#if editingId === vol.id} - - {:else} - - + - @@ -276,34 +184,22 @@ -
{$t('volumeEditor.sourceHost')} {$t('volumeEditor.targetContainer')}{$t('volumeEditor.scope')}{$t('volumeEditor.nameColumn')}{$t('volumeEditor.mode')} {$t('volumeEditor.actions')}
- {#if editIsEphemeral} - {$t('volumeEditor.noHostPath')} - {:else} - - {/if} + - + + - {#if editNeedsName} - - {:else} - - {/if} -
@@ -239,34 +161,20 @@
- {#if vol.scope === 'ephemeral'} - {$t('volumeEditor.tmpfs')} - {:else} - {vol.source} - {/if} - {vol.source} {vol.target} - {vol.scope} - - {vol.name || '—'} + {#if vol.mode === 'shared'} + {$t('volumeEditor.shared')} + {:else} + {$t('volumeEditor.isolated')} + {/if}
- {#if vol.scope !== 'ephemeral'} - - - - - - - {/if} - +
- {#if newIsEphemeral} - {$t('volumeEditor.noHostPath')} - {:else} - - {/if} + - + + - {#if newNeedsName} - - {:else} - - {/if} -
- - {#if scopeDescription(newScope)} -
-

- {newScope}: - {scopeDescription(newScope)} -

- {scopePathExample(newScope)} -
- {/if} - {#if volumes.length === 0}

{$t('volumeEditor.noVolumes')}

{/if} {/if} + + { + const volId = volumeDeleteTarget; + volumeDeleteTarget = null; + if (volId) await handleDelete(volId); + }} + oncancel={() => { volumeDeleteTarget = null; }} +/> diff --git a/web/src/routes/settings/auth/+page.svelte b/web/src/routes/settings/auth/+page.svelte index ac74bab..29b63a1 100644 --- a/web/src/routes/settings/auth/+page.svelte +++ b/web/src/routes/settings/auth/+page.svelte @@ -3,7 +3,7 @@ import { t } from '$lib/i18n'; import { IconLoader, IconPlus, IconTrash, IconUsers } from '$lib/components/icons'; import EmptyState from '$lib/components/EmptyState.svelte'; - import { getAuthToken } from '$lib/auth'; + import ConfirmDialog from '$lib/components/ConfirmDialog.svelte'; interface AuthSettings { auth_mode: string; @@ -34,7 +34,10 @@ let newEmail = $state(''); let newRole = $state('viewer'); - function authHeaders(): Record { return { 'Content-Type': 'application/json', Authorization: `Bearer ${getAuthToken() ?? ''}` }; } + let userDeleteTarget = $state(null); + + function getToken(): string { return localStorage.getItem('auth_token') ?? ''; } + function authHeaders(): Record { return { 'Content-Type': 'application/json', Authorization: `Bearer ${getToken()}` }; } onMount(async () => { await Promise.all([loadSettings(), loadUsers()]); }); @@ -68,13 +71,12 @@ } async function deleteUser(id: string) { - if (!confirm($t('settingsAuth.deleteConfirm'))) return; try { const res = await fetch(`/api/auth/users/${id}`, { method: 'DELETE', headers: authHeaders() }); const envelope = await res.json(); if (envelope.success) { await loadUsers(); message = $t('settingsAuth.userDeleted'); } else error = envelope.error ?? $t('settingsAuth.deleteFailed'); - } catch (err: unknown) { error = err instanceof Error ? err.message : 'Network error'; } + } catch (err: unknown) { error = err instanceof Error ? err.message : $t('settingsAuth.networkError'); } } @@ -165,7 +167,7 @@ {user.created_at} - @@ -198,3 +200,17 @@ + + { + const user = userDeleteTarget; + userDeleteTarget = null; + if (user) await deleteUser(user.id); + }} + oncancel={() => { userDeleteTarget = null; }} +/> diff --git a/web/src/routes/settings/registries/+page.svelte b/web/src/routes/settings/registries/+page.svelte index 9753819..5dfeac8 100644 --- a/web/src/routes/settings/registries/+page.svelte +++ b/web/src/routes/settings/registries/+page.svelte @@ -7,6 +7,7 @@ import { toasts } from '$lib/stores/toast'; import { t } from '$lib/i18n'; import { IconPlus, IconLoader, IconEdit, IconTrash, IconWifi } from '$lib/components/icons'; + import ConfirmDialog from '$lib/components/ConfirmDialog.svelte'; let registries = $state([]); let loading = $state(true); @@ -22,6 +23,7 @@ let testingId = $state(null); let healthStatus = $state>({}); + let registryDeleteTarget = $state(null); let errors = $state>({}); function validateForm(): boolean { @@ -59,7 +61,6 @@ } async function handleDelete(registry: Registry) { - if (!confirm($t('settingsRegistries.deleteConfirm', { name: registry.name }))) return; try { await deleteRegistry(registry.id); toasts.success($t('settingsRegistries.registryDeleted', { name: registry.name })); await loadRegistryList(); } catch (err) { toasts.error(err instanceof Error ? err.message : $t('settingsRegistries.deleteFailed')); } } @@ -174,10 +175,24 @@ {testingId === registry.id ? $t('settingsRegistries.testing') : $t('settingsRegistries.test')} - + {/each} {/if} + + { + const reg = registryDeleteTarget; + registryDeleteTarget = null; + if (reg) await handleDelete(reg); + }} + oncancel={() => { registryDeleteTarget = null; }} +/>