diff --git a/apps/desktop/src/components/grid/DataGrid.vue b/apps/desktop/src/components/grid/DataGrid.vue index 56453bddd2..eaa72a1b79 100644 --- a/apps/desktop/src/components/grid/DataGrid.vue +++ b/apps/desktop/src/components/grid/DataGrid.vue @@ -8723,7 +8723,6 @@ const ddlLoading = ref(false); const ddlWidth = ref(settingsStore.editorSettings.tableInfoDrawerWidth); const detailPanelHeight = ref(settingsStore.editorSettings.cellDetailDrawerWidth); const mongoJsonPreviewWidth = ref(MONGO_JSON_PREVIEW_DEFAULT_WIDTH); -const ddlWrap = ref(true); const isResizingDdl = ref(false); const isResizingMongoJsonPreview = ref(false); let ddlResizeStartX = 0; @@ -9245,7 +9244,9 @@ function openTableStructureEditor() { } function toggleDdlWrap() { - ddlWrap.value = !ddlWrap.value; + settingsStore.updateEditorSettings({ + tableDdlWordWrap: !settingsStore.editorSettings.tableDdlWordWrap, + }); } function onDataGridTopbarFixedActionWheel(event: WheelEvent) { @@ -11231,7 +11232,7 @@ const gridContextMenuItems = computed(() => { {{ t("grid.copyDdl") }} - @@ -11437,7 +11438,7 @@ const gridContextMenuItems = computed(() => { data-native-clipboard tabindex="0" class="flex-1 min-w-0 text-xs font-mono p-3 overflow-auto ddl-code leading-5 select-text outline-none" - :class="ddlWrap ? 'whitespace-pre-wrap break-words' : 'whitespace-pre'" + :class="settingsStore.editorSettings.tableDdlWordWrap ? 'whitespace-pre-wrap break-words' : 'whitespace-pre'" v-html="filteredDdlContent" @keydown="onDdlKeydown" > diff --git a/apps/desktop/src/components/objects/ObjectBrowser.vue b/apps/desktop/src/components/objects/ObjectBrowser.vue index 30dc65addf..a25e21ed55 100644 --- a/apps/desktop/src/components/objects/ObjectBrowser.vue +++ b/apps/desktop/src/components/objects/ObjectBrowser.vue @@ -191,7 +191,6 @@ const tableForeignKeysLoading = ref(false); const tableTriggers = ref([]); const tableTriggersLoading = ref(false); const tableInfoSearchQuery = ref(""); -const tableInfoWrap = ref(true); const tableInfoDdlPreRef = ref(null); const SIDE_PANEL_MIN_WIDTH = 280; const SIDE_PANEL_MAX_WIDTH = 900; @@ -207,6 +206,12 @@ const isGaussdbM = computed(() => effectiveDatabaseType.value === "gaussdb" && p const isVictoriaMetrics = computed(() => effectiveDatabaseType.value === "victoriametrics"); const objectRowsLabel = computed(() => t(isVictoriaMetrics.value ? "objects.series" : "objects.rows")); +function toggleTableDdlWordWrap() { + settingsStore.updateEditorSettings({ + tableDdlWordWrap: !settingsStore.editorSettings.tableDdlWordWrap, + }); +} + function gaussdbMColumnType(dataType: string): string { if (isGaussdbM.value) { return gaussdbMTypeDisplayName(dataType); @@ -3144,7 +3149,7 @@ function getObjectBrowserMenuItems(item: ObjectBrowserRow): ContextMenuItem[] { {{ t("grid.copyDdl") }} - @@ -3284,7 +3289,7 @@ function getObjectBrowserMenuItems(item: ObjectBrowserRow): ContextMenuItem[] { data-native-clipboard tabindex="0" class="flex-1 min-w-0 text-xs font-mono p-3 overflow-auto ddl-code leading-5 select-text outline-none" - :class="tableInfoWrap ? 'whitespace-pre-wrap break-words' : 'whitespace-pre'" + :class="settingsStore.editorSettings.tableDdlWordWrap ? 'whitespace-pre-wrap break-words' : 'whitespace-pre'" v-html="filteredTableDdlContent" @keydown="onTableInfoDdlKeydown" > diff --git a/apps/desktop/src/stores/settingsStore.ts b/apps/desktop/src/stores/settingsStore.ts index cf9b992ff9..7744f19a36 100644 --- a/apps/desktop/src/stores/settingsStore.ts +++ b/apps/desktop/src/stores/settingsStore.ts @@ -517,6 +517,7 @@ export interface EditorSettings { insertSpaceAfterCompletion: boolean; sortCompletionColumnsAlphabetically: boolean; wordWrap: boolean; + tableDdlWordWrap: boolean; vimModeEnabled: boolean; autoCloseBrackets: boolean; sqlSemanticDiagnosticsMode: SqlSemanticDiagnosticsMode; @@ -713,6 +714,7 @@ export const DEFAULT_EDITOR_SETTINGS: EditorSettings = { insertSpaceAfterCompletion: true, sortCompletionColumnsAlphabetically: true, wordWrap: false, + tableDdlWordWrap: true, vimModeEnabled: false, autoCloseBrackets: true, sqlSemanticDiagnosticsMode: "auto", @@ -1053,6 +1055,7 @@ export function normalizeEditorSettings(settings: Partial, exist insertSpaceAfterCompletion: typeof settings.insertSpaceAfterCompletion === "boolean" ? settings.insertSpaceAfterCompletion : DEFAULT_EDITOR_SETTINGS.insertSpaceAfterCompletion, sortCompletionColumnsAlphabetically: typeof settings.sortCompletionColumnsAlphabetically === "boolean" ? settings.sortCompletionColumnsAlphabetically : DEFAULT_EDITOR_SETTINGS.sortCompletionColumnsAlphabetically, wordWrap: settings.wordWrap ?? DEFAULT_EDITOR_SETTINGS.wordWrap, + tableDdlWordWrap: typeof settings.tableDdlWordWrap === "boolean" ? settings.tableDdlWordWrap : DEFAULT_EDITOR_SETTINGS.tableDdlWordWrap, vimModeEnabled: typeof settings.vimModeEnabled === "boolean" ? settings.vimModeEnabled : DEFAULT_EDITOR_SETTINGS.vimModeEnabled, autoCloseBrackets: typeof settings.autoCloseBrackets === "boolean" ? settings.autoCloseBrackets : DEFAULT_EDITOR_SETTINGS.autoCloseBrackets, sqlSemanticDiagnosticsMode, @@ -1626,6 +1629,7 @@ export const useSettingsStore = defineStore("settings", () => { if (partial.insertSpaceAfterCompletion !== undefined) editorSettings.value.insertSpaceAfterCompletion = partial.insertSpaceAfterCompletion === true; if (partial.sortCompletionColumnsAlphabetically !== undefined) editorSettings.value.sortCompletionColumnsAlphabetically = partial.sortCompletionColumnsAlphabetically === true; if (partial.wordWrap !== undefined) editorSettings.value.wordWrap = partial.wordWrap; + if (partial.tableDdlWordWrap !== undefined) editorSettings.value.tableDdlWordWrap = partial.tableDdlWordWrap === true; if (partial.vimModeEnabled !== undefined) editorSettings.value.vimModeEnabled = partial.vimModeEnabled === true; if (partial.autoCloseBrackets !== undefined) editorSettings.value.autoCloseBrackets = partial.autoCloseBrackets === true; if (partial.sqlSemanticDiagnosticsMode !== undefined || partial.sqlSemanticDiagnosticsEnabled !== undefined) { diff --git a/packages/app-tests/objectBrowserTableInfo.test.ts b/packages/app-tests/objectBrowserTableInfo.test.ts index 04f7db0e7d..92622e1d21 100644 --- a/packages/app-tests/objectBrowserTableInfo.test.ts +++ b/packages/app-tests/objectBrowserTableInfo.test.ts @@ -53,3 +53,14 @@ test("keeps the data-grid table properties search on the shared column filter", assert.match(source, /filterObjectBrowserTableColumns\(props\.tableMeta\?\.columns \?\? \[\], searchQuery\.value\)/); }); + +test("both table DDL surfaces use the persisted wrapping preference", () => { + const sources = ["apps/desktop/src/components/grid/DataGrid.vue", "apps/desktop/src/components/objects/ObjectBrowser.vue"].map((path) => readFileSync(path, "utf8")); + + for (const source of sources) { + assert.doesNotMatch(source, /const (?:ddlWrap|tableInfoWrap) = ref\(true\)/); + assert.match(source, /:class="\{ 'bg-accent': settingsStore\.editorSettings\.tableDdlWordWrap \}"/); + assert.match(source, /:class="settingsStore\.editorSettings\.tableDdlWordWrap \? 'whitespace-pre-wrap break-words' : 'whitespace-pre'"/); + assert.match(source, /settingsStore\.updateEditorSettings\(\{\s*tableDdlWordWrap: !settingsStore\.editorSettings\.tableDdlWordWrap,?\s*\}\)/); + } +}); diff --git a/packages/app-tests/settingsStore.test.ts b/packages/app-tests/settingsStore.test.ts index 0082b15528..079c14a771 100644 --- a/packages/app-tests/settingsStore.test.ts +++ b/packages/app-tests/settingsStore.test.ts @@ -107,6 +107,19 @@ test("completion column sorting defaults to alphabetical and normalizes saved bo assert.equal(normalizeEditorSettings({ sortCompletionColumnsAlphabetically: "false" as unknown as boolean }).sortCompletionColumnsAlphabetically, true); }); +test("table DDL wrapping defaults on and normalizes saved booleans independently", () => { + assert.equal(DEFAULT_EDITOR_SETTINGS.tableDdlWordWrap, true); + assert.equal(DEFAULT_EDITOR_SETTINGS.wordWrap, false); + assert.equal(normalizeEditorSettings({}).tableDdlWordWrap, true); + assert.equal(normalizeEditorSettings({ tableDdlWordWrap: false }).tableDdlWordWrap, false); + assert.equal(normalizeEditorSettings({ tableDdlWordWrap: true }).tableDdlWordWrap, true); + assert.equal(normalizeEditorSettings({ tableDdlWordWrap: "false" as unknown as boolean }).tableDdlWordWrap, true); + + const settings = normalizeEditorSettings({ tableDdlWordWrap: false, wordWrap: true }); + assert.equal(settings.tableDdlWordWrap, false); + assert.equal(settings.wordWrap, true); +}); + test("updateEditorSettings persists completion column sort toggles", async () => { await withMockLocalStorage({}, async () => { setActivePinia(createPinia()); @@ -122,6 +135,21 @@ test("updateEditorSettings persists completion column sort toggles", async () => }); }); +test("updateEditorSettings persists table DDL wrapping toggles", async () => { + await withMockLocalStorage({}, async () => { + setActivePinia(createPinia()); + const store = useSettingsStore(); + await store.initEditorSettings(); + + store.updateEditorSettings({ tableDdlWordWrap: false }); + assert.equal(store.editorSettings.tableDdlWordWrap, false); + await vi.waitFor(() => { + const saved = saveEditorSettingsMock.mock.calls.at(-1)?.[0] as { tableDdlWordWrap?: boolean } | undefined; + assert.equal(saved?.tableDdlWordWrap, false); + }); + }); +}); + test("updateEditorSettings persists numericColumnRightAlign toggles", async () => { await withMockLocalStorage({}, async () => { setActivePinia(createPinia());