feat: Query history + saved queries (#5)

* fix: restore frontend test baseline (vitest jsdom env + tsc + mock fixes)

* feat: v6 migration — favorite column + queries table (Task 1)

* feat: extend TS types for favorites + saved queries (Task 2)

* feat: dedup consecutive + prune to 500 in insert_query_history (Task 3)

* feat: favorite column threading + set_history_favorite command (Task 4)

* feat: saved queries store CRUD (Task 5)

* feat: saved query commands + registration (Task 6)

* feat: queryStore — Zustand cache for history + saved queries (Task 7)

* feat: QueryHistoryDropdown — toolbar history dropdown (Task 8)

* feat: SaveQueryDialog — save query modal (Task 9)

* feat: QueryToolbar — add History + Save icons (Task 10)

* feat: QueriesPanel — History + Saved tabs (Task 11)

* feat: wire Queries view + toolbar to panel (Task 12)

* fix: global scope wrappers, empty/spinner states, cache invalidation (Task 13)

* feat: Queries view — history sidebar + tabbed query workspace (PR feedback)

* fix: toolbar action order + view-specific empty state (PR feedback)

* fix: view-specific empty state icon (PR feedback)

* fix: portal Tooltip to body so it is never clipped by overflow containers (PR feedback)

* feat: Queries sidebar — Explorer-style header + per-connection scoping (PR feedback)

* fix: move History/Saved dropdown to right side of Queries header (PR feedback)

* fix: History/Saved dropdown on its own row in Queries header (PR feedback)

* fix: Queries header order (search above dropdown) + sidebar width matches Explorer (PR feedback)

* fix: Queries header spacing — tight rows, pb-3 on container (PR feedback)

* fix: Queries header spacing — space-y-2 on container, no mb on title row (PR feedback)

* feat: history/saved rows click-to-load, remove sub-buttons (PR feedback)

* feat: merge Functions/Triggers/Sequences/Enums/Extensions into single Objects view (PR feedback)

* fix: Schema Visualizer nav icon — node graph glyph (PR feedback)

* fix: Objects view — type dropdown replaces static header label (PR feedback)

* fix: Objects empty state — remove bg circle, larger icon (PR feedback)

* fix: center icon in Objects empty state (PR feedback)

* feat: merge Backup/Restore/DB Sync into single Tools view (PR feedback)

* docs: update AGENTS.md + README for query history/saved queries, merged Objects + Tools views
This commit is contained in:
2026-08-01 17:43:40 +08:00
committed by GitHub
parent 80962d7d11
commit 7db66f1160
33 changed files with 3069 additions and 192 deletions
+67
View File
@@ -0,0 +1,67 @@
// Bun test runner DOM setup: `bun test` uses Bun's native runner, which does
// not read vite.config.ts and provides no DOM. Register jsdom globals (plus the
// ResizeObserver polyfill used by @xyflow/react) so the vitest-authored suite
// runs under `bun test` too. This MUST load before any module that imports
// @testing-library/react, because bun caches modules process-wide and
// testing-library's `screen` binds `document.body` at module-evaluation time.
import { JSDOM } from "jsdom";
if (typeof globalThis.document === "undefined") {
const dom = new JSDOM("<!DOCTYPE html><html><body></body></html>", {
url: "http://localhost/",
pretendToBeVisual: true,
});
const { window } = dom;
for (const key of Object.getOwnPropertyNames(window)) {
if (
key !== "window" &&
key !== "self" &&
key !== "top" &&
!(key in globalThis)
) {
(globalThis as Record<string, unknown>)[key] = (
window as unknown as Record<string, unknown>
)[key];
}
}
globalThis.window = window as unknown as Window & typeof globalThis;
globalThis.document = window.document;
globalThis.navigator = window.navigator;
globalThis.HTMLElement = window.HTMLElement;
globalThis.Element = window.Element;
globalThis.Node = window.Node;
globalThis.getComputedStyle = window.getComputedStyle.bind(window);
globalThis.requestAnimationFrame = (cb: FrameRequestCallback) =>
setTimeout(() => cb(Date.now()), 0) as unknown as number;
globalThis.cancelAnimationFrame = (id: number) => clearTimeout(id);
globalThis.matchMedia =
globalThis.matchMedia ||
((query: string) => ({
matches: false,
media: query,
onchange: null,
addListener: () => {},
removeListener: () => {},
addEventListener: () => {},
removeEventListener: () => {},
dispatchEvent: () => false,
}));
}
// Polyfill ResizeObserver for jsdom (required by @xyflow/react)
if (typeof globalThis.ResizeObserver === "undefined") {
globalThis.ResizeObserver = class ResizeObserver {
observe() {}
unobserve() {}
disconnect() {}
};
}
// jsdom does not implement the execCommand family; monaco-editor probes
// document.queryCommandSupported at import time and crashes without it.
if (typeof globalThis.document.queryCommandSupported !== "function") {
globalThis.document.queryCommandSupported = () => false;
globalThis.document.queryCommandEnabled = () => false;
globalThis.document.execCommand = () => false;
}
+23
View File
@@ -0,0 +1,23 @@
// Bun test runner setup: register testing-library cleanup (bun does not inject
// a global `afterEach`, so RTL's auto-cleanup never hooks in) and minimal
// vitest-compat shims for `vi.mocked`/`vi.hoisted` (bun's compat `vi` omits
// them). Loaded via bunfig.toml [test].preload — bun-dom.ts must run first so
// `document` exists before @testing-library/react evaluates.
import { afterEach, vi } from "vitest";
import { cleanup } from "@testing-library/react";
import "@testing-library/jest-dom";
// NOTE: under `bun test`, importing from "vitest" resolves to bun's built-in
// vitest-compat module (which provides afterEach and a limited vi), while under
// `tsc` it resolves to the real vitest types.
// @testing-library/react auto-cleanup relies on a global `afterEach`, which
// bun does not inject; register it explicitly so DOM doesn't leak between tests.
afterEach(() => {
cleanup();
});
// Minimal vi shims matching vitest semantics used by the suite.
(vi as unknown as { mocked: unknown }).mocked = (m: unknown) => m;
(vi as unknown as { hoisted: unknown }).hoisted = <T>(factory: () => T): T =>
factory();
+4
View File
@@ -0,0 +1,4 @@
// jsdom ships no type declarations and @types/jsdom is not installed; this
// ambient declaration keeps `src/test/bun-dom.ts` (used only by `bun test`)
// type-clean. The JSDOM API is consumed through `any`.
declare module "jsdom";
+1 -1
View File
@@ -1,7 +1,7 @@
import "@testing-library/jest-dom";
// Polyfill ResizeObserver for jsdom (required by @xyflow/react)
global.ResizeObserver = class ResizeObserver {
globalThis.ResizeObserver = class ResizeObserver {
observe() {}
unobserve() {}
disconnect() {}