feat(sidebar): add local table search
This commit is contained in:
15 files changed
+421
-17
No files matched your search
@@ -165,6 +165,9 @@ export type TreeClipboard =
|
||||
interface LoadTreeOptions {
|
||||
force?: boolean;
|
||||
expectedSidebarSearchQuery?: string;
|
||||
searchFilter?: string;
|
||||
sidebarTableSearchParentId?: string;
|
||||
expectedSidebarTableSearchQuery?: string;
|
||||
}
|
||||
|
||||
interface PersistedTreeChildrenLoadResult {
|
||||
@@ -218,6 +221,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
const mongoCompletionFieldsCache = ref<Record<string, MongoCompletionField[]>>({});
|
||||
const schemaListCache = ref<Record<string, string[]>>({});
|
||||
const sidebarSearchQuery = ref("");
|
||||
const sidebarTableSearchQueries = ref<Record<string, string>>({});
|
||||
const completionTableIndex = new Map<string, { touched: number; tables: SqlCompletionTable[] }>();
|
||||
const completionObjectIndex = new Map<string, { touched: number; objects: SqlCompletionObject[] }>();
|
||||
const completionColumnIndex = new Map<string, { touched: number; columns: SqlCompletionColumn[] }>();
|
||||
@@ -974,7 +978,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
if (!options.node.connectionId || !options.node.database) {
|
||||
return { children: [], objectCount: 0, hasMore: false, nextOffset: options.offset };
|
||||
}
|
||||
const searchFilter = options.searchFilter || sidebarSearchQuery.value || undefined;
|
||||
const searchFilter = (options.searchFilter ?? sidebarSearchQuery.value) || undefined;
|
||||
const fetchLimit = searchFilter ? options.pageSize : options.pageSize + 1;
|
||||
const tables = await api.listTables(options.node.connectionId, options.node.database, options.querySchema, searchFilter, fetchLimit, searchFilter ? undefined : options.offset, options.objectTypes);
|
||||
const hasMore = searchFilter ? false : tables.length > options.pageSize;
|
||||
@@ -1007,7 +1011,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
pageSize: number;
|
||||
searchFilter?: string;
|
||||
}): Promise<{ children: TreeNode[]; objectCount: number; hasMore: boolean; nextOffset: number }> {
|
||||
const searchFilter = options.searchFilter || sidebarSearchQuery.value || undefined;
|
||||
const searchFilter = (options.searchFilter ?? sidebarSearchQuery.value) || undefined;
|
||||
const fetchLimit = searchFilter ? options.pageSize : options.pageSize + 1;
|
||||
const tables = await api.listTables(options.connectionId, options.database, options.querySchema, searchFilter, fetchLimit, searchFilter ? undefined : options.offset);
|
||||
const hasMore = searchFilter ? false : tables.length > options.pageSize;
|
||||
@@ -1110,6 +1114,20 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
return options?.expectedSidebarSearchQuery !== undefined && (sidebarSearchQuery.value || "") !== options.expectedSidebarSearchQuery;
|
||||
}
|
||||
|
||||
function isSidebarTableSearchQueryChanged(options?: LoadTreeOptions) {
|
||||
if (!options?.sidebarTableSearchParentId || options.expectedSidebarTableSearchQuery === undefined) return false;
|
||||
return (sidebarTableSearchQueries.value[options.sidebarTableSearchParentId]?.trim() || "") !== options.expectedSidebarTableSearchQuery;
|
||||
}
|
||||
|
||||
function activeTreeLoadSearchFilter(options?: LoadTreeOptions): string {
|
||||
return (options?.searchFilter ?? sidebarSearchQuery.value) || "";
|
||||
}
|
||||
|
||||
function isTreeLoadSearchChanged(searchFilter: string, options?: LoadTreeOptions): boolean {
|
||||
if (options?.sidebarTableSearchParentId) return isSidebarTableSearchQueryChanged(options);
|
||||
return (sidebarSearchQuery.value || "") !== searchFilter || isSidebarSearchQueryChanged(options);
|
||||
}
|
||||
|
||||
function isTreeNodeChildrenLoaded(nodeId: string): boolean {
|
||||
return loadedTreeNodeChildrenIds.value.has(nodeId);
|
||||
}
|
||||
@@ -2350,7 +2368,8 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
if (useCachedChildren(node, options)) return;
|
||||
const simpleObjectDisplay = useSettingsStore().editorSettings.sidebarObjectDisplay === "simple";
|
||||
const cacheKey = schemaCacheKey(connectionId, database, schema || "", simpleObjectDisplay ? "objects-simple-v3" : "objects-grouped-v3");
|
||||
const searchFilter = sidebarSearchQuery.value || "";
|
||||
const searchFilter = activeTreeLoadSearchFilter(options);
|
||||
const isSidebarTableSearch = !!options?.sidebarTableSearchParentId;
|
||||
if (!options?.force && !searchFilter) {
|
||||
const cached = await loadPersistedTreeChildren(node, cacheKey);
|
||||
if (cached.hit) {
|
||||
@@ -2388,9 +2407,9 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
objectTypes: supportedSidebarObjectTypes(config),
|
||||
});
|
||||
}
|
||||
if ((sidebarSearchQuery.value || "") !== searchFilter || isSidebarSearchQueryChanged(options)) return;
|
||||
if (isTreeLoadSearchChanged(searchFilter, options)) return;
|
||||
setChildren(node, children);
|
||||
if (!searchFilter) {
|
||||
if (!searchFilter && !isSidebarTableSearch) {
|
||||
await savePersistedTreeChildren(cacheKey, children);
|
||||
}
|
||||
node.isExpanded = true;
|
||||
@@ -2416,7 +2435,8 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
const querySchema = connectionObjectTreeQuerySchema(config, node.database, node.schema);
|
||||
const effectiveSchema = connectionObjectTreeNodeSchema(config, node.database, node.schema);
|
||||
const cacheKey = objectGroupCacheKey(node);
|
||||
const searchFilter = sidebarSearchQuery.value || "";
|
||||
const searchFilter = activeTreeLoadSearchFilter(options);
|
||||
const isSidebarTableSearch = !!options?.sidebarTableSearchParentId;
|
||||
if (!options?.force && !searchFilter) {
|
||||
const cached = await loadPersistedTreeChildren(node, cacheKey);
|
||||
if (cached.hit) {
|
||||
@@ -2451,9 +2471,9 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
});
|
||||
node.objectCount = children.length;
|
||||
}
|
||||
if ((sidebarSearchQuery.value || "") !== searchFilter || isSidebarSearchQueryChanged(options)) return;
|
||||
if (isTreeLoadSearchChanged(searchFilter, options)) return;
|
||||
setChildren(node, children);
|
||||
if (!searchFilter) {
|
||||
if (!searchFilter && !isSidebarTableSearch) {
|
||||
await savePersistedTreeChildren(cacheKey, children);
|
||||
}
|
||||
node.isExpanded = true;
|
||||
@@ -2623,6 +2643,39 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
}
|
||||
}
|
||||
|
||||
function setSidebarTableSearchQuery(parentNodeId: string, query: string) {
|
||||
const normalized = query.trim();
|
||||
const next = { ...sidebarTableSearchQueries.value };
|
||||
if (normalized) {
|
||||
next[parentNodeId] = query;
|
||||
} else {
|
||||
delete next[parentNodeId];
|
||||
}
|
||||
sidebarTableSearchQueries.value = next;
|
||||
}
|
||||
|
||||
async function refreshSidebarTableSearch(parentNodeId: string) {
|
||||
const parent = findNode(treeNodes.value, parentNodeId);
|
||||
if (!parent?.connectionId || !hasTreeNodeDatabaseContext(parent)) return;
|
||||
|
||||
const searchFilter = sidebarTableSearchQueries.value[parentNodeId]?.trim() || "";
|
||||
const options: LoadTreeOptions = {
|
||||
force: true,
|
||||
searchFilter: searchFilter || undefined,
|
||||
sidebarTableSearchParentId: parentNodeId,
|
||||
expectedSidebarTableSearchQuery: searchFilter,
|
||||
};
|
||||
|
||||
if (parent.type === "group-tables") {
|
||||
await loadObjectGroupChildren(parent, options);
|
||||
return;
|
||||
}
|
||||
|
||||
if (parent.type === "database" || parent.type === "schema" || parent.type === "linked-server-schema") {
|
||||
await loadTables(parent.connectionId, parent.database, parent.schema, options);
|
||||
}
|
||||
}
|
||||
|
||||
function normalizedObjectTreeKind(type: string): DatabaseObjectTreeKind {
|
||||
return normalizeSidebarObjectKind(type);
|
||||
}
|
||||
@@ -4313,6 +4366,9 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
databaseSearchSource,
|
||||
databaseExportSource,
|
||||
sidebarSearchQuery,
|
||||
sidebarTableSearchQueries,
|
||||
setSidebarTableSearchQuery,
|
||||
refreshSidebarTableSearch,
|
||||
createConnectionGroup(name: string, parentGroupId?: string | null) {
|
||||
const result = createGroupOp(sidebarLayout.value, name, parentGroupId);
|
||||
updateLayoutAndRebuild(result.layout);
|
||||
|
||||
Reference in new issue
Block a user