From 047aff41d9a359f8774f45e081afdf294f852556 Mon Sep 17 00:00:00 2001 From: busya Date: Sat, 4 Jul 2026 15:34:02 +0300 Subject: [PATCH] Task Status Center: save progress --- .../src/lib/components/layout/TopNavbar.svelte | 17 ++++++++++++----- .../src/lib/models/AgentChatModel.svelte.ts | 6 +++--- frontend/src/routes/+layout.svelte | 4 ++-- frontend/src/routes/agent/+page.svelte | 14 +++++++++++--- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/frontend/src/lib/components/layout/TopNavbar.svelte b/frontend/src/lib/components/layout/TopNavbar.svelte index a039199e..0b7369ca 100644 --- a/frontend/src/lib/components/layout/TopNavbar.svelte +++ b/frontend/src/lib/components/layout/TopNavbar.svelte @@ -109,17 +109,22 @@ hasPermission(user, "admin:settings", "READ"), ); let globalEnvironments = $derived( - environmentContextStore.value?.environments || [], + $environmentContextStore?.environments || [], ); let globalSelectedEnvId = $derived( - environmentContextStore.value?.selectedEnvId || "", + $environmentContextStore?.selectedEnvId || "", ); - let globalSelectedEnv = $derived(selectedEnvironmentStore.value); + let globalSelectedEnv = $derived($selectedEnvironmentStore); + let selectedEnvironmentValue = $state(""); let isProdContext = $derived( String(globalSelectedEnv?.stage || "").toUpperCase() === "PROD" || Boolean(globalSelectedEnv?.is_production), ); + $effect(() => { + selectedEnvironmentValue = globalSelectedEnvId; + }); + function toggleUserMenu(event) { event.stopPropagation(); showUserMenu = !showUserMenu; @@ -187,7 +192,9 @@ } function handleGlobalEnvironmentChange(event) { - setSelectedEnvironment(event.target.value); + const nextEnvId = event.currentTarget.value; + selectedEnvironmentValue = nextEnvId; + setSelectedEnvironment(nextEnvId); if (searchQuery.trim().length >= SEARCH_MIN_LENGTH) { triggerSearch(searchQuery.trim()); } @@ -479,7 +486,7 @@ {isProdContext ? 'border-destructive-ring bg-destructive-light text-destructive focus:ring-destructive-ring' : 'border-border-strong bg-surface-card text-text focus:ring-sky-200'}" - value={globalSelectedEnvId} + bind:value={selectedEnvironmentValue} onchange={handleGlobalEnvironmentChange} aria-label={$t.dashboard?.environment || "Environment"} title={$t.dashboard?.environment || "Environment"} diff --git a/frontend/src/lib/models/AgentChatModel.svelte.ts b/frontend/src/lib/models/AgentChatModel.svelte.ts index 64560d08..734130de 100644 --- a/frontend/src/lib/models/AgentChatModel.svelte.ts +++ b/frontend/src/lib/models/AgentChatModel.svelte.ts @@ -108,9 +108,9 @@ export class AgentChatModel { _userCancelled: boolean = $state(false); /** Populated by file_uploaded metadata — attached to user message on stream end. */ _pendingAttachment: { file_name: string; file_path: string; file_size: number } | null = $state(null); - userId: string = ""; - userJwt: string = ""; - envId: string = ""; + userId: string = $state(""); + userJwt: string = $state(""); + envId: string = $state(""); // ── Private fields ───────────────────────────────────────────── _client: GradioClient | null = null; // non-private for legacy Object.assign usage diff --git a/frontend/src/routes/+layout.svelte b/frontend/src/routes/+layout.svelte index 4748390f..f3bc33e4 100644 --- a/frontend/src/routes/+layout.svelte +++ b/frontend/src/routes/+layout.svelte @@ -42,8 +42,8 @@ let isLoginPage = $derived(page.url.pathname === '/login'); let isExpanded = $derived(sidebarStore.value?.isExpanded ?? true); - let isProductionContext = $derived(isProductionContextStore.value); - let selectedEnvironment = $derived(selectedEnvironmentStore.value); + let isProductionContext = $derived($isProductionContextStore); + let selectedEnvironment = $derived($selectedEnvironmentStore); diff --git a/frontend/src/routes/agent/+page.svelte b/frontend/src/routes/agent/+page.svelte index 17b039f3..e46ed7f2 100644 --- a/frontend/src/routes/agent/+page.svelte +++ b/frontend/src/routes/agent/+page.svelte @@ -26,18 +26,22 @@ // $auth is Svelte auto-subscription syntax for stores with .subscribe() let currentUserId = $derived($auth.user?.id ?? ""); let currentUserJwt = $derived($auth.token ?? ""); + let currentEnvironmentId = $derived( + $environmentContextStore?.selectedEnvId || (browser ? localStorage.getItem("selected_env_id") || "" : ""), + ); // Guard against double initialization in dev HMR let _initialized = false; // Sync model with reactive values before each send - function syncModel(m: AgentChatModel): void { + function syncModel(m: AgentChatModel, envId: string = currentEnvironmentId): void { m.userId = $auth.user?.id ?? ""; m.userJwt = $auth.token ?? ""; - m.envId = environmentContextStore.value?.selectedEnvId || (browser ? localStorage.getItem("selected_env_id") || "" : ""); + m.envId = envId; } $effect(() => { - if (model) syncModel(model); + const envId = currentEnvironmentId; + if (model) syncModel(model, envId); }); onMount(() => { @@ -47,6 +51,9 @@ const m = new AgentChatModel(); m.onBeforeSend = () => syncModel(m); syncModel(m); + const unsubscribeEnvironment = environmentContextStore.subscribe((state) => { + syncModel(m, state?.selectedEnvId || (browser ? localStorage.getItem("selected_env_id") || "" : "")); + }); const desktopQuery = window.matchMedia("(min-width: 768px)"); const syncSidebarForViewport = (matches: boolean) => { m.setConversationSidebarOpen(matches); @@ -71,6 +78,7 @@ }); return () => { + unsubscribeEnvironment(); desktopQuery.removeEventListener("change", handleViewportChange); _initialized = false; };