fix(data-grid): preserve resized column widths across query reruns
This commit is contained in:
1 parent
ff4667b93f
commit
707296c71d
6 files changed
+78
-5
No files matched your search
@@ -452,6 +452,7 @@ interface DataGridProps {
|
||||
countTotalRows?: () => Promise<number | undefined>;
|
||||
loading?: boolean;
|
||||
cacheKey?: string;
|
||||
columnWidthCacheKey?: string;
|
||||
pendingStateKey?: string;
|
||||
exportSql?: string;
|
||||
onExecuteSql?: (sql: string) => Promise<void>;
|
||||
@@ -2714,7 +2715,7 @@ function scrollToColumnIndex(columnIndex: number) {
|
||||
// --- Column resize composable ---
|
||||
const columnWidthDensity = computed(() => settingsStore.editorSettings.columnWidthDensity);
|
||||
const tableFontFamily = computed(() => settingsStore.editorSettings.tableFontFamily);
|
||||
const columnWidthCacheKey = computed(() => props.cacheKey?.trim() || undefined);
|
||||
const columnWidthCacheKey = computed(() => props.columnWidthCacheKey?.trim() || props.cacheKey?.trim() || undefined);
|
||||
const columnStructureSignature = computed(() => createDataGridColumnStructureSignature(props.result.columns, props.result.column_types));
|
||||
// Bumped once the configured header font is ready, so widths measured against a temporary fallback
|
||||
// font get re-measured without reacting to unrelated fonts loaded elsewhere in the application.
|
||||
|
||||
@@ -125,7 +125,20 @@ import { TABLE_FONT_SIZE_MAX, TABLE_FONT_SIZE_MIN, useSettingsStore, type DataGr
|
||||
import { useToast } from "@/composables/useToast";
|
||||
import { isTauriRuntime } from "@/lib/backend/tauriRuntime";
|
||||
import { canCancelQueryExecution, queryExecutionLabelKey } from "@/lib/sql/queryExecutionState";
|
||||
import { databaseDisplayNameForTab, executionSummaryItems, queryResultExecutionSql, resultGridCacheKey, resultGridInstanceKey, resultRunItems, resultSourceRange, resultSqlForGrid, statementExecutionMarkers, tabularResultItems, type ExecutionSummaryItem } from "@/lib/tabs/tabPresentation";
|
||||
import {
|
||||
databaseDisplayNameForTab,
|
||||
executionSummaryItems,
|
||||
queryResultExecutionSql,
|
||||
resultGridCacheKey,
|
||||
resultGridColumnWidthCacheKey,
|
||||
resultGridInstanceKey,
|
||||
resultRunItems,
|
||||
resultSourceRange,
|
||||
resultSqlForGrid,
|
||||
statementExecutionMarkers,
|
||||
tabularResultItems,
|
||||
type ExecutionSummaryItem,
|
||||
} from "@/lib/tabs/tabPresentation";
|
||||
import { defaultQueryResultArchiveFileName } from "@/lib/query/queryResultArchive";
|
||||
import { saveQueryResultArchiveFile } from "@/lib/query/queryResultArchiveFile";
|
||||
import { isTableDataEditable } from "@/lib/table/tableEditing";
|
||||
@@ -443,6 +456,7 @@ const allResultExportSheets = computed(() =>
|
||||
);
|
||||
const resultRuns = computed(() => resultRunItems(props.activeTab));
|
||||
const activeResultGridCacheKey = computed(() => resultGridCacheKey(props.activeTab));
|
||||
const activeResultGridColumnWidthCacheKey = computed(() => resultGridColumnWidthCacheKey(props.activeTab));
|
||||
const activeResultGridInstanceKey = computed(() => resultGridInstanceKey(props.activeTab));
|
||||
const activeResultSql = computed(() => resultSqlForGrid(props.activeTab));
|
||||
const activeResultExportSql = computed(() => queryResultExecutionSql(props.activeTab));
|
||||
@@ -1716,6 +1730,7 @@ defineExpose({
|
||||
ref="dataGridRef"
|
||||
:key="activeResultGridInstanceKey"
|
||||
:cache-key="activeResultGridCacheKey"
|
||||
:column-width-cache-key="activeResultGridColumnWidthCacheKey"
|
||||
:pending-state-key="activeResultGridInstanceKey"
|
||||
class="flex-1 min-h-0"
|
||||
:result="activeTab.result"
|
||||
|
||||
@@ -5,6 +5,7 @@ import { beforeEach, describe, expect, it } from "vitest";
|
||||
import { DATA_GRID_COL_AUTO_FIT_MAX_WIDTH, DATA_GRID_COL_MIN_WIDTH, sampleDataGridColumnValues } from "@/lib/dataGrid/dataGridColumnWidth";
|
||||
import { clearDataGridColumnWidthStates, createDataGridColumnMeasurementSignature, createDataGridColumnStructureSignature, DATA_GRID_COLUMN_WIDTH_STATE_LIMIT, dataGridColumnWidthStateCount, loadDataGridColumnWidthState, saveDataGridColumnWidthState } from "@/lib/dataGrid/dataGridColumnWidthState";
|
||||
import { DATA_GRID_ROW_NUM_WIDTH, dataGridRowNumberColumnWidth, resizeDataGridColumnWidth, useDataGridColumnResize } from "@/composables/useDataGridColumnResize";
|
||||
import { resultGridColumnWidthCacheKey } from "@/lib/tabs/tabPresentation";
|
||||
|
||||
function createResizeState(options: {
|
||||
columns: string[];
|
||||
@@ -178,6 +179,32 @@ describe("useDataGridColumnResize", () => {
|
||||
expect(remounted.columnWidths.value).toEqual(first.columnWidths.value);
|
||||
});
|
||||
|
||||
it("restores manually resized widths when the active result run changes", () => {
|
||||
const firstResult = { id: "tab-1", activeResultRunId: "run-1", activeResultIndex: 2 };
|
||||
const rerunResult = { ...firstResult, activeResultRunId: "run-2" };
|
||||
const firstCacheKey = resultGridColumnWidthCacheKey(firstResult);
|
||||
|
||||
expect(resultGridColumnWidthCacheKey(rerunResult)).toBe(firstCacheKey);
|
||||
|
||||
const first = createResizeState({
|
||||
columns: ["id", "resource"],
|
||||
rows: [[1, "lock"]],
|
||||
cacheKey: firstCacheKey,
|
||||
});
|
||||
first.initColumnWidths();
|
||||
first.onResizeStart(1, new MouseEvent("mousedown", { clientX: 100, cancelable: true }));
|
||||
document.dispatchEvent(new MouseEvent("mouseup", { clientX: 260 }));
|
||||
|
||||
const remounted = createResizeState({
|
||||
columns: ["id", "resource"],
|
||||
rows: [[1, "lock"]],
|
||||
cacheKey: resultGridColumnWidthCacheKey(rerunResult),
|
||||
});
|
||||
remounted.initColumnWidths();
|
||||
|
||||
expect(remounted.columnWidths.value).toEqual(first.columnWidths.value);
|
||||
});
|
||||
|
||||
it("isolates widths by result cache key", () => {
|
||||
const first = createResizeState({ columns: ["id"], rows: [["x".repeat(120)]], cacheKey: "result-a" });
|
||||
first.initColumnWidths();
|
||||
|
||||
+19
-3
@@ -1,7 +1,21 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createPinia, setActivePinia } from "pinia";
|
||||
import { useConnectionStore } from "@/stores/connectionStore";
|
||||
import { connectionGroupDisplayName, executionSummaryItems, middleEllipsis, queryResultBaseSql, queryResultExecutionSql, resultGridCacheKey, resultGridInstanceKey, resultSourceRange, statementExecutionMarkers, tabDisplayTitle, tabTooltipLines, tabularResultItems } from "@/lib/tabs/tabPresentation";
|
||||
import {
|
||||
connectionGroupDisplayName,
|
||||
executionSummaryItems,
|
||||
middleEllipsis,
|
||||
queryResultBaseSql,
|
||||
queryResultExecutionSql,
|
||||
resultGridCacheKey,
|
||||
resultGridColumnWidthCacheKey,
|
||||
resultGridInstanceKey,
|
||||
resultSourceRange,
|
||||
statementExecutionMarkers,
|
||||
tabDisplayTitle,
|
||||
tabTooltipLines,
|
||||
tabularResultItems,
|
||||
} from "@/lib/tabs/tabPresentation";
|
||||
import { sqlTextFingerprint } from "@/lib/sql/sqlTextFingerprint";
|
||||
import type { ConnectionConfig, QueryTab } from "@/types/database";
|
||||
|
||||
@@ -136,12 +150,14 @@ describe("query result labels", () => {
|
||||
describe("query result grid identity", () => {
|
||||
it("separates rerun payloads while retaining run and result-set identity", () => {
|
||||
const first = queryTab({ activeResultRunId: "run-1", activeResultIndex: 2, resultGridRevision: "execution-1" });
|
||||
const rerun = queryTab({ activeResultRunId: "run-1", activeResultIndex: 2, resultGridRevision: "execution-2" });
|
||||
const rerun = queryTab({ activeResultRunId: "run-2", activeResultIndex: 2, resultGridRevision: "execution-2" });
|
||||
|
||||
expect(resultGridInstanceKey(first)).toBe("tab-1-run-1-2-execution-1");
|
||||
expect(resultGridInstanceKey(rerun)).not.toBe(resultGridInstanceKey(first));
|
||||
expect(resultGridInstanceKey({ ...first, activeResultIndex: 1 })).toBe("tab-1-run-1-1-execution-1");
|
||||
expect(resultGridCacheKey(rerun)).toBe(resultGridCacheKey(first));
|
||||
expect(resultGridCacheKey(rerun)).not.toBe(resultGridCacheKey(first));
|
||||
expect(resultGridColumnWidthCacheKey(rerun)).toBe(resultGridColumnWidthCacheKey(first));
|
||||
expect(resultGridColumnWidthCacheKey({ ...first, activeResultIndex: 1 })).not.toBe(resultGridColumnWidthCacheKey(first));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -358,6 +358,10 @@ export function resultGridCacheKey(tab: Pick<QueryTab, "id" | "activeResultRunId
|
||||
return `${tab.id}-${tab.activeResultRunId ?? "current"}-${tab.activeResultIndex ?? 0}`;
|
||||
}
|
||||
|
||||
export function resultGridColumnWidthCacheKey(tab: Pick<QueryTab, "id"> & Partial<Pick<QueryTab, "activeResultIndex">>): string {
|
||||
return `result-column-width-${tab.id}-${tab.activeResultIndex ?? 0}`;
|
||||
}
|
||||
|
||||
export function resultGridInstanceKey(tab: Pick<QueryTab, "id" | "activeResultRunId" | "activeResultIndex" | "resultGridRevision">): string {
|
||||
return `${resultGridCacheKey(tab)}-${tab.resultGridRevision ?? "initial"}`;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user