feat(grid): add split toolbar layout option
This commit is contained in:
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">
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+71
-7
@@ -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();
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -7169,6 +7169,10 @@ export default withEnglishFallback({
|
||||
debugLogsClear: "ログをクリア",
|
||||
tableStructureSection: "テーブル構造",
|
||||
dataGridDisplay: "データグリッド表示",
|
||||
dataGridToolbarLayout: "テーブルツールバーのレイアウト",
|
||||
dataGridToolbarLayoutDescription: "操作ツールバーとフィルター・並べ替え操作を別の行に表示するか、元の1行レイアウトに戻すかを選択します。",
|
||||
dataGridToolbarLayoutSplit: "別々の行に表示(操作とフィルターを分離)",
|
||||
dataGridToolbarLayoutSingle: "1行で表示(元のレイアウト)",
|
||||
dataGridFilterView: "テーブルフィルタービュー",
|
||||
dataGridFilterViewDescription: "フィルターポップオーバー、固定条件パネル、またはコンパクトなテキスト条件パネルを使用します。",
|
||||
dataGridFilterViewPreview: "効果プレビュー",
|
||||
|
||||
@@ -6904,6 +6904,10 @@ export default withEnglishFallback({
|
||||
debugLogsClear: "로그 지우기",
|
||||
tableStructureSection: "테이블 구조",
|
||||
dataGridDisplay: "데이터 그리드 표시",
|
||||
dataGridToolbarLayout: "데이터 표 도구 모음 레이아웃",
|
||||
dataGridToolbarLayoutDescription: "작업 도구 모음과 필터·정렬 컨트롤을 별도 행으로 표시하거나 기존 한 줄 레이아웃으로 복원합니다.",
|
||||
dataGridToolbarLayoutSplit: "별도 행 표시(작업과 필터 분리)",
|
||||
dataGridToolbarLayoutSingle: "한 줄 표시(기존 레이아웃)",
|
||||
dataGridFilterView: "테이블 필터 보기",
|
||||
dataGridFilterViewDescription: "필터 팝오버, 고정 조건 패널 또는 간결한 텍스트 조건 패널을 사용합니다.",
|
||||
dataGridFilterViewPreview: "효과 미리보기",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -7717,6 +7717,10 @@ export default withEnglishFallback({
|
||||
debugLogsClear: "清空日志",
|
||||
tableStructureSection: "表结构",
|
||||
dataGridDisplay: "数据表格显示",
|
||||
dataGridToolbarLayout: "表格工具栏布局",
|
||||
dataGridToolbarLayoutDescription: "选择将操作工具栏与筛选、排序栏分开展示,或恢复为原来的单行布局。",
|
||||
dataGridToolbarLayoutSplit: "分开展示(操作栏与筛选栏分行)",
|
||||
dataGridToolbarLayoutSingle: "单行显示(原布局)",
|
||||
dataGridFilterView: "表格筛选视图",
|
||||
dataGridFilterViewDescription: "选择弹出式快捷筛选、固定条件面板或紧凑文本条件面板。",
|
||||
dataGridKeepFilterEditorExpanded: "筛选编辑器常驻展开",
|
||||
|
||||
@@ -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", () => {
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user