diff --git a/apps/desktop/src/components/editor/QueryEditor.vue b/apps/desktop/src/components/editor/QueryEditor.vue index e3ed3712d..f033cab04 100644 --- a/apps/desktop/src/components/editor/QueryEditor.vue +++ b/apps/desktop/src/components/editor/QueryEditor.vue @@ -1705,7 +1705,16 @@ onMounted(async () => { highlightActiveLineGutter(), highlightSpecialChars(), history(), - foldGutter(), + foldGutter({ + markerDOM(open: boolean) { + const span = document.createElement("span"); + span.className = "cm-foldMarker-svg"; + span.innerHTML = open + ? '' + : ''; + return span; + }, + }), drawSelection(), trimmedSelectionLayer(), selectionMatchOccurrences(), @@ -2249,4 +2258,26 @@ defineExpose({ openSearch, openReplace, scrollCursorIntoView }); .query-editor--table-navigation-hover :deep(.cm-line) { cursor: pointer; } + +:deep(.cm-foldMarker-svg) { + display: inline-flex; + align-items: center; + justify-content: center; + vertical-align: middle; + width: 16px; + height: 16px; + color: var(--muted-foreground); + opacity: 0.65; + transition: opacity 0.15s; +} + +:deep(.cm-foldMarker-svg:hover) { + opacity: 0.95; +} + +:deep(.cm-foldMarker-svg svg) { + display: block; + width: 16px; + height: 16px; +} diff --git a/packages/app-tests/queryStore.test.ts b/packages/app-tests/queryStore.test.ts index f8c62d285..730a89efc 100644 --- a/packages/app-tests/queryStore.test.ts +++ b/packages/app-tests/queryStore.test.ts @@ -157,7 +157,7 @@ test("editing query sql preserves the displayed result editability state", () => assert.equal(tab.tableMeta?.tableName, "users"); }); -test("selecting a result run restores its displayed result without changing SQL draft", () => { +test("selecting a result run restores its displayed result without changing SQL draft", async () => { setActivePinia(createPinia()); const store = useQueryStore(); const tabId = store.createTab("conn-1", "db"); @@ -187,7 +187,7 @@ test("selecting a result run restores its displayed result without changing SQL ]; tab.activeResultRunId = "run-2"; - store.setActiveResultRun(tabId, "run-1"); + await store.setActiveResultRun(tabId, "run-1"); assert.equal(tab.sql, "select draft"); assert.equal(tab.activeResultRunId, "run-1"); @@ -196,7 +196,7 @@ test("selecting a result run restores its displayed result without changing SQL assert.equal(tab.resultBaseSql, "select 1"); }); -test("removing the active result run selects an adjacent run", () => { +test("removing the active result run selects an adjacent run", async () => { setActivePinia(createPinia()); const store = useQueryStore(); const tabId = store.createTab("conn-1", "db"); @@ -233,7 +233,7 @@ test("removing the active result run selects an adjacent run", () => { resultBaseSql: "select 3", }, ]; - store.setActiveResultRun(tabId, "run-2"); + await store.setActiveResultRun(tabId, "run-2"); assert.equal(store.removeResultRun(tabId, "run-2"), true); @@ -349,7 +349,7 @@ test("result archives import into a new query tab with switchable runs", async ( }, ]; tab.activeResultRunId = "run-2"; - store.setActiveResultRun(tabId, "run-2"); + await store.setActiveResultRun(tabId, "run-2"); const archive = await store.exportResultArchive(tabId); assert.ok(archive); @@ -369,7 +369,7 @@ test("result archives import into a new query tab with switchable runs", async ( assert.deepEqual(imported?.result?.columns, ["two"]); assert.deepEqual(imported?.result?.rows, [[2]]); - store.setActiveResultRun(importedTabId, "run-1"); + await store.setActiveResultRun(importedTabId, "run-1"); assert.deepEqual(imported?.result?.columns, ["one"]); assert.deepEqual(imported?.result?.rows, [[1]]); }); @@ -410,6 +410,7 @@ test("completed query executions append result runs and select the latest run", try { const tabId = store.createTab("conn-1", "db", "Query"); + store.toggleResultAutoSave(tabId); await store.executeTabSql(tabId, "select 1"); await store.executeTabSql(tabId, "select 2"); @@ -421,7 +422,7 @@ test("completed query executions append result runs and select the latest run", assert.equal(tab?.activeResultRunId, tab?.resultRuns?.[1]?.id); assert.deepEqual(tab?.result?.columns, ["run_2"]); - store.setActiveResultRun(tabId, tab!.resultRuns![0]!.id); + await store.setActiveResultRun(tabId, tab!.resultRuns![0]!.id); assert.deepEqual(tab?.result?.columns, ["run_1"]); } finally { globalThis.fetch = originalFetch; @@ -454,6 +455,7 @@ test("failed query executions append switchable error result runs", async () => try { const tabId = store.createTab("conn-1", "db", "Query"); + store.toggleResultAutoSave(tabId); await store.executeTabSql(tabId, "select broken"); const tab = store.tabs.find((item) => item.id === tabId); @@ -467,7 +469,7 @@ test("failed query executions append switchable error result runs", async () => } }); -test("statement result switching is scoped to the active result run", () => { +test("statement result switching is scoped to the active result run", async () => { setActivePinia(createPinia()); const store = useQueryStore(); const tabId = store.createTab("conn-1", "db"); @@ -501,13 +503,13 @@ test("statement result switching is scoped to the active result run", () => { }, ]; tab.activeResultRunId = "run-1"; - store.setActiveResultRun(tabId, "run-1"); + await store.setActiveResultRun(tabId, "run-1"); store.setActiveResultIndex(tabId, 1); assert.deepEqual(tab.result?.columns, ["b"]); assert.equal(tab.resultRuns[0]?.activeResultIndex, 1); - store.setActiveResultRun(tabId, "run-2"); + await store.setActiveResultRun(tabId, "run-2"); assert.deepEqual(tab.result?.columns, ["c"]); assert.equal(tab.activeResultIndex, 0); });