feat(secrets): scoped shared secrets rule-management UI (Phase 2)

Completes scoped shared secrets end-to-end: /shared-secrets list/new/edit
routes (mirroring metric-alert-rules) with an env-key name, a WRITE-ONLY
value (password input; never pre-filled — the API returns only has_value;
omitted on PATCH to keep the stored secret, provided to rotate; cleared
after save), an encrypted toggle (flipping it requires re-entering the
value, matching the server's 400 guard), a global|app scope with an
App-grouping picker (listApps), description, and enabled. 409 conflicts
surface a friendly message. New "System" nav entry (IconKey) + api.ts
client + full sharedsecrets.* i18n (en/ru parity).

Reviewed: typescript APPROVE (0 CRITICAL/HIGH).
This commit is contained in:
2026-05-29 16:11:46 +03:00
parent fa6d5bd3ba
commit 15e5b186cd
7 changed files with 1990 additions and 1 deletions
+4 -1
View File
@@ -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, IconDeploy, IconEvents, IconWifi, IconSettings, IconMenu, IconX, IconLogout, IconBox, IconContainer, IconAlert } from '$lib/components/icons';
import { IconDashboard, IconDeploy, IconEvents, IconWifi, IconSettings, IconMenu, IconX, IconLogout, IconBox, IconContainer, IconAlert, IconKey } from '$lib/components/icons';
import { goto } from '$app/navigation';
import { resolvedTheme, applyTheme } from '$lib/stores/theme';
import { exchangeOidcToken, setAuthToken, clearAuth, isAuthenticated } from '$lib/auth';
@@ -50,6 +50,7 @@
{ href: '/event-triggers', labelKey: 'nav.eventTriggers', icon: 'events', section: 'observe' },
{ href: '/log-scan-rules', labelKey: 'nav.logScanRules', icon: 'events', section: 'observe' },
{ href: '/metric-alert-rules', labelKey: 'nav.metricAlertRules', icon: 'alert', section: 'observe' },
{ href: '/shared-secrets', labelKey: 'nav.sharedSecrets', icon: 'key', section: 'system' },
{ href: '/settings', labelKey: 'nav.settings', icon: 'settings', section: 'system' }
];
@@ -319,6 +320,8 @@
<IconEvents size={18} class="{active ? 'text-[var(--color-brand-600)]' : 'text-[var(--text-tertiary)] group-hover:text-[var(--text-secondary)]'} transition-colors duration-150" />
{:else if item.icon === 'alert'}
<IconAlert size={18} class="{active ? 'text-[var(--color-brand-600)]' : 'text-[var(--text-tertiary)] group-hover:text-[var(--text-secondary)]'} transition-colors duration-150" />
{:else if item.icon === 'key'}
<IconKey size={18} class="{active ? 'text-[var(--color-brand-600)]' : 'text-[var(--text-tertiary)] group-hover:text-[var(--text-secondary)]'} transition-colors duration-150" />
{:else if item.icon === 'settings'}
<IconSettings size={18} class="{active ? 'text-[var(--color-brand-600)]' : 'text-[var(--text-tertiary)] group-hover:text-[var(--text-secondary)]'} transition-colors duration-150" />
{/if}