From 446feda3cd5beb7efd81412bb6ba8817501629a3 Mon Sep 17 00:00:00 2001 From: viettranx Date: Mon, 16 Mar 2026 22:47:04 +0700 Subject: [PATCH] fix(ui): workspace dialog scope filter + remove dead tab files - Fix scope dropdown: cache scopes from initial "all" load so dropdown stays stable when filtering by chatID - Derive scopes from file chat_id when task scopes are empty - Remove dead files: team-workspace-tab.tsx, team-tasks-tab.tsx (replaced by board view and workspace dialog) --- .../teams/board/team-workspace-dialog.tsx | 42 ++- ui/web/src/pages/teams/team-tasks-tab.tsx | 302 ------------------ ui/web/src/pages/teams/team-workspace-tab.tsx | 213 ------------ 3 files changed, 37 insertions(+), 520 deletions(-) delete mode 100644 ui/web/src/pages/teams/team-tasks-tab.tsx delete mode 100644 ui/web/src/pages/teams/team-workspace-tab.tsx diff --git a/ui/web/src/pages/teams/board/team-workspace-dialog.tsx b/ui/web/src/pages/teams/board/team-workspace-dialog.tsx index 9bdadbc4..c06ba083 100644 --- a/ui/web/src/pages/teams/board/team-workspace-dialog.tsx +++ b/ui/web/src/pages/teams/board/team-workspace-dialog.tsx @@ -37,16 +37,45 @@ export function TeamWorkspaceDialog({ open, onOpenChange, teamId, scopes }: Team const [activePath, setActivePath] = useState(null); const scopeValue = selectedScope === "__all__" ? "" : selectedScope; + // Stable scope list: populated once from "all" listing, not recalculated on filter. + const [cachedScopes, setCachedScopes] = useState([]); + // Load files for the selected scope. On "all" load, also cache scope list. const load = useCallback(() => { - listFiles(teamId, scopeValue || undefined); + listFiles(teamId, scopeValue || undefined).then((result) => { + // Only update cached scopes from the "all" listing (no filter applied). + if (!scopeValue && result.length > 0) { + const seen = new Set(); + const derived: ScopeEntry[] = []; + for (const f of result) { + if (f.chat_id && !seen.has(f.chat_id)) { + seen.add(f.chat_id); + derived.push({ channel: "", chat_id: f.chat_id }); + } + } + derived.sort((a, b) => a.chat_id.localeCompare(b.chat_id)); + setCachedScopes(derived); + } + }); setFileContent(null); setActivePath(null); }, [teamId, listFiles, scopeValue]); useEffect(() => { - if (open) load(); - }, [open, load]); + if (open) { + setSelectedScope("__all__"); // reset filter on open + load(); + } + }, [open]); // intentionally only depend on `open`, not `load` + + // Re-fetch when scope changes (but not on initial open — handled above). + useEffect(() => { + if (open && scopeValue) { + listFiles(teamId, scopeValue); + setFileContent(null); + setActivePath(null); + } + }, [open, scopeValue, teamId, listFiles]); // Map relative name → absolute disk path (for HTTP file serving). const nameToAbsPath = useMemo(() => { @@ -55,6 +84,9 @@ export function TeamWorkspaceDialog({ open, onOpenChange, teamId, scopes }: Team return m; }, [files]); + // Use provided scopes, or cached scopes from first "all" load. + const effectiveScopes = scopes.length > 0 ? scopes : cachedScopes; + const tree = useMemo( () => buildTree(files.map((f) => ({ path: f.name, @@ -122,14 +154,14 @@ export function TeamWorkspaceDialog({ open, onOpenChange, teamId, scopes }: Team
{t("workspace.title")}
- {scopes.length > 0 && ( + {effectiveScopes.length > 1 && ( { - if (!e.target.value) { - setSelectedScope(null); - } else { - const idx = e.target.value.indexOf(":"); - setSelectedScope({ channel: e.target.value.slice(0, idx), chat_id: e.target.value.slice(idx + 1) }); - } - }} - className="rounded-md border bg-background px-2 py-1 text-base md:text-sm" - > - - {scopes.map((s) => ( - - ))} - - )} -
-
- - -
-
- - - - {/* Create Task Dialog */} - - - - {t("tasks.createTaskTitle")} - -
- {/* Subject */} -
- - setSubject(e.target.value)} - placeholder={t("tasks.subjectPlaceholder")} - className="w-full rounded-md border bg-background px-3 py-2 text-base md:text-sm" - autoFocus - /> -
- - {/* Description */} -
- -