feat(grid): add split toolbar layout option

This commit is contained in:
_Mr丶s ゛😁® authored and GitHub committed 2026-09-23 19:17:08 +08:00
1 parent 6dcd31c0d2
commit 645adff972
19 files changed
+182 -16

No files matched your search

@@ -88,6 +88,7 @@ import {
type DeleteConnectionTabHandlingMode,
type DataTabReuseMode,
type DataGridFilterEditorView,
type DataGridToolbarLayout,
type MultiStatementDefaultView,
type OpenTabsRestoreMode,
type AppCloseUnsavedTabsMode,
@@ -665,6 +666,7 @@ const editShowIndexIndicatorsInHeader = ref(settingsStore.editorSettings.showInd
const editCompactColumnHeaderActions = ref(settingsStore.editorSettings.compactColumnHeaderActions);
const editDataGridQuickEntry = ref(settingsStore.editorSettings.dataGridQuickEntry);
const editDataGridFilterEditorView = ref<DataGridFilterEditorView>(settingsStore.editorSettings.dataGridFilterEditorView);
const editDataGridToolbarLayout = ref<DataGridToolbarLayout>(settingsStore.editorSettings.dataGridToolbarLayout);
const editDataGridKeepFilterEditorExpanded = ref(settingsStore.editorSettings.dataGridKeepFilterEditorExpanded);
const dataGridFilterViewPreviewExpanded = ref(true);
const editDataGridTextFilterPanelHeight = ref(settingsStore.editorSettings.dataGridTextFilterPanelHeight);
@@ -1006,6 +1008,7 @@ function currentEditorSettingsDraft(): EditorSettingsDraft {
compactColumnHeaderActions: editCompactColumnHeaderActions.value,
dataGridQuickEntry: editDataGridQuickEntry.value,
dataGridFilterEditorView: editDataGridFilterEditorView.value,
dataGridToolbarLayout: editDataGridToolbarLayout.value,
dataGridKeepFilterEditorExpanded: editDataGridKeepFilterEditorExpanded.value,
dataGridTextFilterPanelHeight: editDataGridTextFilterPanelHeight.value,
defaultAutoKeepResults: editDefaultAutoKeepResults.value,
@@ -1649,6 +1652,7 @@ function syncEditorSettingsDraftFromStore() {
editCompactColumnHeaderActions.value = settingsStore.editorSettings.compactColumnHeaderActions;
editDataGridQuickEntry.value = settingsStore.editorSettings.dataGridQuickEntry;
editDataGridFilterEditorView.value = settingsStore.editorSettings.dataGridFilterEditorView;
editDataGridToolbarLayout.value = settingsStore.editorSettings.dataGridToolbarLayout;
editDataGridKeepFilterEditorExpanded.value = settingsStore.editorSettings.dataGridKeepFilterEditorExpanded;
editDataGridTextFilterPanelHeight.value = settingsStore.editorSettings.dataGridTextFilterPanelHeight;
editDefaultAutoKeepResults.value = settingsStore.editorSettings.defaultAutoKeepResults;
@@ -1780,6 +1784,7 @@ const editorSettingsDraftRefs: EditorSettingsDraftRefMap = {
compactColumnHeaderActions: editCompactColumnHeaderActions,
dataGridQuickEntry: editDataGridQuickEntry,
dataGridFilterEditorView: editDataGridFilterEditorView,
dataGridToolbarLayout: editDataGridToolbarLayout,
dataGridKeepFilterEditorExpanded: editDataGridKeepFilterEditorExpanded,
dataGridTextFilterPanelHeight: editDataGridTextFilterPanelHeight,
defaultAutoKeepResults: editDefaultAutoKeepResults,
@@ -2302,6 +2307,7 @@ function resetDefaultsForTab(tab: SettingsCategory) {
editCompactColumnHeaderActions.value = DEFAULT_EDITOR_SETTINGS.compactColumnHeaderActions;
editDataGridQuickEntry.value = DEFAULT_EDITOR_SETTINGS.dataGridQuickEntry;
editDataGridFilterEditorView.value = DEFAULT_EDITOR_SETTINGS.dataGridFilterEditorView;
editDataGridToolbarLayout.value = DEFAULT_EDITOR_SETTINGS.dataGridToolbarLayout;
editDataGridKeepFilterEditorExpanded.value = DEFAULT_EDITOR_SETTINGS.dataGridKeepFilterEditorExpanded;
editDataGridTextFilterPanelHeight.value = DEFAULT_EDITOR_SETTINGS.dataGridTextFilterPanelHeight;
editDefaultAutoKeepResults.value = DEFAULT_EDITOR_SETTINGS.defaultAutoKeepResults;
@@ -2407,6 +2413,7 @@ function resetAllDefaults() {
editCompactColumnHeaderActions.value = DEFAULT_EDITOR_SETTINGS.compactColumnHeaderActions;
editDataGridQuickEntry.value = DEFAULT_EDITOR_SETTINGS.dataGridQuickEntry;
editDataGridFilterEditorView.value = DEFAULT_EDITOR_SETTINGS.dataGridFilterEditorView;
editDataGridToolbarLayout.value = DEFAULT_EDITOR_SETTINGS.dataGridToolbarLayout;
editDataGridKeepFilterEditorExpanded.value = DEFAULT_EDITOR_SETTINGS.dataGridKeepFilterEditorExpanded;
editDataGridTextFilterPanelHeight.value = DEFAULT_EDITOR_SETTINGS.dataGridTextFilterPanelHeight;
editDefaultAutoKeepResults.value = DEFAULT_EDITOR_SETTINGS.defaultAutoKeepResults;
@@ -7537,6 +7544,21 @@ onUnmounted(() => {
<Button type="button" variant="outline" size="sm" @click="historyRetention.load">{{ t("common.retry") }}</Button>
</div>
</div>
<div id="data-grid-toolbar-layout" data-settings-search-id="data-grid-toolbar-layout" :class="['settings-item flex items-center justify-between gap-4 rounded-md border bg-muted/20 px-3 py-2', settingsSearchTargetClass('data-grid-toolbar-layout')]">
<div class="min-w-0 space-y-1">
<Label for="data-grid-toolbar-layout-select">{{ t("settings.dataGridToolbarLayout") }}</Label>
<p class="text-xs text-muted-foreground">{{ t("settings.dataGridToolbarLayoutDescription") }}</p>
</div>
<Select v-model="editDataGridToolbarLayout">
<SelectTrigger id="data-grid-toolbar-layout-select" class="w-48 shrink-0">
<SelectValue :placeholder="t('settings.dataGridToolbarLayout')" />
</SelectTrigger>
<SelectContent>
<SelectItem value="split">{{ t("settings.dataGridToolbarLayoutSplit") }}</SelectItem>
<SelectItem value="single">{{ t("settings.dataGridToolbarLayoutSingle") }}</SelectItem>
</SelectContent>
</Select>
</div>
<div data-settings-search-id="data-grid-filter-view" :class="['overflow-hidden rounded-md border bg-muted/20', settingsSearchTargetClass('data-grid-filter-view')]">
<div class="space-y-3 p-3">
<div class="flex items-start justify-between gap-4">
+26 -4
View File
@@ -758,6 +758,7 @@ const compactColumnHeaderActions = computed(() => settingsStore.editorSettings.c
const dataGridRenderMode = computed(() => settingsStore.editorSettings.dataGridRenderMode);
const dataGridSearchMode = computed(() => settingsStore.editorSettings.dataGridSearchMode);
const compactDataGridToolbar = computed(() => dataGridTopbarOverflowCompact.value || isDataGridToolbarCompact(dataGridTopbarWidth.value, dataGridViewportWidth.value, DATA_GRID_CONDITION_TOOLBAR_MIN_WIDTH));
const splitDataGridToolbar = computed(() => settingsStore.editorSettings.dataGridToolbarLayout === "split");
const responsiveDataGridToolbarActionCount = computed(() => dataGridToolbarActionCollapseCount(dataGridTopbarWidth.value, dataGridViewportWidth.value, DATA_GRID_CONDITION_TOOLBAR_MIN_WIDTH));
const compactDataGridToolbarActionCount = computed(() => Math.max(responsiveDataGridToolbarActionCount.value, dataGridTopbarOverflowActionCount.value));
const infiniteScrollEnabled = computed(() => props.paginationEnabled && settingsStore.editorSettings.infiniteScroll);
@@ -11974,12 +11975,18 @@ useUpdateBlocker(() => (hasPendingChanges.value || hasPendingDataEditorDraft.val
<div v-if="hasData || canShowWhereSearch" class="flex-1 flex flex-col overflow-hidden" @contextmenu="onContextMenu">
<!-- Search bar -->
<!-- Leave real vertical space around the 28px controls instead of fitting them against the border. -->
<div ref="dataGridTopbarRef" v-if="showDataGridTopbar" class="data-grid-topbar-shell flex h-8 min-w-0 shrink-0 items-center border-b bg-muted/20">
<div v-if="hasResultToolbarLeadingSlot" class="flex shrink-0 items-center border-r">
<div
ref="dataGridTopbarRef"
v-if="showDataGridTopbar"
:data-grid-toolbar-layout="settingsStore.editorSettings.dataGridToolbarLayout"
class="data-grid-topbar-shell min-w-0 shrink-0 border-b bg-muted/20"
:class="splitDataGridToolbar ? 'grid h-16 grid-cols-[auto_minmax(0,1fr)] grid-rows-2' : 'flex h-8 items-center'"
>
<div v-if="hasResultToolbarLeadingSlot" data-grid-topbar-row="actions" class="flex shrink-0 items-center border-r" :class="splitDataGridToolbar ? 'col-start-1 row-start-1' : ''">
<slot name="result-toolbar-leading" :compact="compactDataGridToolbar" />
</div>
<!-- Clip both axes instead of creating a hidden scroll container around the toolbar controls. -->
<div class="data-grid-topbar-scroll min-w-0 flex-1 overflow-clip">
<div data-grid-topbar-row="filters" class="data-grid-topbar-scroll min-w-0 overflow-clip" :class="splitDataGridToolbar ? 'data-grid-topbar-scroll--row-divider col-span-2 row-start-2' : 'flex-1'">
<div class="data-grid-topbar flex items-stretch relative" :class="{ 'data-grid-topbar--compact': compactDataGridToolbar }">
<div v-if="useTransaction && editable && hasDataGridSaveTarget" class="flex items-center px-2 py-0.5 border-r shrink-0">
<Select :model-value="rowStatusFilter" @update:model-value="(value: any) => setRowStatusFilter(String(value))">
@@ -12049,7 +12056,8 @@ useUpdateBlocker(() => (hasPendingChanges.value || hasPendingDataEditorDraft.val
</div>
<DataGridToolbar
class="ml-auto"
data-grid-topbar-row="actions"
:class="splitDataGridToolbar ? 'col-start-2 row-start-1' : 'ml-auto'"
:compact-action-count="compactDataGridToolbarActionCount"
:navigation-visible="props.result.columns.length > 0"
:refresh="refreshToolbarCapability"
@@ -14343,6 +14351,20 @@ useUpdateBlocker(() => (hasPendingChanges.value || hasPendingDataEditorDraft.val
scrollbar-gutter: auto;
}
.data-grid-topbar-scroll--row-divider {
position: relative;
}
.data-grid-topbar-scroll--row-divider::before {
position: absolute;
inset: 0 0 auto;
z-index: 1;
height: 1px;
background-color: var(--border);
content: "";
pointer-events: none;
}
.data-grid-topbar-scroll::-webkit-scrollbar {
display: none;
}
@@ -50,7 +50,7 @@ const RecycleScroller = defineComponent({
},
});
function mountGrid(options: { displayableColumns?: boolean; columns?: string[] } = {}) {
function mountGrid(options: { displayableColumns?: boolean; columns?: string[]; slots?: Record<string, () => ReturnType<typeof h>>; withTableMetadata?: boolean } = {}) {
const pinia = createPinia();
setActivePinia(pinia);
const settingsStore = useSettingsStore();
@@ -79,11 +79,22 @@ function mountGrid(options: { displayableColumns?: boolean; columns?: string[] }
{ delayDuration: 0 },
{
default: () =>
h(DataGrid, {
result,
databaseType: "mysql",
context: "table-data",
}),
h(
DataGrid,
{
result,
databaseType: "mysql",
context: "table-data",
...(options.withTableMetadata
? {
connectionId: "test-connection",
database: "test-database",
tableMeta: { tableName: "users", schema: "test-database", columns: [], primaryKeys: [] },
}
: {}),
},
options.slots,
),
},
);
},
@@ -95,7 +106,7 @@ function mountGrid(options: { displayableColumns?: boolean; columns?: string[] }
app.mount(host);
const mounted = { app, host };
mountedApps.push(mounted);
return mounted;
return { ...mounted, settingsStore };
}
async function settle() {
@@ -129,6 +140,7 @@ function goToColumnEvent(target: HTMLElement): KeyboardEvent {
}
afterEach(() => {
vi.restoreAllMocks();
for (const { app, host } of mountedApps.splice(0)) {
app.unmount();
host.remove();
@@ -142,6 +154,58 @@ function functionBody(name: string, nextName: string): string {
}
describe("DataGrid go-to-column shortcut", () => {
it("switches between the split and original single-row toolbar layouts", async () => {
const { host, settingsStore } = mountGrid();
await settle();
const topbar = host.querySelector<HTMLElement>("[data-grid-toolbar-layout]");
expect(topbar?.dataset.gridToolbarLayout).toBe("single");
settingsStore.updateEditorSettings({ dataGridToolbarLayout: "split" });
await settle();
expect(topbar?.dataset.gridToolbarLayout).toBe("split");
expect(topbar?.classList.contains("grid")).toBe(true);
settingsStore.updateEditorSettings({ dataGridToolbarLayout: "single" });
await settle();
expect(topbar?.dataset.gridToolbarLayout).toBe("single");
expect(topbar?.classList.contains("flex")).toBe(true);
expect(host.querySelector('[data-grid-topbar-row="actions"].ml-auto')).not.toBeNull();
settingsStore.updateEditorSettings({ dataGridToolbarLayout: "split" });
await settle();
expect(topbar?.dataset.gridToolbarLayout).toBe("split");
expect(topbar?.classList.contains("grid")).toBe(true);
expect(host.querySelector('[data-grid-topbar-row="filters"].data-grid-topbar-scroll--row-divider')).not.toBeNull();
});
it("does not show a DDL action in the result action toolbar", async () => {
const { host } = mountGrid({ withTableMetadata: true });
await settle();
expect(host.querySelector('[data-toolbar-action="tableInfo"]')).toBeNull();
});
it("keeps result actions and query filters in their separate toolbar rows", async () => {
const { host } = mountGrid({
slots: {
"result-toolbar-leading": () => h("span", { "data-testid": "result-view" }, "结果视图"),
"result-toolbar-actions": () => h("span", { "data-testid": "result-actions" }, "结果操作"),
"search-bar": () => h("span", { "data-testid": "search-controls" }, "文档筛选"),
},
});
await settle();
const actionRowSelector = '[data-grid-topbar-row="actions"]';
const filterRowSelector = '[data-grid-topbar-row="filters"]';
expect(host.querySelector('[data-testid="result-view"]')?.closest(actionRowSelector)).not.toBeNull();
expect(host.querySelector('[data-testid="result-actions"]')?.closest(actionRowSelector)).not.toBeNull();
expect(host.querySelector('[data-testid="search-controls"]')?.closest(filterRowSelector)).not.toBeNull();
});
it("opens and consumes the configured shortcut when a column is displayable", async () => {
const { host } = mountGrid();
await settle();
+4
View File
@@ -7745,6 +7745,10 @@ export default {
debugLogsClear: "Clear logs",
tableStructureSection: "Table Structure",
dataGridDisplay: "Data grid display",
dataGridToolbarLayout: "Data grid toolbar layout",
dataGridToolbarLayoutDescription: "Choose separate rows for the action toolbar and filter/sort controls, or restore the original single-row layout.",
dataGridToolbarLayoutSplit: "Separate rows (actions and filters split)",
dataGridToolbarLayoutSingle: "Single row (original layout)",
dataGridFilterView: "Table filter view",
dataGridFilterViewDescription: "Use a filter popover, a fixed conditions panel, or a compact text conditions panel.",
dataGridKeepFilterEditorExpanded: "Keep filter editor expanded",
+4
View File
@@ -7137,6 +7137,10 @@ export default withEnglishFallback({
debugLogsClear: "Borrar logs",
tableStructureSection: "Estructura de tabla",
dataGridDisplay: "Visualización de la tabla",
dataGridToolbarLayout: "Diseño de la barra de herramientas de la tabla",
dataGridToolbarLayoutDescription: "Elige entre mostrar la barra de acciones separada de los controles de filtro y ordenación o restaurar el diseño original de una sola fila.",
dataGridToolbarLayoutSplit: "Filas separadas (acciones y filtros)",
dataGridToolbarLayoutSingle: "Una sola fila (diseño original)",
dataGridFilterView: "Vista de filtro de tabla",
dataGridFilterViewDescription: "Usa un filtro emergente, un panel de condiciones fijo o un panel de texto compacto.",
dataGridFilterViewPreview: "Vista previa del efecto",
+4
View File
@@ -7136,6 +7136,10 @@ export default withEnglishFallback({
debugLogsClear: "Cancella log",
tableStructureSection: "Struttura tabella",
dataGridDisplay: "Visualizzazione griglia dati",
dataGridToolbarLayout: "Layout della barra degli strumenti della tabella",
dataGridToolbarLayoutDescription: "Scegli se mostrare la barra delle azioni separatamente dai controlli di filtro e ordinamento o ripristinare il layout originale su una sola riga.",
dataGridToolbarLayoutSplit: "Righe separate (azioni e filtri su righe distinte)",
dataGridToolbarLayoutSingle: "Una sola riga (layout originale)",
dataGridFilterView: "Vista filtro tabella",
dataGridFilterViewDescription: "Usa un filtro popup, un pannello condizioni fisso o un pannello di testo compatto.",
dataGridFilterViewPreview: "Anteprima effetto",
+4
View File
@@ -7169,6 +7169,10 @@ export default withEnglishFallback({
debugLogsClear: "ログをクリア",
tableStructureSection: "テーブル構造",
dataGridDisplay: "データグリッド表示",
dataGridToolbarLayout: "テーブルツールバーのレイアウト",
dataGridToolbarLayoutDescription: "操作ツールバーとフィルター・並べ替え操作を別の行に表示するか、元の1行レイアウトに戻すかを選択します。",
dataGridToolbarLayoutSplit: "別々の行に表示(操作とフィルターを分離)",
dataGridToolbarLayoutSingle: "1行で表示(元のレイアウト)",
dataGridFilterView: "テーブルフィルタービュー",
dataGridFilterViewDescription: "フィルターポップオーバー、固定条件パネル、またはコンパクトなテキスト条件パネルを使用します。",
dataGridFilterViewPreview: "効果プレビュー",
+4
View File
@@ -6904,6 +6904,10 @@ export default withEnglishFallback({
debugLogsClear: "로그 지우기",
tableStructureSection: "테이블 구조",
dataGridDisplay: "데이터 그리드 표시",
dataGridToolbarLayout: "데이터 표 도구 모음 레이아웃",
dataGridToolbarLayoutDescription: "작업 도구 모음과 필터·정렬 컨트롤을 별도 행으로 표시하거나 기존 한 줄 레이아웃으로 복원합니다.",
dataGridToolbarLayoutSplit: "별도 행 표시(작업과 필터 분리)",
dataGridToolbarLayoutSingle: "한 줄 표시(기존 레이아웃)",
dataGridFilterView: "테이블 필터 보기",
dataGridFilterViewDescription: "필터 팝오버, 고정 조건 패널 또는 간결한 텍스트 조건 패널을 사용합니다.",
dataGridFilterViewPreview: "효과 미리보기",
+4
View File
@@ -7138,6 +7138,10 @@ export default withEnglishFallback({
debugLogsClear: "Limpar logs",
tableStructureSection: "Estrutura da tabela",
dataGridDisplay: "Exibição da grade de dados",
dataGridToolbarLayout: "Layout da barra de ferramentas da tabela",
dataGridToolbarLayoutDescription: "Escolha entre exibir a barra de ações separada dos controles de filtro e ordenação ou restaurar o layout original de uma única linha.",
dataGridToolbarLayoutSplit: "Linhas separadas (ações e filtros)",
dataGridToolbarLayoutSingle: "Uma única linha (layout original)",
dataGridFilterView: "Visualização de filtro da tabela",
dataGridFilterViewDescription: "Use um filtro pop-up, um painel de condições fixo ou um painel de texto compacto.",
dataGridFilterViewPreview: "Prévia do efeito",
+4
View File
@@ -7717,6 +7717,10 @@ export default withEnglishFallback({
debugLogsClear: "清空日志",
tableStructureSection: "表结构",
dataGridDisplay: "数据表格显示",
dataGridToolbarLayout: "表格工具栏布局",
dataGridToolbarLayoutDescription: "选择将操作工具栏与筛选、排序栏分开展示,或恢复为原来的单行布局。",
dataGridToolbarLayoutSplit: "分开展示(操作栏与筛选栏分行)",
dataGridToolbarLayoutSingle: "单行显示(原布局)",
dataGridFilterView: "表格筛选视图",
dataGridFilterViewDescription: "选择弹出式快捷筛选、固定条件面板或紧凑文本条件面板。",
dataGridKeepFilterEditorExpanded: "筛选编辑器常驻展开",
+4
View File
@@ -6455,6 +6455,10 @@ export default withEnglishFallback({
debugLogsClear: "清空日誌",
tableStructureSection: "表結構",
dataGridDisplay: "資料表格顯示",
dataGridToolbarLayout: "資料表工具列版面配置",
dataGridToolbarLayoutDescription: "選擇將操作工具列與篩選、排序列分開顯示,或還原為原本的單列版面。",
dataGridToolbarLayoutSplit: "分開顯示(操作列與篩選列分行)",
dataGridToolbarLayoutSingle: "單列顯示(原本版面)",
dataGridFilterView: "表格篩選檢視",
dataGridFilterViewDescription: "選擇彈出式快速篩選、固定條件面板或精簡文字條件面板。",
dataGridFilterViewPreview: "效果預覽",
@@ -77,6 +77,13 @@ describe("EDITOR_SETTINGS_DRAFT_KEYS", () => {
expect(EDITOR_SETTINGS_DRAFT_KEYS).toContain("dataTabReuseMode");
});
it("includes the data grid toolbar layout", () => {
expect(EDITOR_SETTINGS_DRAFT_KEYS).toContain("dataGridToolbarLayout");
const draft = editorSettingsDraftFromSettings(makeSettings({ dataGridToolbarLayout: "single" }));
expect(draft.dataGridToolbarLayout).toBe("single");
});
it("includes generated SQL identifier quote preference", () => {
expect(EDITOR_SETTINGS_DRAFT_KEYS).toContain("generateSqlQuoteIdentifiers");
});
@@ -110,6 +117,7 @@ describe("EDITOR_SETTINGS_DRAFT_KEYS", () => {
it("includes the data grid filter view", () => {
expect(EDITOR_SETTINGS_DRAFT_KEYS).toContain("dataGridFilterEditorView");
expect(EDITOR_SETTINGS_DRAFT_KEYS).toContain("dataGridToolbarLayout");
expect(EDITOR_SETTINGS_DRAFT_KEYS).toContain("dataGridKeepFilterEditorExpanded");
expect(EDITOR_SETTINGS_DRAFT_KEYS).toContain("dataGridTextFilterPanelHeight");
});
@@ -315,6 +315,7 @@ describe("settings search", () => {
{ titleKey: "settings.confirmDangerousSqlExecution", category: "editor", targetId: "editor" },
{ titleKey: "settings.continueOnErrorOnBatch", category: "editor", targetId: "editor" },
{ titleKey: "settings.dataGridQuickEntry", category: "data", targetId: "data" },
{ titleKey: "settings.dataGridToolbarLayout", category: "data", targetId: "data-grid-toolbar-layout" },
{ titleKey: "settings.dataGridFilterView", category: "data", targetId: "data-grid-filter-view" },
{ titleKey: "settings.colorizeDataGridCellTypes", category: "data", targetId: "data" },
{ titleKey: "transfer.dataTransfer", category: "appearance", targetId: "appearance" },
@@ -53,6 +53,7 @@ export const EDITOR_SETTINGS_DRAFT_KEYS = [
"compactColumnHeaderActions",
"dataGridQuickEntry",
"dataGridFilterEditorView",
"dataGridToolbarLayout",
"dataGridKeepFilterEditorExpanded",
"dataGridTextFilterPanelHeight",
"defaultAutoKeepResults",
@@ -231,6 +231,7 @@ export const SETTINGS_SEARCH_DEFINITIONS: readonly SettingsSearchDefinition[] =
{ id: "redis-key-templates", category: "data", titleKey: "settings.redisKeyTemplates", descriptionKey: "settings.redisKeyTemplatesDescription", targetId: "redis-key-templates" },
{ id: "data-grid-auto-transpose", category: "data", titleKey: "settings.dataGridAutoTransposeSingleRow", descriptionKey: "settings.dataGridAutoTransposeSingleRowDescription", targetId: "data" },
{ id: "data-grid-quick-entry", category: "data", titleKey: "settings.dataGridQuickEntry", descriptionKey: "settings.dataGridQuickEntryDescription", targetId: "data" },
{ id: "data-grid-toolbar-layout", category: "data", titleKey: "settings.dataGridToolbarLayout", descriptionKey: "settings.dataGridToolbarLayoutDescription", targetId: "data-grid-toolbar-layout" },
{ id: "data-grid-filter-view", category: "data", titleKey: "settings.dataGridFilterView", descriptionKey: "settings.dataGridFilterViewDescription", targetId: "data-grid-filter-view" },
{ id: "data-grid-flattening-multi-line", category: "data", titleKey: "settings.flatteningMultiLineText", descriptionKey: "settings.flatteningMultiLineTextDescription", targetId: "data" },
{ id: "data-grid-show-whitespace", category: "data", titleKey: "settings.dataGridShowWhitespace", descriptionKey: "settings.dataGridShowWhitespaceDescription", targetId: "data" },
@@ -149,6 +149,7 @@ const SETTINGS_TRANSFER_CATEGORY_KEYS: Record<SettingsTransferCategoryId, readon
"dataGridFilterEditorView",
"dataGridKeepFilterEditorExpanded",
"dataGridTextFilterPanelHeight",
"dataGridToolbarLayout",
"defaultAutoKeepResults",
"multiStatementDefaultView",
"dataGridAutoTransposeSingleRow",
@@ -47,6 +47,9 @@ describe("normalizeEditorSettings", () => {
expect(normalizeEditorSettings({ dataGridFilterEditorView: "conditions" }).dataGridFilterEditorView).toBe("conditions");
expect(normalizeEditorSettings({ dataGridFilterEditorView: "text" }).dataGridFilterEditorView).toBe("text");
expect(normalizeEditorSettings({ dataGridFilterEditorView: "invalid" } as any).dataGridFilterEditorView).toBe("quick");
expect(normalizeEditorSettings({}).dataGridToolbarLayout).toBe("single");
expect(normalizeEditorSettings({ dataGridToolbarLayout: "split" }).dataGridToolbarLayout).toBe("split");
expect(normalizeEditorSettings({ dataGridToolbarLayout: "invalid" } as any).dataGridToolbarLayout).toBe("single");
});
it("keeps filter editor expansion disabled unless explicitly enabled", () => {
+9
View File
@@ -664,6 +664,7 @@ export type DataGridRenderMode = (typeof DATA_GRID_RENDER_MODES)[number];
const DATA_GRID_SEARCH_MODES = ["filter", "highlight"] as const;
export type DataGridSearchMode = (typeof DATA_GRID_SEARCH_MODES)[number];
export type DataGridFilterEditorView = "quick" | "conditions" | "text";
export type DataGridToolbarLayout = "single" | "split";
const RESULT_RUN_DISPLAY_MODES = ["tabs", "list"] as const;
export type ResultRunDisplayMode = (typeof RESULT_RUN_DISPLAY_MODES)[number];
const MULTI_STATEMENT_DEFAULT_VIEWS = ["result", "summary"] as const;
@@ -845,6 +846,7 @@ export interface EditorSettings {
columnWidthDensity: ColumnWidthDensity;
dataGridQuickEntry: boolean;
dataGridFilterEditorView: DataGridFilterEditorView;
dataGridToolbarLayout: DataGridToolbarLayout;
dataGridKeepFilterEditorExpanded: boolean;
dataGridTextFilterPanelHeight: number;
localFilterPopoverWidth: number;
@@ -1119,6 +1121,7 @@ export const DEFAULT_EDITOR_SETTINGS: EditorSettings = {
columnWidthDensity: "standard",
dataGridQuickEntry: false,
dataGridFilterEditorView: "quick",
dataGridToolbarLayout: "single",
dataGridKeepFilterEditorExpanded: false,
dataGridTextFilterPanelHeight: DATA_GRID_TEXT_FILTER_PANEL_HEIGHT_DEFAULT,
localFilterPopoverWidth: 360,
@@ -1301,6 +1304,10 @@ function normalizeDataGridFilterEditorView(value: unknown): DataGridFilterEditor
return value === "conditions" || value === "text" ? value : DEFAULT_EDITOR_SETTINGS.dataGridFilterEditorView;
}
function normalizeDataGridToolbarLayout(value: unknown): DataGridToolbarLayout {
return value === "single" || value === "split" ? value : DEFAULT_EDITOR_SETTINGS.dataGridToolbarLayout;
}
function normalizeResultRunDisplayMode(value: unknown): ResultRunDisplayMode {
return RESULT_RUN_DISPLAY_MODES.includes(value as ResultRunDisplayMode) ? (value as ResultRunDisplayMode) : DEFAULT_EDITOR_SETTINGS.resultRunDisplayMode;
}
@@ -1662,6 +1669,7 @@ export function normalizeEditorSettings(settings: Partial<EditorSettings>, exist
columnWidthDensity: normalizeColumnWidthDensity(settings.columnWidthDensity),
dataGridQuickEntry: settings.dataGridQuickEntry ?? DEFAULT_EDITOR_SETTINGS.dataGridQuickEntry,
dataGridFilterEditorView: normalizeDataGridFilterEditorView(settings.dataGridFilterEditorView),
dataGridToolbarLayout: normalizeDataGridToolbarLayout(settings.dataGridToolbarLayout),
dataGridKeepFilterEditorExpanded: typeof settings.dataGridKeepFilterEditorExpanded === "boolean" ? settings.dataGridKeepFilterEditorExpanded : hasDataGridKeepFilterEditorExpanded ? false : legacyDataGridAutoHideFilterBuilder === false,
dataGridTextFilterPanelHeight: normalizeDataGridTextFilterPanelHeight(settings.dataGridTextFilterPanelHeight),
localFilterPopoverWidth: normalizeDrawerWidth(settings.localFilterPopoverWidth, 240, DEFAULT_EDITOR_SETTINGS.localFilterPopoverWidth),
@@ -2485,6 +2493,7 @@ export const useSettingsStore = defineStore("settings", () => {
if (partial.columnWidthDensity !== undefined) editorSettings.value.columnWidthDensity = normalizeColumnWidthDensity(partial.columnWidthDensity);
if (partial.dataGridQuickEntry !== undefined) editorSettings.value.dataGridQuickEntry = partial.dataGridQuickEntry;
if (partial.dataGridFilterEditorView !== undefined) editorSettings.value.dataGridFilterEditorView = normalizeDataGridFilterEditorView(partial.dataGridFilterEditorView);
if (partial.dataGridToolbarLayout !== undefined) editorSettings.value.dataGridToolbarLayout = normalizeDataGridToolbarLayout(partial.dataGridToolbarLayout);
if (partial.dataGridKeepFilterEditorExpanded !== undefined) editorSettings.value.dataGridKeepFilterEditorExpanded = partial.dataGridKeepFilterEditorExpanded === true;
if (partial.dataGridTextFilterPanelHeight !== undefined) editorSettings.value.dataGridTextFilterPanelHeight = normalizeDataGridTextFilterPanelHeight(partial.dataGridTextFilterPanelHeight);
if (partial.localFilterPopoverWidth !== undefined) editorSettings.value.localFilterPopoverWidth = normalizeDrawerWidth(partial.localFilterPopoverWidth, 240, DEFAULT_EDITOR_SETTINGS.localFilterPopoverWidth);