From de370fd10ff74488b7aec3ff14a963335c7d37c1 Mon Sep 17 00:00:00 2001 From: AhmetArif0 <147827411+AhmetArif0@users.noreply.github.com> Date: Wed, 3 Jun 2026 18:17:55 +0300 Subject: [PATCH] fix(dashboard): prevent stale desc-save indicator when requests overlap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit handleSaveDesc and handleAutoDescribe both set their loading flag in a try block but always cleared it unconditionally in finally. When a user opened profile A's description editor, clicked Save, then quickly switched to profile B's editor and saved, profile A's resolving request would clear descSaving/describing while profile B's request was still in-flight, making the "Saving…" indicator disappear prematurely. Track concurrent in-flight counts with descSavingCount and describingCount refs (mirrors the existing activeDescRequest guard pattern). The loading flag is cleared only when the counter reaches zero, i.e. all overlapping requests have settled. --- web/src/pages/ProfilesPage.tsx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/web/src/pages/ProfilesPage.tsx b/web/src/pages/ProfilesPage.tsx index 9a1795cc9..add35a153 100644 --- a/web/src/pages/ProfilesPage.tsx +++ b/web/src/pages/ProfilesPage.tsx @@ -333,6 +333,10 @@ export default function ProfilesPage() { // Tracks the latest description request (save / auto-describe) so a late // response can't overwrite state for a different, newly-opened editor. const activeDescRequest = useRef(null); + // Counts in-flight save / auto-describe requests so the saving indicator + // is only cleared when the last concurrent request settles. + const descSavingCount = useRef(0); + const describingCount = useRef(0); // Inline model editor state const [editingModelFor, setEditingModelFor] = useState(null); @@ -551,6 +555,7 @@ export default function ProfilesPage() { ); const handleSaveDesc = async (name: string) => { + descSavingCount.current += 1; setDescSaving(true); activeDescRequest.current = name; try { @@ -577,11 +582,13 @@ export default function ProfilesPage() { showToast(`${t.status.error}: ${e}`, "error"); } } finally { - setDescSaving(false); + descSavingCount.current -= 1; + if (descSavingCount.current === 0) setDescSaving(false); } }; const handleAutoDescribe = async (name: string) => { + describingCount.current += 1; setDescribing(true); activeDescRequest.current = name; try { @@ -609,7 +616,8 @@ export default function ProfilesPage() { showToast(`${t.status.error}: ${e}`, "error"); } } finally { - setDescribing(false); + describingCount.current -= 1; + if (describingCount.current === 0) setDescribing(false); } };