From 658e3d16adfdb1aa332484065cc858da35071d6e Mon Sep 17 00:00:00 2001 From: zipg Date: Mon, 3 Aug 2026 16:57:26 +0800 Subject: [PATCH] fix(frontend): guard startup and loading shortcuts --- apps/desktop/index.html | 19 ++++ apps/desktop/src/App.vue | 7 ++ .../src/__tests__/startupInputGuard.spec.ts | 38 ++++++++ apps/desktop/src/components/grid/DataGrid.vue | 47 +++++++--- .../__tests__/DataGridLoadingElapsed.spec.ts | 14 +++ .../dataGrid/dataGridClipboard.spec.ts | 28 +++++- .../dataGrid/dataGridNativeSelection.spec.ts | 86 +++++++++++++++++++ .../startup/startupPreloadRecovery.spec.ts | 44 ++++++++++ apps/desktop/src/lib/common/clipboard.ts | 5 ++ .../src/lib/dataGrid/dataGridClipboard.ts | 12 +++ .../lib/dataGrid/dataGridNativeSelection.ts | 60 +++++++++++++ .../src/lib/startup/startupPreloadRecovery.ts | 31 +++++++ apps/desktop/src/main.ts | 4 + apps/desktop/src/stores/queryStore.ts | 4 + apps/desktop/src/styles/globals.css | 16 ++++ packages/app-tests/clipboard.test.ts | 18 +++- packages/app-tests/dataGridPagination.test.ts | 2 +- 17 files changed, 420 insertions(+), 15 deletions(-) create mode 100644 apps/desktop/src/__tests__/startupInputGuard.spec.ts create mode 100644 apps/desktop/src/components/grid/__tests__/DataGridLoadingElapsed.spec.ts create mode 100644 apps/desktop/src/lib/__tests__/dataGrid/dataGridNativeSelection.spec.ts create mode 100644 apps/desktop/src/lib/__tests__/startup/startupPreloadRecovery.spec.ts create mode 100644 apps/desktop/src/lib/dataGrid/dataGridNativeSelection.ts create mode 100644 apps/desktop/src/lib/startup/startupPreloadRecovery.ts diff --git a/apps/desktop/index.html b/apps/desktop/index.html index b8890ef54..be982e97c 100644 --- a/apps/desktop/index.html +++ b/apps/desktop/index.html @@ -47,6 +47,25 @@ root.style.colorScheme = dark ? "dark" : "light"; })(); +
diff --git a/apps/desktop/src/App.vue b/apps/desktop/src/App.vue index 3cb7815e6..e48f5bfba 100644 --- a/apps/desktop/src/App.vue +++ b/apps/desktop/src/App.vue @@ -90,6 +90,7 @@ import { countAvailableAgentDriverUpdates, type AgentDriverUpdateBadgeState } fr import type { DriverStoreFocus } from "@/lib/connection/agentDriverInstallHint"; import { safeLocalStorageGet, safeLocalStorageSet } from "@/lib/backend/safeStorage"; import { apiUrl, webPath } from "@/lib/common/webPath"; +import { shouldBlockAppNativeSelectAll } from "@/lib/common/clipboard"; import { APP_FONT_SANS_CSS_VAR, DATA_GRID_FONT_FAMILY_CSS_VAR, DEFAULT_DATA_GRID_FONT_FAMILY, DEFAULT_UI_FONT_FAMILY } from "@/lib/app/appFonts"; import { rankSavedSqlHistory } from "@/lib/savedSql/savedSqlHistory"; import { savedSqlDefaultTargetForWrite } from "@/lib/savedSql/savedSqlExecutionTarget"; @@ -1873,6 +1874,10 @@ function activateAdjacentTab(direction: -1 | 1): boolean { return activateTabByIndex(nextIndex); } +function handleNativeSelectAll(e: KeyboardEvent) { + if (shouldBlockAppNativeSelectAll(e)) e.preventDefault(); +} + function handleKeydown(e: KeyboardEvent) { if (e.defaultPrevented) return; @@ -2138,6 +2143,7 @@ onMounted(async () => { }); applyTheme(); void applyUiScale(settingsStore.editorSettings.uiScale); + window.addEventListener("keydown", handleNativeSelectAll, true); window.addEventListener("keydown", handleKeydown); window.addEventListener("dbx-open-driver-store", openDriverStoreFromEvent); if (isDesktop) { @@ -2204,6 +2210,7 @@ onUnmounted(() => { if (updateCheckTimer) { clearInterval(updateCheckTimer); } + window.removeEventListener("keydown", handleNativeSelectAll, true); window.removeEventListener("keydown", handleKeydown); window.removeEventListener("dbx-open-driver-store", openDriverStoreFromEvent); document.removeEventListener("contextmenu", handleContextMenu); diff --git a/apps/desktop/src/__tests__/startupInputGuard.spec.ts b/apps/desktop/src/__tests__/startupInputGuard.spec.ts new file mode 100644 index 000000000..0ffbb87d6 --- /dev/null +++ b/apps/desktop/src/__tests__/startupInputGuard.spec.ts @@ -0,0 +1,38 @@ +// @vitest-environment happy-dom + +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; +import { describe, expect, it } from "vitest"; + +const indexSource = readFileSync(resolve(process.cwd(), "apps/desktop/index.html"), "utf8"); +const mainSource = readFileSync(resolve(process.cwd(), "apps/desktop/src/main.ts"), "utf8"); + +function installStartupInputGuard() { + const script = indexSource.match(/