From 65af80409997388731f7029b60cdd76247d82ac9 Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Tue, 7 Jul 2026 12:36:19 +0800 Subject: [PATCH] feat(editor): allow disabling SQL snippets --- .../editor/EditorSettingsDialog.vue | 34 ++++++++++++++++--- apps/desktop/src/i18n/locales/en.ts | 4 +++ apps/desktop/src/i18n/locales/es.ts | 4 +++ apps/desktop/src/i18n/locales/it.ts | 4 +++ apps/desktop/src/i18n/locales/ja.ts | 4 +++ apps/desktop/src/i18n/locales/pt-BR.ts | 4 +++ apps/desktop/src/i18n/locales/zh-CN.ts | 4 +++ apps/desktop/src/i18n/locales/zh-TW.ts | 4 +++ .../sql/sqlCompletion.snippet.spec.ts | 5 +++ apps/desktop/src/lib/sql/sqlCompletion.ts | 12 +++++++ apps/desktop/src/stores/settingsStore.ts | 3 +- apps/desktop/src/types/database.ts | 1 + packages/app-tests/settingsStore.test.ts | 16 +++++++++ 13 files changed, 93 insertions(+), 6 deletions(-) diff --git a/apps/desktop/src/components/editor/EditorSettingsDialog.vue b/apps/desktop/src/components/editor/EditorSettingsDialog.vue index 44eeaac3a..95c985f99 100644 --- a/apps/desktop/src/components/editor/EditorSettingsDialog.vue +++ b/apps/desktop/src/components/editor/EditorSettingsDialog.vue @@ -326,7 +326,11 @@ const visibleTableColumnTemplateRows = computed(() => ); // --- Snippet state --- -const editSnippets = ref(settingsStore.editorSettings.snippets.map((s) => ({ ...s }))); +function editableSnippet(snippet: SqlSnippet): SqlSnippet { + return { ...snippet, enabled: snippet.enabled !== false }; +} + +const editSnippets = ref(settingsStore.editorSettings.snippets.map(editableSnippet)); const snippetDialogOpen = ref(false); const snippetEditingId = ref(null); @@ -445,6 +449,7 @@ function saveSnippet() { label: snippetForm.value.label.trim() || prefix, prefix, body: snippetForm.value.body, + enabled: editSnippets.value[idx].enabled !== false, }; } } else { @@ -453,11 +458,18 @@ function saveSnippet() { label: snippetForm.value.label.trim() || prefix, prefix, body: snippetForm.value.body, + enabled: true, }); } snippetDialogOpen.value = false; } +function setSnippetEnabled(id: string, enabled: boolean) { + const idx = editSnippets.value.findIndex((s) => s.id === id); + if (idx === -1) return; + editSnippets.value[idx] = { ...editSnippets.value[idx], enabled }; +} + function deleteSnippet(id: string) { editSnippets.value = editSnippets.value.filter((s) => s.id !== id); } @@ -593,7 +605,7 @@ watch( editQueryExportKeysetOptimizationEnabled.value = settingsStore.editorSettings.queryExportKeysetOptimizationEnabled; editUpdateDownloadSource.value = settingsStore.editorSettings.updateDownloadSource; editToolbarItems.value = { ...settingsStore.editorSettings.toolbarItems }; - editSnippets.value = settingsStore.editorSettings.snippets.map((s) => ({ ...s })); + editSnippets.value = settingsStore.editorSettings.snippets.map(editableSnippet); } }, { immediate: true }, @@ -3470,12 +3482,13 @@ onUnmounted(cleanupPreviewEditor);

{{ t("settings.snippetsDescription") }}

-
- +
+
+ @@ -3491,13 +3507,21 @@ onUnmounted(cleanupPreviewEditor); - + + diff --git a/apps/desktop/src/i18n/locales/en.ts b/apps/desktop/src/i18n/locales/en.ts index 8e38fbd7a..0e8830d4c 100644 --- a/apps/desktop/src/i18n/locales/en.ts +++ b/apps/desktop/src/i18n/locales/en.ts @@ -2942,6 +2942,10 @@ export default { snippetsAdd: "Add Snippet", snippetsLabel: "Label", snippetsPrefix: "Prefix", + snippetsStatus: "Status", + snippetsEnabled: "Enabled", + snippetsDisabled: "Disabled", + snippetsToggle: "Enable or disable snippet", snippetsBody: "SQL Body", snippetsLabelPlaceholder: "e.g. select *", snippetsPrefixPlaceholder: "e.g. sel", diff --git a/apps/desktop/src/i18n/locales/es.ts b/apps/desktop/src/i18n/locales/es.ts index dba8e778e..75259ce95 100644 --- a/apps/desktop/src/i18n/locales/es.ts +++ b/apps/desktop/src/i18n/locales/es.ts @@ -2855,6 +2855,10 @@ export default withEnglishFallback({ snippetsAdd: "Agregar fragmento", snippetsLabel: "Etiqueta", snippetsPrefix: "Prefijo", + snippetsStatus: "Estado", + snippetsEnabled: "Activado", + snippetsDisabled: "Desactivado", + snippetsToggle: "Activar o desactivar fragmento", snippetsBody: "SQL", snippetsLabelPlaceholder: "p. ej. select *", snippetsPrefixPlaceholder: "p. ej. sel", diff --git a/apps/desktop/src/i18n/locales/it.ts b/apps/desktop/src/i18n/locales/it.ts index 76d2967c9..e2dea31ab 100644 --- a/apps/desktop/src/i18n/locales/it.ts +++ b/apps/desktop/src/i18n/locales/it.ts @@ -2853,6 +2853,10 @@ export default withEnglishFallback({ snippetsAdd: "Aggiungi Snippet", snippetsLabel: "Etichetta", snippetsPrefix: "Prefisso", + snippetsStatus: "Stato", + snippetsEnabled: "Attivo", + snippetsDisabled: "Disattivo", + snippetsToggle: "Attiva o disattiva snippet", snippetsBody: "Corpo SQL", snippetsLabelPlaceholder: "es. select *", snippetsPrefixPlaceholder: "es. sel", diff --git a/apps/desktop/src/i18n/locales/ja.ts b/apps/desktop/src/i18n/locales/ja.ts index c43aaa549..139bd1a50 100644 --- a/apps/desktop/src/i18n/locales/ja.ts +++ b/apps/desktop/src/i18n/locales/ja.ts @@ -2844,6 +2844,10 @@ export default withEnglishFallback({ snippetsAdd: "スニペットを追加", snippetsLabel: "ラベル", snippetsPrefix: "プレフィックス", + snippetsStatus: "ステータス", + snippetsEnabled: "有効", + snippetsDisabled: "無効", + snippetsToggle: "スニペットを有効または無効にする", snippetsBody: "SQL本文", snippetsLabelPlaceholder: "例: select *", snippetsPrefixPlaceholder: "例: sel", diff --git a/apps/desktop/src/i18n/locales/pt-BR.ts b/apps/desktop/src/i18n/locales/pt-BR.ts index ea324ebe6..37b91b876 100644 --- a/apps/desktop/src/i18n/locales/pt-BR.ts +++ b/apps/desktop/src/i18n/locales/pt-BR.ts @@ -2854,6 +2854,10 @@ export default withEnglishFallback({ snippetsAdd: "Adicionar snippet", snippetsLabel: "Rótulo", snippetsPrefix: "Prefixo", + snippetsStatus: "Status", + snippetsEnabled: "Ativo", + snippetsDisabled: "Desativado", + snippetsToggle: "Ativar ou desativar snippet", snippetsBody: "Corpo SQL", snippetsLabelPlaceholder: "ex.: select *", snippetsPrefixPlaceholder: "ex.: sel", diff --git a/apps/desktop/src/i18n/locales/zh-CN.ts b/apps/desktop/src/i18n/locales/zh-CN.ts index 4f5f7dec0..d131162c7 100644 --- a/apps/desktop/src/i18n/locales/zh-CN.ts +++ b/apps/desktop/src/i18n/locales/zh-CN.ts @@ -2942,6 +2942,10 @@ export default withEnglishFallback({ snippetsAdd: "添加片段", snippetsLabel: "显示名", snippetsPrefix: "触发键", + snippetsStatus: "状态", + snippetsEnabled: "已启用", + snippetsDisabled: "已关闭", + snippetsToggle: "启用或关闭片段", snippetsBody: "SQL 内容", snippetsLabelPlaceholder: "如:select *", snippetsPrefixPlaceholder: "如:sel", diff --git a/apps/desktop/src/i18n/locales/zh-TW.ts b/apps/desktop/src/i18n/locales/zh-TW.ts index 778aeab61..ceb1477ba 100644 --- a/apps/desktop/src/i18n/locales/zh-TW.ts +++ b/apps/desktop/src/i18n/locales/zh-TW.ts @@ -2751,6 +2751,10 @@ export default withEnglishFallback({ snippetsAdd: "新增片段", snippetsLabel: "顯示名", snippetsPrefix: "觸發鍵", + snippetsStatus: "狀態", + snippetsEnabled: "已啟用", + snippetsDisabled: "已停用", + snippetsToggle: "啟用或停用片段", snippetsBody: "SQL 內容", snippetsLabelPlaceholder: "如:select *", snippetsPrefixPlaceholder: "如:sel", diff --git a/apps/desktop/src/lib/__tests__/sql/sqlCompletion.snippet.spec.ts b/apps/desktop/src/lib/__tests__/sql/sqlCompletion.snippet.spec.ts index 7807911e2..638119545 100644 --- a/apps/desktop/src/lib/__tests__/sql/sqlCompletion.snippet.spec.ts +++ b/apps/desktop/src/lib/__tests__/sql/sqlCompletion.snippet.spec.ts @@ -81,6 +81,11 @@ describe("buildSnippetItems", () => { expect(items[0].label).toBe("select all"); }); + it("does not return disabled snippets", () => { + const items = buildSnippetItemsForTest("sel", [{ ...TEST_SNIPPETS[0], enabled: false }, TEST_SNIPPETS[1]]); + expect(items).toEqual([]); + }); + it("does not keep matching a renamed snippet by its old short label prefix", () => { const items = buildSnippetItemsForTest("sel", [{ id: "1", label: "select all", prefix: "fff", body: "SELECT *\nFROM my_table;" }]); expect(items).toEqual([]); diff --git a/apps/desktop/src/lib/sql/sqlCompletion.ts b/apps/desktop/src/lib/sql/sqlCompletion.ts index e6720ad7b..893086c67 100644 --- a/apps/desktop/src/lib/sql/sqlCompletion.ts +++ b/apps/desktop/src/lib/sql/sqlCompletion.ts @@ -662,66 +662,77 @@ export const DEFAULT_SQL_SNIPPETS: SqlSnippet[] = [ label: "select *", prefix: "sel", body: "SELECT *\nFROM table\nLIMIT 100;", + enabled: true, }, { id: "builtin-ins", label: "insert into", prefix: "ins", body: "INSERT INTO table (columns)\nVALUES (values);", + enabled: true, }, { id: "builtin-upd", label: "update set", prefix: "upd", body: "UPDATE table\nSET column = value\nWHERE condition;", + enabled: true, }, { id: "builtin-cte", label: "common table expression", prefix: "cte", body: "WITH name AS (\n SELECT columns\n FROM table\n)\nSELECT *\nFROM name;", + enabled: true, }, { id: "builtin-join", label: "join", prefix: "join", body: "JOIN table ON left_column = right_column", + enabled: true, }, { id: "builtin-case", label: "case when", prefix: "case", body: "CASE\n WHEN condition THEN value\n ELSE default\nEND", + enabled: true, }, { id: "builtin-ct", label: "create table", prefix: "ct", body: "CREATE TABLE table (\n column type\n);", + enabled: true, }, { id: "builtin-ex", label: "exists", prefix: "ex", body: "EXISTS (\n SELECT 1\n FROM table\n WHERE condition\n)", + enabled: true, }, { id: "builtin-nex", label: "not exists", prefix: "nex", body: "NOT EXISTS (\n SELECT 1\n FROM table\n WHERE condition\n)", + enabled: true, }, { id: "builtin-at", label: "alter table add column", prefix: "at", body: "ALTER TABLE table\nADD COLUMN column type;", + enabled: true, }, { id: "builtin-ci", label: "create index", prefix: "ci", body: "CREATE INDEX idx_name\nON table (column);", + enabled: true, }, ]; @@ -3587,6 +3598,7 @@ function buildSnippetItems(prefix: string, snippets: SqlSnippet[], keywordCase?: if (!prefix) return []; return snippets .filter((snippet) => { + if (snippet.enabled === false) return false; const matchesSnippetPrefix = matchesPrefix(snippet.prefix, prefix); const matchesSnippetLabel = prefix.length > snippet.prefix.length && matchesPrefix(snippet.label, prefix); return matchesSnippetPrefix || matchesSnippetLabel; diff --git a/apps/desktop/src/stores/settingsStore.ts b/apps/desktop/src/stores/settingsStore.ts index 689b2e53f..8861e6f20 100644 --- a/apps/desktop/src/stores/settingsStore.ts +++ b/apps/desktop/src/stores/settingsStore.ts @@ -658,7 +658,8 @@ function normalizeSqlSnippets(value: unknown, existing?: SqlSnippet[]): SqlSnipp } if (seenPrefixes.has(item.prefix)) continue; seenPrefixes.add(item.prefix); - valid.push({ id: item.id, label: item.label, prefix: item.prefix, body: item.body }); + // Older settings do not have this field; only an explicit false disables a snippet. + valid.push({ id: item.id, label: item.label, prefix: item.prefix, body: item.body, enabled: item.enabled !== false }); } if (valid.length === 0) return existing ?? DEFAULT_SQL_SNIPPETS; return valid; diff --git a/apps/desktop/src/types/database.ts b/apps/desktop/src/types/database.ts index 940331ee5..b12fc0eed 100644 --- a/apps/desktop/src/types/database.ts +++ b/apps/desktop/src/types/database.ts @@ -68,6 +68,7 @@ export interface SqlSnippet { label: string; prefix: string; body: string; + enabled?: boolean; } export type CompletionAssistantObjectKind = "database" | "schema" | "table" | "view" | "routine" | "procedure" | "function" | "column"; diff --git a/packages/app-tests/settingsStore.test.ts b/packages/app-tests/settingsStore.test.ts index 1c22dd169..cc3febed0 100644 --- a/packages/app-tests/settingsStore.test.ts +++ b/packages/app-tests/settingsStore.test.ts @@ -136,6 +136,22 @@ test("defaults statement run buttons to enabled and preserves saved booleans", ( assert.equal(normalizeEditorSettings({ showStatementRunButtons: "nope" as any }).showStatementRunButtons, true); }); +test("normalizes SQL snippet enabled state", () => { + const settings = normalizeEditorSettings({ + snippets: [ + { id: "legacy", label: "legacy", prefix: "leg", body: "SELECT 1;" }, + { id: "disabled", label: "disabled", prefix: "dis", body: "SELECT 2;", enabled: false }, + { id: "invalid", label: "invalid", prefix: "inv", body: "SELECT 3;", enabled: "nope" }, + ], + } as any); + + assert.deepEqual(settings.snippets, [ + { id: "legacy", label: "legacy", prefix: "leg", body: "SELECT 1;", enabled: true }, + { id: "disabled", label: "disabled", prefix: "dis", body: "SELECT 2;", enabled: false }, + { id: "invalid", label: "invalid", prefix: "inv", body: "SELECT 3;", enabled: true }, + ]); +}); + test("defaults unsaved SQL close confirmation to enabled", () => { assert.equal(DEFAULT_EDITOR_SETTINGS.confirmUnsavedSqlClose, true); assert.equal(normalizeEditorSettings({}).confirmUnsavedSqlClose, true);
@@ -3484,6 +3497,9 @@ onUnmounted(cleanupPreviewEditor); {{ t("settings.snippetsPrefix") }} + {{ t("settings.snippetsStatus") }} + {{ t("settings.snippetsBody") }}
{{ snippet.label }} {{ snippet.prefix }} +
+ + +
+
{{ snippet.body }}