From d79d35792407a646b8c8dab15f98bca854b75054 Mon Sep 17 00:00:00 2001 From: Abeautifulsnow Date: Tue, 1 Sep 2026 11:00:59 +0800 Subject: [PATCH] feat(sql-library): add collapse all button and collapsed default --- .../src/components/layout/SqlLibraryPanel.vue | 51 +++++++++++++++++-- .../layout/__tests__/SqlLibraryPanel.spec.ts | 14 +++++ apps/desktop/src/i18n/locales/en.ts | 1 + apps/desktop/src/i18n/locales/es.ts | 1 + apps/desktop/src/i18n/locales/it.ts | 1 + apps/desktop/src/i18n/locales/ja.ts | 1 + apps/desktop/src/i18n/locales/ko.ts | 1 + apps/desktop/src/i18n/locales/pt-BR.ts | 1 + apps/desktop/src/i18n/locales/zh-CN.ts | 1 + apps/desktop/src/i18n/locales/zh-TW.ts | 1 + 10 files changed, 68 insertions(+), 5 deletions(-) diff --git a/apps/desktop/src/components/layout/SqlLibraryPanel.vue b/apps/desktop/src/components/layout/SqlLibraryPanel.vue index 19278a56fb..cf8913a8f2 100644 --- a/apps/desktop/src/components/layout/SqlLibraryPanel.vue +++ b/apps/desktop/src/components/layout/SqlLibraryPanel.vue @@ -2,7 +2,7 @@ import { computed, nextTick, onBeforeUnmount, reactive, ref, watch } from "vue"; import type { CSSProperties } from "vue"; import { useI18n } from "vue-i18n"; -import { ArrowDownWideNarrow, Download, FilePlus, FileText, FolderCog, FolderClosed, FolderOpen, FolderPlus, Library, LocateFixed, Pencil, Play, Search, Trash2, Upload, X } from "@lucide/vue"; +import { ArrowDownWideNarrow, ChevronsDownUp, Download, FilePlus, FileText, FolderCog, FolderClosed, FolderOpen, FolderPlus, Library, LocateFixed, Pencil, Play, Search, Trash2, Upload, X } from "@lucide/vue"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import CustomContextMenu, { type ContextMenuItem as CtxMenuItem } from "@/components/ui/CustomContextMenu.vue"; @@ -346,7 +346,7 @@ const visibleFolderRows = computed(() => { const appendFolder = (folder: SavedSqlFolder, depth: number) => { if (!folderBranchMatchesQuery(folder)) return; rows.push({ type: "folder", folder, depth, folderIndex: folderIndex++ }); - if (!isFolderExpanded(folder.id)) return; + if (!isFolderExpanded(folder)) return; for (const child of childFolders(folder.id)) { appendFolder(child, depth + 1); } @@ -375,16 +375,52 @@ const hasAnyVisibleItem = computed(() => visibleFolderRows.value.length > 0 || v const collapsedFolders = ref>(new Set()); +// Seed a default-collapsed state when the library first becomes non-empty so +// opening the panel shows every directory collapsed instead of fully expanded. +// Guarded so a later in-session folder add/delete does not re-collapse folders +// the user has already expanded. +const collapseDefaultsSeeded = ref(false); +watch( + () => savedSqlStore.allFolders.map((folder) => folder.id), + (folderIds) => { + if (collapseDefaultsSeeded.value || folderIds.length === 0) return; + collapseDefaultsSeeded.value = true; + collapsedFolders.value = new Set(folderIds); + }, + { immediate: true }, +); + +function collapseAllFolders() { + // Collapse the whole tree: every folder currently known, including nested + // children, is marked collapsed in one shot. + const folderIds = savedSqlStore.allFoldersTreeOrder.map((folder) => folder.id); + if (folderIds.length === 0) return; + collapsedFolders.value = new Set(folderIds); +} + +function hasAnyFolder(): boolean { + return savedSqlStore.allFolders.length > 0; +} + function toggleFolder(folderId: string) { if (suppressNextRowClick.value) return; + // While a search is active, matched branches are force-expanded for + // visibility; toggling them would only mutate hidden state that surprises + // after the search is cleared, so treat the click as a no-op. + if (searchQuery.value) { + const folder = savedSqlStore.allFolders.find((candidate) => candidate.id === folderId); + if (folder && folderBranchMatchesQuery(folder)) return; + } const next = new Set(collapsedFolders.value); if (next.has(folderId)) next.delete(folderId); else next.add(folderId); collapsedFolders.value = next; } -function isFolderExpanded(folderId: string) { - return !collapsedFolders.value.has(folderId); +function isFolderExpanded(folder: SavedSqlFolder) { + // 搜索激活时,命中的分支自动展开以便直接看到匹配文件;否则遵循折叠状态。 + if (searchQuery.value && folderBranchMatchesQuery(folder)) return true; + return !collapsedFolders.value.has(folder.id); } async function openNewFolderInput(parentFolderId?: string) { @@ -1127,6 +1163,11 @@ function showDropInside(targetId: string) { ({{ selectedCount }}) + + +