fix(sidebar): show loading while global search is in flight

This commit is contained in:
Melody Ruch authored and GitHub committed 2026-08-15 18:56:58 +08:00
1 parent bdf5f6a87c
commit c573c249ed
6 files changed
+123 -8

No files matched your search

@@ -22,6 +22,7 @@ import {
import { createSidebarLabelMatcher, matchSidebarLabel } from "@/lib/sidebar/sidebarSearch";
import { collectSidebarRegexIndexScopes, resolveSidebarRemoteSearchQuery, resolveSidebarSearchDispatchMode } from "@/lib/sidebar/sidebarRegexSearchIndex";
import { createSidebarSearchExpansionState } from "@/lib/sidebar/sidebarSearchExpansionState";
import { createSidebarSearchLoadingTracker } from "@/lib/sidebar/sidebarSearchLoadingTracker";
import { buildTableTreeNodes } from "@/lib/table/tableTree";
import { isCancelSearchShortcut, isCopySidebarSelectionShortcut, isEditSidebarConnectionShortcut, isPasteSidebarSelectionShortcut, isViewTableDdlShortcut } from "@/lib/editor/keyboardShortcuts";
import { sidebarNodeSupportsDdlView } from "@/lib/sidebar/sidebarTreeDdlShortcut";
@@ -78,6 +79,8 @@ const { toast } = useToast();
const searchQuery = ref("");
const deferredSearchQuery = ref("");
const regexMode = ref(false);
const sidebarSearchLoadingTracker = createSidebarSearchLoadingTracker();
const isSidebarSearchLoading = ref(false);
const showConnectedConnectionsOnly = ref(false);
const isDisconnectingAllActiveConnections = ref(false);
const searchInputRef = ref<HTMLInputElement>();
@@ -262,14 +265,20 @@ watch([deferredSearchQuery, regexMode], ([newQuery, isRegexMode], [oldQuery, was
// Regex search is a read-only projection over live nodes and the local
// table index. It must never trigger ensureConnected/listTables.
const restoreTasks = restoreTrackedSearchTargets();
void Promise.all([loadRegexTableSearchIndexes(), ...restoreTasks])
const searchGeneration = sidebarSearchLoadingTracker.begin();
isSidebarSearchLoading.value = true;
void Promise.allSettled([loadRegexTableSearchIndexes(), ...restoreTasks])
.then(() => {
if (restoreTasks.length > 0) refreshActiveSidebarTableSearches();
})
.catch(() => {});
.finally(() => {
if (sidebarSearchLoadingTracker.end(searchGeneration)) isSidebarSearchLoading.value = false;
});
return;
}
if (dispatchMode === "none") {
sidebarSearchLoadingTracker.cancel();
isSidebarSearchLoading.value = false;
const restoreTasks = restoreTrackedSearchTargets();
if (restoreTasks.length > 0) {
void Promise.all(restoreTasks)
@@ -286,11 +295,21 @@ watch([deferredSearchQuery, regexMode], ([newQuery, isRegexMode], [oldQuery, was
if (!newQuery && oldQuery) {
searchExpansionState.clear();
}
Promise.all(tasks)
let searchGeneration = -1;
if (newQuery && tasks.length > 0) {
searchGeneration = sidebarSearchLoadingTracker.begin();
isSidebarSearchLoading.value = true;
} else {
sidebarSearchLoadingTracker.cancel();
isSidebarSearchLoading.value = false;
}
void Promise.allSettled(tasks)
.then(() => {
if (!newQuery && oldQuery) refreshActiveSidebarTableSearches();
})
.catch(() => {});
.finally(() => {
if (searchGeneration >= 0 && sidebarSearchLoadingTracker.end(searchGeneration)) isSidebarSearchLoading.value = false;
});
});
const searchableObjectGroupTypes = new Set<TreeNodeType>(["group-tables", "group-dolt-system-tables", "group-views", "group-materialized-views", "group-procedures", "group-functions", "group-triggers", "group-sequences", "group-synonyms", "group-packages", "group-types"]);
@@ -2023,7 +2042,8 @@ defineExpose({ focusSearch, createNewGroup, collapseAllTreeNodes });
<div class="connection-tree-search sticky top-0 z-10 bg-background px-2 py-1">
<div class="relative flex items-center gap-1">
<div class="relative flex-1">
<Search class="absolute left-2 top-1/2 -translate-y-1/2 h-3 w-3 text-muted-foreground" />
<Loader2 v-if="isSidebarSearchLoading" class="absolute left-2 top-1/2 -translate-y-1/2 h-3 w-3 animate-spin text-muted-foreground" />
<Search v-else class="absolute left-2 top-1/2 -translate-y-1/2 h-3 w-3 text-muted-foreground" />
<input
ref="searchInputRef"
v-model="searchQuery"