fix: quick deploy duplicate detection, logout UX, backup toggle, CSP, SSE guard, and migration
- Detect existing projects with same image on quick deploy; show conflict dialog with options - Move logout button to sidebar header as icon-only - Replace backup checkbox with ToggleSwitch component - Allow unsafe-inline in CSP script-src for SvelteKit hydration - Guard SSE connection behind isAuthenticated() check - Add notification_url ALTER TABLE migration for existing databases - Restore RegisterPersistentLogger on event bus
This commit is contained in:
@@ -6,12 +6,13 @@
|
||||
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 } from '$lib/components/icons';
|
||||
import { IconDashboard, IconProjects, IconDeploy, IconSettings, IconMenu, IconX, IconLogout } from '$lib/components/icons';
|
||||
import { goto } from '$app/navigation';
|
||||
import { connectGlobalEvents, type SSEConnection } from '$lib/sse';
|
||||
import { instanceStatusStore } from '$lib/stores/instance-status';
|
||||
import { resolvedTheme, applyTheme } from '$lib/stores/theme';
|
||||
import { exchangeOidcToken, setAuthToken } from '$lib/auth';
|
||||
import { exchangeOidcToken, setAuthToken, clearAuth, isAuthenticated } from '$lib/auth';
|
||||
import { logout as apiLogout } from '$lib/api';
|
||||
import { t } from '$lib/i18n';
|
||||
|
||||
interface Props {
|
||||
@@ -68,14 +69,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
sseConnection = connectGlobalEvents({
|
||||
onInstanceStatus(payload) {
|
||||
instanceStatusStore.update(payload);
|
||||
},
|
||||
onDeployStatus(payload) {
|
||||
instanceStatusStore.notifyDeploy(payload);
|
||||
}
|
||||
});
|
||||
// Only connect SSE when authenticated (has a token).
|
||||
if (isAuthenticated()) {
|
||||
sseConnection = connectGlobalEvents({
|
||||
onInstanceStatus(payload) {
|
||||
instanceStatusStore.update(payload);
|
||||
},
|
||||
onDeployStatus(payload) {
|
||||
instanceStatusStore.notifyDeploy(payload);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
@@ -112,9 +116,24 @@
|
||||
</div>
|
||||
<span class="text-base font-bold text-[var(--text-primary)]">{$t('app.name')}</span>
|
||||
|
||||
<!-- Logout button -->
|
||||
<button
|
||||
type="button"
|
||||
title={$t('nav.logout')}
|
||||
aria-label={$t('nav.logout')}
|
||||
onclick={async () => {
|
||||
try { await apiLogout(); } catch { /* best effort */ }
|
||||
clearAuth();
|
||||
goto('/login');
|
||||
}}
|
||||
class="ml-auto rounded-md p-1.5 text-[var(--text-tertiary)] hover:text-[var(--color-danger)] transition-colors"
|
||||
>
|
||||
<IconLogout size={18} />
|
||||
</button>
|
||||
|
||||
<!-- Close sidebar (mobile) -->
|
||||
<button
|
||||
class="ml-auto rounded-md p-1 text-[var(--text-tertiary)] hover:text-[var(--text-primary)] lg:hidden"
|
||||
class="rounded-md p-1 text-[var(--text-tertiary)] hover:text-[var(--text-primary)] lg:hidden"
|
||||
onclick={() => { sidebarOpen = false; }}
|
||||
aria-label="Close sidebar"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user