feat(settings): configure table open page size
This commit is contained in:
21 files changed
+156
-31
No files matched your search
@@ -108,7 +108,7 @@ import ChangelogPanel from "@/components/settings/ChangelogPanel.vue";
|
|||||||
import ScheduledDatabaseBackupSettings from "@/components/backup/ScheduledDatabaseBackupSettings.vue";
|
import ScheduledDatabaseBackupSettings from "@/components/backup/ScheduledDatabaseBackupSettings.vue";
|
||||||
import SqlFormatterSettingsPanel from "./SqlFormatterSettingsPanel.vue";
|
import SqlFormatterSettingsPanel from "./SqlFormatterSettingsPanel.vue";
|
||||||
import { APP_THEME_PALETTES, type AppThemeAppearance, type AppThemeMode, type AppThemePalette } from "@/lib/app/appTheme";
|
import { APP_THEME_PALETTES, type AppThemeAppearance, type AppThemeMode, type AppThemePalette } from "@/lib/app/appTheme";
|
||||||
import { editorSettingsDraftChanged, editorSettingsDraftFromSettings, editorSettingsPatchFromDraft, type EditorSettingsDraft } from "@/lib/settings/editorSettingsDraft";
|
import { editorSettingsDraftChanged, editorSettingsDraftFromSettings, editorSettingsPatchFromDraft, normalizeTableOpenPageSizeDraft, type EditorSettingsDraft } from "@/lib/settings/editorSettingsDraft";
|
||||||
import { useConnectionStore } from "@/stores/connectionStore";
|
import { useConnectionStore } from "@/stores/connectionStore";
|
||||||
import { useSavedSqlStore } from "@/stores/savedSqlStore";
|
import { useSavedSqlStore } from "@/stores/savedSqlStore";
|
||||||
import { useTunnelProfileStore } from "@/stores/tunnelProfileStore";
|
import { useTunnelProfileStore } from "@/stores/tunnelProfileStore";
|
||||||
@@ -119,6 +119,7 @@ import { apiUrl } from "@/lib/common/webPath";
|
|||||||
import { DEFAULT_UI_FONT_FAMILY, SYSTEM_UI_FONT_FAMILY } from "@/lib/app/appFonts";
|
import { DEFAULT_UI_FONT_FAMILY, SYSTEM_UI_FONT_FAMILY } from "@/lib/app/appFonts";
|
||||||
import { buildAppSupportInfoRows, formatAppSupportInfoForClipboard, type AppSupportInfoLabels } from "@/lib/app/supportInfo";
|
import { buildAppSupportInfoRows, formatAppSupportInfoForClipboard, type AppSupportInfoLabels } from "@/lib/app/supportInfo";
|
||||||
import { DateTimePatterns, normalizeSupportedDateTimePattern } from "@/lib/dataGrid/columnFormatter";
|
import { DateTimePatterns, normalizeSupportedDateTimePattern } from "@/lib/dataGrid/columnFormatter";
|
||||||
|
import { MAX_RESULT_PAGE_SIZE, MIN_RESULT_PAGE_SIZE } from "@/lib/dataGrid/paginationPageSize";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
@@ -295,6 +296,7 @@ const editShowColumnCommentsInHeader = ref(settingsStore.editorSettings.showColu
|
|||||||
const editShowColumnTypesInHeader = ref(settingsStore.editorSettings.showColumnTypesInHeader);
|
const editShowColumnTypesInHeader = ref(settingsStore.editorSettings.showColumnTypesInHeader);
|
||||||
const editCompactColumnHeaderActions = ref(settingsStore.editorSettings.compactColumnHeaderActions);
|
const editCompactColumnHeaderActions = ref(settingsStore.editorSettings.compactColumnHeaderActions);
|
||||||
const editDataGridQuickEntry = ref(settingsStore.editorSettings.dataGridQuickEntry);
|
const editDataGridQuickEntry = ref(settingsStore.editorSettings.dataGridQuickEntry);
|
||||||
|
const editTableOpenPageSize = ref(settingsStore.editorSettings.tableOpenPageSize);
|
||||||
const editInfiniteScroll = ref(settingsStore.editorSettings.infiniteScroll);
|
const editInfiniteScroll = ref(settingsStore.editorSettings.infiniteScroll);
|
||||||
const editInfiniteScrollMaxRows = ref(settingsStore.editorSettings.infiniteScrollMaxRows);
|
const editInfiniteScrollMaxRows = ref(settingsStore.editorSettings.infiniteScrollMaxRows);
|
||||||
const editAutoCalculateTotalRows = ref(settingsStore.editorSettings.autoCalculateTotalRows);
|
const editAutoCalculateTotalRows = ref(settingsStore.editorSettings.autoCalculateTotalRows);
|
||||||
@@ -303,6 +305,10 @@ const editTableColumnTemplateDatabaseType = ref<DatabaseType>(TABLE_COLUMN_TEMPL
|
|||||||
const editSqlVariableSyntaxOverrides = ref<SqlVariableSyntaxOverrides>(normalizeSqlVariableSyntaxOverrides(settingsStore.editorSettings.sqlVariableSyntaxOverrides));
|
const editSqlVariableSyntaxOverrides = ref<SqlVariableSyntaxOverrides>(normalizeSqlVariableSyntaxOverrides(settingsStore.editorSettings.sqlVariableSyntaxOverrides));
|
||||||
const editSqlVariableSyntaxDatabaseType = ref<DatabaseType>(SQL_VARIABLE_SYNTAX_DATABASE_TYPES[0] ?? "mysql");
|
const editSqlVariableSyntaxDatabaseType = ref<DatabaseType>(SQL_VARIABLE_SYNTAX_DATABASE_TYPES[0] ?? "mysql");
|
||||||
|
|
||||||
|
function updateTableOpenPageSizeDraft(value: string | number) {
|
||||||
|
editTableOpenPageSize.value = normalizeTableOpenPageSizeDraft(value);
|
||||||
|
}
|
||||||
|
|
||||||
function sqlVariableSyntaxToggle(key: keyof SqlVariableSyntaxToggles): boolean {
|
function sqlVariableSyntaxToggle(key: keyof SqlVariableSyntaxToggles): boolean {
|
||||||
return editSqlVariableSyntaxOverrides.value[editSqlVariableSyntaxDatabaseType.value]?.[key] ?? true;
|
return editSqlVariableSyntaxOverrides.value[editSqlVariableSyntaxDatabaseType.value]?.[key] ?? true;
|
||||||
}
|
}
|
||||||
@@ -428,6 +434,7 @@ function currentEditorSettingsDraft(): EditorSettingsDraft {
|
|||||||
showColumnTypesInHeader: editShowColumnTypesInHeader.value,
|
showColumnTypesInHeader: editShowColumnTypesInHeader.value,
|
||||||
compactColumnHeaderActions: editCompactColumnHeaderActions.value,
|
compactColumnHeaderActions: editCompactColumnHeaderActions.value,
|
||||||
dataGridQuickEntry: editDataGridQuickEntry.value,
|
dataGridQuickEntry: editDataGridQuickEntry.value,
|
||||||
|
tableOpenPageSize: editTableOpenPageSize.value,
|
||||||
infiniteScroll: editInfiniteScroll.value,
|
infiniteScroll: editInfiniteScroll.value,
|
||||||
infiniteScrollMaxRows: editInfiniteScrollMaxRows.value,
|
infiniteScrollMaxRows: editInfiniteScrollMaxRows.value,
|
||||||
autoCalculateTotalRows: editAutoCalculateTotalRows.value,
|
autoCalculateTotalRows: editAutoCalculateTotalRows.value,
|
||||||
@@ -708,6 +715,7 @@ function syncEditorSettingsDraftFromStore() {
|
|||||||
editShowColumnTypesInHeader.value = settingsStore.editorSettings.showColumnTypesInHeader;
|
editShowColumnTypesInHeader.value = settingsStore.editorSettings.showColumnTypesInHeader;
|
||||||
editCompactColumnHeaderActions.value = settingsStore.editorSettings.compactColumnHeaderActions;
|
editCompactColumnHeaderActions.value = settingsStore.editorSettings.compactColumnHeaderActions;
|
||||||
editDataGridQuickEntry.value = settingsStore.editorSettings.dataGridQuickEntry;
|
editDataGridQuickEntry.value = settingsStore.editorSettings.dataGridQuickEntry;
|
||||||
|
editTableOpenPageSize.value = settingsStore.editorSettings.tableOpenPageSize;
|
||||||
editInfiniteScroll.value = settingsStore.editorSettings.infiniteScroll;
|
editInfiniteScroll.value = settingsStore.editorSettings.infiniteScroll;
|
||||||
editInfiniteScrollMaxRows.value = settingsStore.editorSettings.infiniteScrollMaxRows;
|
editInfiniteScrollMaxRows.value = settingsStore.editorSettings.infiniteScrollMaxRows;
|
||||||
editAutoCalculateTotalRows.value = settingsStore.editorSettings.autoCalculateTotalRows;
|
editAutoCalculateTotalRows.value = settingsStore.editorSettings.autoCalculateTotalRows;
|
||||||
@@ -931,6 +939,7 @@ function resetDefaultsForTab(tab: SettingsCategory) {
|
|||||||
editShowColumnTypesInHeader.value = DEFAULT_EDITOR_SETTINGS.showColumnTypesInHeader;
|
editShowColumnTypesInHeader.value = DEFAULT_EDITOR_SETTINGS.showColumnTypesInHeader;
|
||||||
editCompactColumnHeaderActions.value = DEFAULT_EDITOR_SETTINGS.compactColumnHeaderActions;
|
editCompactColumnHeaderActions.value = DEFAULT_EDITOR_SETTINGS.compactColumnHeaderActions;
|
||||||
editDataGridQuickEntry.value = DEFAULT_EDITOR_SETTINGS.dataGridQuickEntry;
|
editDataGridQuickEntry.value = DEFAULT_EDITOR_SETTINGS.dataGridQuickEntry;
|
||||||
|
editTableOpenPageSize.value = DEFAULT_EDITOR_SETTINGS.tableOpenPageSize;
|
||||||
editInfiniteScroll.value = DEFAULT_EDITOR_SETTINGS.infiniteScroll;
|
editInfiniteScroll.value = DEFAULT_EDITOR_SETTINGS.infiniteScroll;
|
||||||
editInfiniteScrollMaxRows.value = DEFAULT_EDITOR_SETTINGS.infiniteScrollMaxRows;
|
editInfiniteScrollMaxRows.value = DEFAULT_EDITOR_SETTINGS.infiniteScrollMaxRows;
|
||||||
editAutoCalculateTotalRows.value = DEFAULT_EDITOR_SETTINGS.autoCalculateTotalRows;
|
editAutoCalculateTotalRows.value = DEFAULT_EDITOR_SETTINGS.autoCalculateTotalRows;
|
||||||
@@ -988,6 +997,7 @@ function resetAllDefaults() {
|
|||||||
editShowColumnTypesInHeader.value = DEFAULT_EDITOR_SETTINGS.showColumnTypesInHeader;
|
editShowColumnTypesInHeader.value = DEFAULT_EDITOR_SETTINGS.showColumnTypesInHeader;
|
||||||
editCompactColumnHeaderActions.value = DEFAULT_EDITOR_SETTINGS.compactColumnHeaderActions;
|
editCompactColumnHeaderActions.value = DEFAULT_EDITOR_SETTINGS.compactColumnHeaderActions;
|
||||||
editDataGridQuickEntry.value = DEFAULT_EDITOR_SETTINGS.dataGridQuickEntry;
|
editDataGridQuickEntry.value = DEFAULT_EDITOR_SETTINGS.dataGridQuickEntry;
|
||||||
|
editTableOpenPageSize.value = DEFAULT_EDITOR_SETTINGS.tableOpenPageSize;
|
||||||
editInfiniteScroll.value = DEFAULT_EDITOR_SETTINGS.infiniteScroll;
|
editInfiniteScroll.value = DEFAULT_EDITOR_SETTINGS.infiniteScroll;
|
||||||
editInfiniteScrollMaxRows.value = DEFAULT_EDITOR_SETTINGS.infiniteScrollMaxRows;
|
editInfiniteScrollMaxRows.value = DEFAULT_EDITOR_SETTINGS.infiniteScrollMaxRows;
|
||||||
editAutoCalculateTotalRows.value = DEFAULT_EDITOR_SETTINGS.autoCalculateTotalRows;
|
editAutoCalculateTotalRows.value = DEFAULT_EDITOR_SETTINGS.autoCalculateTotalRows;
|
||||||
@@ -3818,6 +3828,21 @@ onUnmounted(cleanupPreviewEditor);
|
|||||||
|
|
||||||
<!-- Data Tab -->
|
<!-- Data Tab -->
|
||||||
<section v-else-if="activeSettingsTab === 'data'" class="flex flex-col gap-5 py-2">
|
<section v-else-if="activeSettingsTab === 'data'" class="flex flex-col gap-5 py-2">
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div class="text-sm font-medium text-muted-foreground">{{ t("settings.dataGridDisplay") }}</div>
|
||||||
|
<div class="flex items-center justify-between gap-4 rounded-md border bg-muted/20 px-3 py-2">
|
||||||
|
<div class="space-y-1">
|
||||||
|
<Label for="table-open-page-size">
|
||||||
|
{{ t("settings.tableOpenPageSize") }}
|
||||||
|
</Label>
|
||||||
|
<p class="text-xs text-muted-foreground">
|
||||||
|
{{ t("settings.tableOpenPageSizeDescription") }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Input id="table-open-page-size" type="number" inputmode="numeric" class="h-7 w-24 px-2 text-right text-xs tabular-nums" :min="MIN_RESULT_PAGE_SIZE" :max="MAX_RESULT_PAGE_SIZE" :model-value="editTableOpenPageSize" @update:model-value="updateTableOpenPageSizeDraft" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<template v-if="!isWeb">
|
<template v-if="!isWeb">
|
||||||
<div class="space-y-3">
|
<div class="space-y-3">
|
||||||
<div class="text-sm font-medium text-muted-foreground">DuckDB</div>
|
<div class="text-sm font-medium text-muted-foreground">DuckDB</div>
|
||||||
|
|||||||
@@ -2259,7 +2259,7 @@ watch(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// --- Pagination ---
|
// --- Pagination ---
|
||||||
const pageSize = ref(normalizeResultPageSize(props.context === "table-data" ? (props.pageLimit ?? tableOpenPageLimit()) : settingsStore.editorSettings.pageSize));
|
const pageSize = ref(normalizeResultPageSize(props.context === "table-data" ? (props.pageLimit ?? tableOpenPageLimit(settingsStore.editorSettings.tableOpenPageSize)) : settingsStore.editorSettings.pageSize));
|
||||||
const currentPage = ref(1);
|
const currentPage = ref(1);
|
||||||
const pageSizeOptions = computed(() => resultPageSizeMenuOptions(pageSize.value));
|
const pageSizeOptions = computed(() => resultPageSizeMenuOptions(pageSize.value));
|
||||||
const customPageSizeInput = ref(String(pageSize.value));
|
const customPageSizeInput = ref(String(pageSize.value));
|
||||||
@@ -2522,7 +2522,7 @@ function checkInfiniteScroll(scroller: HTMLElement) {
|
|||||||
function changePageSize(size: number) {
|
function changePageSize(size: number) {
|
||||||
const normalizedSize = normalizeResultPageSize(size);
|
const normalizedSize = normalizeResultPageSize(size);
|
||||||
pageSize.value = normalizedSize;
|
pageSize.value = normalizedSize;
|
||||||
settingsStore.updateEditorSettings({ pageSize: normalizedSize });
|
settingsStore.updateEditorSettings(props.context === "table-data" ? { tableOpenPageSize: normalizedSize } : { pageSize: normalizedSize });
|
||||||
currentPage.value = 1;
|
currentPage.value = 1;
|
||||||
lastInfiniteScrollPage = 0;
|
lastInfiniteScrollPage = 0;
|
||||||
infiniteScrollAllLoaded = false;
|
infiniteScrollAllLoaded = false;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ const mocks = vi.hoisted(() => ({
|
|||||||
getColumns: vi.fn(),
|
getColumns: vi.fn(),
|
||||||
listIndexes: vi.fn(),
|
listIndexes: vi.fn(),
|
||||||
ensureConnected: vi.fn(),
|
ensureConnected: vi.fn(),
|
||||||
|
tableOpenPageSize: 100,
|
||||||
tabs: [] as QueryTab[],
|
tabs: [] as QueryTab[],
|
||||||
setTableMeta: vi.fn(),
|
setTableMeta: vi.fn(),
|
||||||
}));
|
}));
|
||||||
@@ -58,6 +59,10 @@ vi.mock("@/stores/queryStore", () => ({
|
|||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
vi.mock("@/stores/settingsStore", () => ({
|
||||||
|
useSettingsStore: () => ({ editorSettings: { tableOpenPageSize: mocks.tableOpenPageSize } }),
|
||||||
|
}));
|
||||||
|
|
||||||
vi.mock("@/composables/useToast", () => ({
|
vi.mock("@/composables/useToast", () => ({
|
||||||
useToast: () => ({ toast: vi.fn() }),
|
useToast: () => ({ toast: vi.fn() }),
|
||||||
}));
|
}));
|
||||||
@@ -92,6 +97,7 @@ describe("useDataGridActions", () => {
|
|||||||
clearTableMetadataCache();
|
clearTableMetadataCache();
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
mocks.tabs.length = 0;
|
mocks.tabs.length = 0;
|
||||||
|
mocks.tableOpenPageSize = 100;
|
||||||
mocks.getConfig.mockReturnValue({ id: "postgres-1", db_type: "postgres" });
|
mocks.getConfig.mockReturnValue({ id: "postgres-1", db_type: "postgres" });
|
||||||
mocks.buildTableSelectSql.mockResolvedValue("SELECT * FROM public.users LIMIT 100 OFFSET 0");
|
mocks.buildTableSelectSql.mockResolvedValue("SELECT * FROM public.users LIMIT 100 OFFSET 0");
|
||||||
mocks.buildSortedQuerySql.mockResolvedValue({ ok: true, sql: "SELECT sorted" });
|
mocks.buildSortedQuerySql.mockResolvedValue({ ok: true, sql: "SELECT sorted" });
|
||||||
@@ -100,7 +106,9 @@ describe("useDataGridActions", () => {
|
|||||||
mocks.listIndexes.mockResolvedValue([]);
|
mocks.listIndexes.mockResolvedValue([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("uses the table-data default when toolbar reload has no saved pagination", async () => {
|
it("uses the configured table-data default when toolbar reload has no saved pagination", async () => {
|
||||||
|
mocks.tableOpenPageSize = 250;
|
||||||
|
mocks.buildTableSelectSql.mockResolvedValueOnce("SELECT * FROM public.users LIMIT 250 OFFSET 0");
|
||||||
const tab = tableDataTab();
|
const tab = tableDataTab();
|
||||||
const actions = useDataGridActions(computed(() => tab));
|
const actions = useDataGridActions(computed(() => tab));
|
||||||
|
|
||||||
@@ -108,11 +116,11 @@ describe("useDataGridActions", () => {
|
|||||||
|
|
||||||
expect(mocks.buildTableSelectSql).toHaveBeenCalledWith(
|
expect(mocks.buildTableSelectSql).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
limit: 100,
|
limit: 250,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
expect(mocks.executeTabSql).toHaveBeenCalledWith("tab-1", "SELECT * FROM public.users LIMIT 100 OFFSET 0", expect.objectContaining({ pagination: { limit: 100, offset: 0 } }));
|
expect(mocks.executeTabSql).toHaveBeenCalledWith("tab-1", "SELECT * FROM public.users LIMIT 250 OFFSET 0", expect.objectContaining({ pagination: { limit: 250, offset: 0 } }));
|
||||||
expect(mocks.executeTabSql.mock.calls[0]?.[2]).not.toHaveProperty("preserveTotalRowCountDuringExecution");
|
expect(mocks.executeTabSql.mock.calls[0]?.[2]).not.toHaveProperty("preserveTotalRowCountDuringExecution");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { type ComputedRef } from "vue";
|
|||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { useConnectionStore } from "@/stores/connectionStore";
|
import { useConnectionStore } from "@/stores/connectionStore";
|
||||||
import { useQueryStore } from "@/stores/queryStore";
|
import { useQueryStore } from "@/stores/queryStore";
|
||||||
|
import { useSettingsStore } from "@/stores/settingsStore";
|
||||||
import { buildTableSelectSql, quoteTableDataIdentifier } from "@/lib/table/tableSelectSql";
|
import { buildTableSelectSql, quoteTableDataIdentifier } from "@/lib/table/tableSelectSql";
|
||||||
import { tableOpenPageLimit } from "@/lib/table/tableOpenPageLimit";
|
import { tableOpenPageLimit } from "@/lib/table/tableOpenPageLimit";
|
||||||
import { usesSyntheticRowIdKey } from "@/lib/table/tableEditing";
|
import { usesSyntheticRowIdKey } from "@/lib/table/tableEditing";
|
||||||
@@ -37,6 +38,7 @@ export function useDataGridActions(activeTab: ComputedRef<QueryTab | undefined>)
|
|||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const connectionStore = useConnectionStore();
|
const connectionStore = useConnectionStore();
|
||||||
const queryStore = useQueryStore();
|
const queryStore = useQueryStore();
|
||||||
|
const settingsStore = useSettingsStore();
|
||||||
|
|
||||||
function quoteIdent(tab: QueryTab, name: string): string {
|
function quoteIdent(tab: QueryTab, name: string): string {
|
||||||
const config = connectionStore.getConfig(tab.connectionId);
|
const config = connectionStore.getConfig(tab.connectionId);
|
||||||
@@ -64,7 +66,7 @@ export function useDataGridActions(activeTab: ComputedRef<QueryTab | undefined>)
|
|||||||
columns: realColumns?.map((column) => column.name),
|
columns: realColumns?.map((column) => column.name),
|
||||||
primaryKeys,
|
primaryKeys,
|
||||||
includeRowId: useRowId,
|
includeRowId: useRowId,
|
||||||
limit: options.limit ?? tab.resultPageLimit ?? tableOpenPageLimit(),
|
limit: options.limit ?? tab.resultPageLimit ?? tableOpenPageLimit(settingsStore.editorSettings.tableOpenPageSize),
|
||||||
...options,
|
...options,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -135,7 +137,7 @@ export function useDataGridActions(activeTab: ComputedRef<QueryTab | undefined>)
|
|||||||
const elapsed = () => `${Math.round(performance.now() - startedAt)}ms`;
|
const elapsed = () => `${Math.round(performance.now() - startedAt)}ms`;
|
||||||
if (tab.mode === "data" && tableMetaForDataTab(tab)) {
|
if (tab.mode === "data" && tableMetaForDataTab(tab)) {
|
||||||
tab.whereInput = whereInput ?? "";
|
tab.whereInput = whereInput ?? "";
|
||||||
const pageLimit = limit ?? tab.resultPageLimit ?? tableOpenPageLimit();
|
const pageLimit = limit ?? tab.resultPageLimit ?? tableOpenPageLimit(settingsStore.editorSettings.tableOpenPageSize);
|
||||||
const pageOffset = offset ?? 0;
|
const pageOffset = offset ?? 0;
|
||||||
console.info("[DBX][reloadData:start]", {
|
console.info("[DBX][reloadData:start]", {
|
||||||
traceId,
|
traceId,
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ async function openTableTarget(target: NavigationTarget, options: { tableInfoTab
|
|||||||
const connectionStore = useConnectionStore();
|
const connectionStore = useConnectionStore();
|
||||||
const queryStore = useQueryStore();
|
const queryStore = useQueryStore();
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
const pageLimit = tableOpenPageLimit();
|
const pageLimit = tableOpenPageLimit(settingsStore.editorSettings.tableOpenPageSize);
|
||||||
|
|
||||||
connectionStore.activeConnectionId = target.connectionId;
|
connectionStore.activeConnectionId = target.connectionId;
|
||||||
const config = connectionStore.getConfig(target.connectionId);
|
const config = connectionStore.getConfig(target.connectionId);
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ export function useSidebarDataOpenRuntime() {
|
|||||||
logPhase("ensure-connected", { tabId });
|
logPhase("ensure-connected", { tabId });
|
||||||
if (!config) throw new Error("Connection config not found");
|
if (!config) throw new Error("Connection config not found");
|
||||||
|
|
||||||
const limit = tableOpenPageLimit();
|
const limit = tableOpenPageLimit(settingsStore.editorSettings.tableOpenPageSize);
|
||||||
const shouldRefreshTableMeta = !cachedTableMeta;
|
const shouldRefreshTableMeta = !cachedTableMeta;
|
||||||
// Dameng metadata calls must remain serialized behind the table query.
|
// Dameng metadata calls must remain serialized behind the table query.
|
||||||
const deferTableMetaRefresh = effectiveDbType === "dameng";
|
const deferTableMetaRefresh = effectiveDbType === "dameng";
|
||||||
|
|||||||
@@ -3576,6 +3576,8 @@ export default {
|
|||||||
debugLogsClear: "Clear logs",
|
debugLogsClear: "Clear logs",
|
||||||
tableStructureSection: "Table Structure",
|
tableStructureSection: "Table Structure",
|
||||||
dataGridDisplay: "Data grid display",
|
dataGridDisplay: "Data grid display",
|
||||||
|
tableOpenPageSize: "Default rows per page when opening tables",
|
||||||
|
tableOpenPageSizeDescription: "Rows loaded per page when opening a new table. Changing rows per page in a table updates this default for future table tabs.",
|
||||||
showColumnCommentsInHeader: "Show column comments under names",
|
showColumnCommentsInHeader: "Show column comments under names",
|
||||||
showColumnCommentsInHeaderDescription: "Display table column comments directly below grid column names.",
|
showColumnCommentsInHeaderDescription: "Display table column comments directly below grid column names.",
|
||||||
showColumnTypesInHeader: "Show column types under names",
|
showColumnTypesInHeader: "Show column types under names",
|
||||||
|
|||||||
@@ -3354,6 +3354,8 @@ export default withEnglishFallback({
|
|||||||
debugLogsClear: "Borrar logs",
|
debugLogsClear: "Borrar logs",
|
||||||
tableStructureSection: "Estructura de tabla",
|
tableStructureSection: "Estructura de tabla",
|
||||||
dataGridDisplay: "Visualización de la tabla",
|
dataGridDisplay: "Visualización de la tabla",
|
||||||
|
tableOpenPageSize: "Filas predeterminadas por página al abrir tablas",
|
||||||
|
tableOpenPageSizeDescription: "Filas cargadas por página al abrir una tabla nueva. Cambiar las filas por página actualiza este valor para futuras pestañas de tablas.",
|
||||||
showColumnCommentsInHeader: "Mostrar comentarios bajo los nombres",
|
showColumnCommentsInHeader: "Mostrar comentarios bajo los nombres",
|
||||||
showColumnCommentsInHeaderDescription: "Muestra los comentarios de columnas directamente debajo del nombre de la columna.",
|
showColumnCommentsInHeaderDescription: "Muestra los comentarios de columnas directamente debajo del nombre de la columna.",
|
||||||
showColumnTypesInHeader: "Mostrar tipos de columna bajo los nombres",
|
showColumnTypesInHeader: "Mostrar tipos de columna bajo los nombres",
|
||||||
|
|||||||
@@ -3352,6 +3352,8 @@ export default withEnglishFallback({
|
|||||||
debugLogsClear: "Cancella log",
|
debugLogsClear: "Cancella log",
|
||||||
tableStructureSection: "Struttura tabella",
|
tableStructureSection: "Struttura tabella",
|
||||||
dataGridDisplay: "Visualizzazione griglia dati",
|
dataGridDisplay: "Visualizzazione griglia dati",
|
||||||
|
tableOpenPageSize: "Righe predefinite per pagina all'apertura delle tabelle",
|
||||||
|
tableOpenPageSizeDescription: "Righe caricate per pagina quando si apre una nuova tabella. La modifica delle righe per pagina aggiorna questo valore per le future schede tabella.",
|
||||||
showColumnCommentsInHeader: "Mostra i commenti delle colonne sotto i nomi",
|
showColumnCommentsInHeader: "Mostra i commenti delle colonne sotto i nomi",
|
||||||
showColumnCommentsInHeaderDescription: "Visualizza i commenti delle colonne della tabella direttamente sotto i nomi delle colonne nella griglia.",
|
showColumnCommentsInHeaderDescription: "Visualizza i commenti delle colonne della tabella direttamente sotto i nomi delle colonne nella griglia.",
|
||||||
showColumnTypesInHeader: "Mostra i tipi di colonna sotto i nomi",
|
showColumnTypesInHeader: "Mostra i tipi di colonna sotto i nomi",
|
||||||
|
|||||||
@@ -3349,6 +3349,8 @@ export default withEnglishFallback({
|
|||||||
debugLogsClear: "ログをクリア",
|
debugLogsClear: "ログをクリア",
|
||||||
tableStructureSection: "テーブル構造",
|
tableStructureSection: "テーブル構造",
|
||||||
dataGridDisplay: "データグリッド表示",
|
dataGridDisplay: "データグリッド表示",
|
||||||
|
tableOpenPageSize: "テーブルを開くときのデフォルト行数",
|
||||||
|
tableOpenPageSizeDescription: "新しいテーブルを開くときに 1 ページあたり読み込む行数です。テーブルで行数を変更すると、今後のテーブルタブのデフォルトも更新されます。",
|
||||||
showColumnCommentsInHeader: "列名の下にコメントを表示",
|
showColumnCommentsInHeader: "列名の下にコメントを表示",
|
||||||
showColumnCommentsInHeaderDescription: "グリッド列名の直下にテーブル列コメントを表示します。",
|
showColumnCommentsInHeaderDescription: "グリッド列名の直下にテーブル列コメントを表示します。",
|
||||||
showColumnTypesInHeader: "列名の下にデータ型を表示",
|
showColumnTypesInHeader: "列名の下にデータ型を表示",
|
||||||
|
|||||||
@@ -3354,6 +3354,8 @@ export default withEnglishFallback({
|
|||||||
debugLogsClear: "Limpar logs",
|
debugLogsClear: "Limpar logs",
|
||||||
tableStructureSection: "Estrutura da tabela",
|
tableStructureSection: "Estrutura da tabela",
|
||||||
dataGridDisplay: "Exibição da grade de dados",
|
dataGridDisplay: "Exibição da grade de dados",
|
||||||
|
tableOpenPageSize: "Linhas padrão por página ao abrir tabelas",
|
||||||
|
tableOpenPageSizeDescription: "Linhas carregadas por página ao abrir uma nova tabela. Alterar as linhas por página atualiza esse padrão para futuras abas de tabelas.",
|
||||||
showColumnCommentsInHeader: "Mostrar comentários de coluna sob os nomes",
|
showColumnCommentsInHeader: "Mostrar comentários de coluna sob os nomes",
|
||||||
showColumnCommentsInHeaderDescription: "Exibir comentários de colunas da tabela diretamente abaixo dos nomes das colunas da grade.",
|
showColumnCommentsInHeaderDescription: "Exibir comentários de colunas da tabela diretamente abaixo dos nomes das colunas da grade.",
|
||||||
showColumnTypesInHeader: "Mostrar tipos de coluna sob os nomes",
|
showColumnTypesInHeader: "Mostrar tipos de coluna sob os nomes",
|
||||||
|
|||||||
@@ -3566,6 +3566,8 @@ export default withEnglishFallback({
|
|||||||
debugLogsClear: "清空日志",
|
debugLogsClear: "清空日志",
|
||||||
tableStructureSection: "表结构",
|
tableStructureSection: "表结构",
|
||||||
dataGridDisplay: "数据表格显示",
|
dataGridDisplay: "数据表格显示",
|
||||||
|
tableOpenPageSize: "打开表默认每页行数",
|
||||||
|
tableOpenPageSizeDescription: "新打开数据表时每页加载的行数。在表数据页修改每页行数后,也会更新后续新建表标签页的默认值。",
|
||||||
showColumnCommentsInHeader: "在字段名下方显示注释",
|
showColumnCommentsInHeader: "在字段名下方显示注释",
|
||||||
showColumnCommentsInHeaderDescription: "把表字段注释直接显示在结果表头字段名下方。",
|
showColumnCommentsInHeaderDescription: "把表字段注释直接显示在结果表头字段名下方。",
|
||||||
showColumnTypesInHeader: "在字段名下方显示数据类型",
|
showColumnTypesInHeader: "在字段名下方显示数据类型",
|
||||||
|
|||||||
@@ -3166,6 +3166,8 @@ export default withEnglishFallback({
|
|||||||
debugLogsClear: "清空日誌",
|
debugLogsClear: "清空日誌",
|
||||||
tableStructureSection: "表結構",
|
tableStructureSection: "表結構",
|
||||||
dataGridDisplay: "資料表格顯示",
|
dataGridDisplay: "資料表格顯示",
|
||||||
|
tableOpenPageSize: "開啟資料表預設每頁列數",
|
||||||
|
tableOpenPageSizeDescription: "新開啟資料表時每頁載入的列數。在資料表頁面調整每頁列數後,也會更新後續新建資料表分頁的預設值。",
|
||||||
showColumnCommentsInHeader: "在欄位名稱下方顯示註解",
|
showColumnCommentsInHeader: "在欄位名稱下方顯示註解",
|
||||||
showColumnCommentsInHeaderDescription: "直接在資料表格欄位名稱下方顯示資料表欄位註解。",
|
showColumnCommentsInHeaderDescription: "直接在資料表格欄位名稱下方顯示資料表欄位註解。",
|
||||||
showColumnTypesInHeader: "在欄位名稱下方顯示資料類型",
|
showColumnTypesInHeader: "在欄位名稱下方顯示資料類型",
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import { EDITOR_SETTINGS_DRAFT_KEYS, editorSettingsDraftFromSettings, editorSettingsDraftChanged, editorSettingsPatchFromDraft } from "../editorSettingsDraft";
|
import { EDITOR_SETTINGS_DRAFT_KEYS, editorSettingsDraftFromSettings, editorSettingsDraftChanged, editorSettingsPatchFromDraft, normalizeTableOpenPageSizeDraft } from "../editorSettingsDraft";
|
||||||
import type { EditorSettings } from "@/stores/settingsStore";
|
import type { EditorSettings } from "@/stores/settingsStore";
|
||||||
|
|
||||||
function makeSettings(overrides: Partial<EditorSettings> = {}): EditorSettings {
|
function makeSettings(overrides: Partial<EditorSettings> = {}): EditorSettings {
|
||||||
return {
|
return {
|
||||||
autoCalculateTotalRows: false,
|
autoCalculateTotalRows: false,
|
||||||
pageSize: 100,
|
pageSize: 100,
|
||||||
|
tableOpenPageSize: 100,
|
||||||
sqlEngine: "desktop",
|
sqlEngine: "desktop",
|
||||||
tabSize: 2,
|
tabSize: 2,
|
||||||
keywordCase: "upper",
|
keywordCase: "upper",
|
||||||
@@ -31,6 +32,10 @@ describe("EDITOR_SETTINGS_DRAFT_KEYS", () => {
|
|||||||
it("includes continueOnErrorOnBatch", () => {
|
it("includes continueOnErrorOnBatch", () => {
|
||||||
expect(EDITOR_SETTINGS_DRAFT_KEYS).toContain("continueOnErrorOnBatch");
|
expect(EDITOR_SETTINGS_DRAFT_KEYS).toContain("continueOnErrorOnBatch");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("includes the table-open page size", () => {
|
||||||
|
expect(EDITOR_SETTINGS_DRAFT_KEYS).toContain("tableOpenPageSize");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("editorSettingsDraftFromSettings", () => {
|
describe("editorSettingsDraftFromSettings", () => {
|
||||||
@@ -43,6 +48,27 @@ describe("editorSettingsDraftFromSettings", () => {
|
|||||||
const draft = editorSettingsDraftFromSettings(makeSettings({ continueOnErrorOnBatch: false }));
|
const draft = editorSettingsDraftFromSettings(makeSettings({ continueOnErrorOnBatch: false }));
|
||||||
expect(draft.continueOnErrorOnBatch).toBe(false);
|
expect(draft.continueOnErrorOnBatch).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("preserves the table-open default for legacy settings", () => {
|
||||||
|
const settings = makeSettings();
|
||||||
|
delete (settings as Partial<EditorSettings>).tableOpenPageSize;
|
||||||
|
expect(editorSettingsDraftFromSettings(settings).tableOpenPageSize).toBe(100);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("normalizeTableOpenPageSizeDraft", () => {
|
||||||
|
it.each([
|
||||||
|
[200000, 100000],
|
||||||
|
[0, 100],
|
||||||
|
[-1, 100],
|
||||||
|
["123.9", 123],
|
||||||
|
[Number.NaN, 100],
|
||||||
|
[Number.POSITIVE_INFINITY, 100],
|
||||||
|
["not-a-number", 100],
|
||||||
|
[500, 500],
|
||||||
|
])("normalizes %s to %s", (value, expected) => {
|
||||||
|
expect(normalizeTableOpenPageSizeDraft(value)).toBe(expected);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("editorSettingsDraftChanged", () => {
|
describe("editorSettingsDraftChanged", () => {
|
||||||
@@ -60,6 +86,14 @@ describe("editorSettingsDraftChanged", () => {
|
|||||||
const base = editorSettingsDraftFromSettings(settings);
|
const base = editorSettingsDraftFromSettings(settings);
|
||||||
expect(editorSettingsDraftChanged(draft, base)).toBe(false);
|
expect(editorSettingsDraftChanged(draft, base)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("compares the normalized table-open page size", () => {
|
||||||
|
const settings = makeSettings({ tableOpenPageSize: 100 });
|
||||||
|
const draft = editorSettingsDraftFromSettings(settings);
|
||||||
|
const base = editorSettingsDraftFromSettings(settings);
|
||||||
|
draft.tableOpenPageSize = Number.NaN;
|
||||||
|
expect(editorSettingsDraftChanged(draft, base)).toBe(false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("editorSettingsPatchFromDraft", () => {
|
describe("editorSettingsPatchFromDraft", () => {
|
||||||
@@ -79,6 +113,14 @@ describe("editorSettingsPatchFromDraft", () => {
|
|||||||
const patch = editorSettingsPatchFromDraft(draft, base);
|
const patch = editorSettingsPatchFromDraft(draft, base);
|
||||||
expect(patch.continueOnErrorOnBatch).toBeUndefined();
|
expect(patch.continueOnErrorOnBatch).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("writes the normalized table-open page size", () => {
|
||||||
|
const settings = makeSettings({ tableOpenPageSize: 100 });
|
||||||
|
const draft = editorSettingsDraftFromSettings(settings);
|
||||||
|
const base = editorSettingsDraftFromSettings(settings);
|
||||||
|
draft.tableOpenPageSize = 200000.9;
|
||||||
|
expect(editorSettingsPatchFromDraft(draft, base).tableOpenPageSize).toBe(100000);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("EDITOR_SETTINGS_DRAFT_KEYS - tabLayout", () => {
|
describe("EDITOR_SETTINGS_DRAFT_KEYS - tabLayout", () => {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { EditorSettings } from "@/stores/settingsStore";
|
import type { EditorSettings } from "@/stores/settingsStore";
|
||||||
|
import { normalizeResultPageSize } from "@/lib/dataGrid/paginationPageSize";
|
||||||
|
|
||||||
export const EDITOR_SETTINGS_DRAFT_KEYS = [
|
export const EDITOR_SETTINGS_DRAFT_KEYS = [
|
||||||
"fontFamily",
|
"fontFamily",
|
||||||
@@ -26,6 +27,7 @@ export const EDITOR_SETTINGS_DRAFT_KEYS = [
|
|||||||
"showColumnTypesInHeader",
|
"showColumnTypesInHeader",
|
||||||
"compactColumnHeaderActions",
|
"compactColumnHeaderActions",
|
||||||
"dataGridQuickEntry",
|
"dataGridQuickEntry",
|
||||||
|
"tableOpenPageSize",
|
||||||
"infiniteScroll",
|
"infiniteScroll",
|
||||||
"infiniteScrollMaxRows",
|
"infiniteScrollMaxRows",
|
||||||
"autoCalculateTotalRows",
|
"autoCalculateTotalRows",
|
||||||
@@ -66,14 +68,24 @@ function cloneDraftValue<T>(value: T): T {
|
|||||||
return JSON.parse(JSON.stringify(value)) as T;
|
return JSON.parse(JSON.stringify(value)) as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
function draftValueChanged(a: unknown, b: unknown): boolean {
|
export function normalizeTableOpenPageSizeDraft(value: unknown): number {
|
||||||
return JSON.stringify(a) !== JSON.stringify(b);
|
// Match persistence so legacy, invalid, and fractional values cannot leave the dialog dirty after apply.
|
||||||
|
return normalizeResultPageSize(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizedDraftValue(key: EditorSettingsDraftKey, value: unknown): unknown {
|
||||||
|
if (key === "tableOpenPageSize") return normalizeTableOpenPageSizeDraft(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function draftValueChanged(key: EditorSettingsDraftKey, a: unknown, b: unknown): boolean {
|
||||||
|
return JSON.stringify(normalizedDraftValue(key, a)) !== JSON.stringify(normalizedDraftValue(key, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function editorSettingsDraftFromSettings(settings: EditorSettings): EditorSettingsDraft {
|
export function editorSettingsDraftFromSettings(settings: EditorSettings): EditorSettingsDraft {
|
||||||
const draft = {} as EditorSettingsDraft;
|
const draft = {} as EditorSettingsDraft;
|
||||||
for (const key of EDITOR_SETTINGS_DRAFT_KEYS) {
|
for (const key of EDITOR_SETTINGS_DRAFT_KEYS) {
|
||||||
draft[key] = cloneDraftValue(settings[key]) as never;
|
draft[key] = cloneDraftValue(normalizedDraftValue(key, settings[key])) as never;
|
||||||
}
|
}
|
||||||
return draft;
|
return draft;
|
||||||
}
|
}
|
||||||
@@ -81,13 +93,13 @@ export function editorSettingsDraftFromSettings(settings: EditorSettings): Edito
|
|||||||
export function editorSettingsPatchFromDraft(draft: EditorSettingsDraft, base: EditorSettingsDraft): Partial<EditorSettings> {
|
export function editorSettingsPatchFromDraft(draft: EditorSettingsDraft, base: EditorSettingsDraft): Partial<EditorSettings> {
|
||||||
const patch: Partial<EditorSettings> = {};
|
const patch: Partial<EditorSettings> = {};
|
||||||
for (const key of EDITOR_SETTINGS_DRAFT_KEYS) {
|
for (const key of EDITOR_SETTINGS_DRAFT_KEYS) {
|
||||||
if (draftValueChanged(draft[key], base[key])) {
|
if (draftValueChanged(key, draft[key], base[key])) {
|
||||||
patch[key] = cloneDraftValue(draft[key]) as never;
|
patch[key] = cloneDraftValue(normalizedDraftValue(key, draft[key])) as never;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return patch;
|
return patch;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function editorSettingsDraftChanged(draft: EditorSettingsDraft, base: EditorSettingsDraft): boolean {
|
export function editorSettingsDraftChanged(draft: EditorSettingsDraft, base: EditorSettingsDraft): boolean {
|
||||||
return EDITOR_SETTINGS_DRAFT_KEYS.some((key) => draftValueChanged(draft[key], base[key]));
|
return EDITOR_SETTINGS_DRAFT_KEYS.some((key) => draftValueChanged(key, draft[key], base[key]));
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,6 @@ import { DEFAULT_RESULT_PAGE_SIZE, normalizeResultPageSize } from "@/lib/dataGri
|
|||||||
|
|
||||||
export const DEFAULT_TABLE_OPEN_PAGE_LIMIT = DEFAULT_RESULT_PAGE_SIZE;
|
export const DEFAULT_TABLE_OPEN_PAGE_LIMIT = DEFAULT_RESULT_PAGE_SIZE;
|
||||||
|
|
||||||
export function tableOpenPageLimit(): number {
|
export function tableOpenPageLimit(preferredLimit?: unknown): number {
|
||||||
// Opening a table should not inherit the mutable SQL result-grid rows-per-page setting.
|
return normalizeResultPageSize(preferredLimit, DEFAULT_TABLE_OPEN_PAGE_LIMIT);
|
||||||
return normalizeResultPageSize(DEFAULT_TABLE_OPEN_PAGE_LIMIT);
|
|
||||||
}
|
}
|
||||||
@@ -1878,7 +1878,7 @@ export const useQueryStore = defineStore("query", () => {
|
|||||||
const primaryKeys = tab.tableMeta ? tab.tableMeta.primaryKeys : tableMeta.primaryKeys;
|
const primaryKeys = tab.tableMeta ? tab.tableMeta.primaryKeys : tableMeta.primaryKeys;
|
||||||
const sortOrder = tab.resultSortColumn && tab.resultSortDirection ? `${quoteTableDataIdentifier(effectiveDbType, tab.resultSortColumn, identifierQuote)} ${tab.resultSortDirection.toUpperCase()}` : undefined;
|
const sortOrder = tab.resultSortColumn && tab.resultSortDirection ? `${quoteTableDataIdentifier(effectiveDbType, tab.resultSortColumn, identifierQuote)} ${tab.resultSortDirection.toUpperCase()}` : undefined;
|
||||||
const orderBy = tab.orderByInput?.trim() || sortOrder;
|
const orderBy = tab.orderByInput?.trim() || sortOrder;
|
||||||
const limit = tab.resultPageLimit ?? tableOpenPageLimit();
|
const limit = tab.resultPageLimit ?? tableOpenPageLimit(settingsStore.editorSettings.tableOpenPageSize);
|
||||||
const offset = tab.resultPageOffset ?? 0;
|
const offset = tab.resultPageOffset ?? 0;
|
||||||
const refreshPreparationId = uuid();
|
const refreshPreparationId = uuid();
|
||||||
|
|
||||||
@@ -3307,7 +3307,7 @@ export const useQueryStore = defineStore("query", () => {
|
|||||||
countSql = plan.countSql;
|
countSql = plan.countSql;
|
||||||
useAgentResultSession = plan.useAgentResultSession;
|
useAgentResultSession = plan.useAgentResultSession;
|
||||||
} else if (tab.mode === "data") {
|
} else if (tab.mode === "data") {
|
||||||
pageLimit = options?.pagination?.limit ?? tableOpenPageLimit();
|
pageLimit = options?.pagination?.limit ?? tableOpenPageLimit(settingsStore.editorSettings.tableOpenPageSize);
|
||||||
pageOffset = options?.pagination?.offset ?? 0;
|
pageOffset = options?.pagination?.offset ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4126,7 +4126,7 @@ export const useQueryStore = defineStore("query", () => {
|
|||||||
pagination:
|
pagination:
|
||||||
tab.mode === "data"
|
tab.mode === "data"
|
||||||
? {
|
? {
|
||||||
limit: tab.resultPageLimit ?? tableOpenPageLimit(),
|
limit: tab.resultPageLimit ?? tableOpenPageLimit(settingsStore.editorSettings.tableOpenPageSize),
|
||||||
offset: tab.resultPageOffset ?? 0,
|
offset: tab.resultPageOffset ?? 0,
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
|
|||||||
@@ -377,6 +377,7 @@ export interface EditorSettings {
|
|||||||
tabLayout: TabLayoutMode;
|
tabLayout: TabLayoutMode;
|
||||||
appLayout: "separated" | "classic";
|
appLayout: "separated" | "classic";
|
||||||
pageSize: number;
|
pageSize: number;
|
||||||
|
tableOpenPageSize: number;
|
||||||
infiniteScroll: boolean;
|
infiniteScroll: boolean;
|
||||||
infiniteScrollMaxRows: number;
|
infiniteScrollMaxRows: number;
|
||||||
autoCalculateTotalRows: boolean;
|
autoCalculateTotalRows: boolean;
|
||||||
@@ -521,6 +522,7 @@ export const DEFAULT_EDITOR_SETTINGS: EditorSettings = {
|
|||||||
tabLayout: "scroll",
|
tabLayout: "scroll",
|
||||||
appLayout: "classic",
|
appLayout: "classic",
|
||||||
pageSize: 100,
|
pageSize: 100,
|
||||||
|
tableOpenPageSize: 100,
|
||||||
infiniteScroll: false,
|
infiniteScroll: false,
|
||||||
infiniteScrollMaxRows: 5000,
|
infiniteScrollMaxRows: 5000,
|
||||||
autoCalculateTotalRows: false,
|
autoCalculateTotalRows: false,
|
||||||
@@ -770,6 +772,7 @@ export function normalizeEditorSettings(settings: Partial<EditorSettings>, exist
|
|||||||
tabLayout: normalizeTabLayout(settings.tabLayout),
|
tabLayout: normalizeTabLayout(settings.tabLayout),
|
||||||
appLayout: settings.appLayout ?? DEFAULT_EDITOR_SETTINGS.appLayout,
|
appLayout: settings.appLayout ?? DEFAULT_EDITOR_SETTINGS.appLayout,
|
||||||
pageSize: normalizeResultPageSize(settings.pageSize),
|
pageSize: normalizeResultPageSize(settings.pageSize),
|
||||||
|
tableOpenPageSize: normalizeResultPageSize(settings.tableOpenPageSize, DEFAULT_EDITOR_SETTINGS.tableOpenPageSize),
|
||||||
infiniteScroll: settings.infiniteScroll ?? DEFAULT_EDITOR_SETTINGS.infiniteScroll,
|
infiniteScroll: settings.infiniteScroll ?? DEFAULT_EDITOR_SETTINGS.infiniteScroll,
|
||||||
infiniteScrollMaxRows: typeof settings.infiniteScrollMaxRows === "number" && settings.infiniteScrollMaxRows >= 1000 && settings.infiniteScrollMaxRows <= 50000 ? Math.round(settings.infiniteScrollMaxRows) : DEFAULT_EDITOR_SETTINGS.infiniteScrollMaxRows,
|
infiniteScrollMaxRows: typeof settings.infiniteScrollMaxRows === "number" && settings.infiniteScrollMaxRows >= 1000 && settings.infiniteScrollMaxRows <= 50000 ? Math.round(settings.infiniteScrollMaxRows) : DEFAULT_EDITOR_SETTINGS.infiniteScrollMaxRows,
|
||||||
autoCalculateTotalRows: settings.autoCalculateTotalRows ?? DEFAULT_EDITOR_SETTINGS.autoCalculateTotalRows,
|
autoCalculateTotalRows: settings.autoCalculateTotalRows ?? DEFAULT_EDITOR_SETTINGS.autoCalculateTotalRows,
|
||||||
@@ -1095,6 +1098,7 @@ export const useSettingsStore = defineStore("settings", () => {
|
|||||||
if (partial.tabLayout !== undefined) editorSettings.value.tabLayout = normalizeTabLayout(partial.tabLayout);
|
if (partial.tabLayout !== undefined) editorSettings.value.tabLayout = normalizeTabLayout(partial.tabLayout);
|
||||||
if (partial.appLayout !== undefined) editorSettings.value.appLayout = partial.appLayout;
|
if (partial.appLayout !== undefined) editorSettings.value.appLayout = partial.appLayout;
|
||||||
if (partial.pageSize !== undefined) editorSettings.value.pageSize = normalizeResultPageSize(partial.pageSize);
|
if (partial.pageSize !== undefined) editorSettings.value.pageSize = normalizeResultPageSize(partial.pageSize);
|
||||||
|
if (partial.tableOpenPageSize !== undefined) editorSettings.value.tableOpenPageSize = normalizeResultPageSize(partial.tableOpenPageSize, DEFAULT_EDITOR_SETTINGS.tableOpenPageSize);
|
||||||
if (partial.infiniteScroll !== undefined) editorSettings.value.infiniteScroll = partial.infiniteScroll;
|
if (partial.infiniteScroll !== undefined) editorSettings.value.infiniteScroll = partial.infiniteScroll;
|
||||||
if (partial.infiniteScrollMaxRows !== undefined)
|
if (partial.infiniteScrollMaxRows !== undefined)
|
||||||
editorSettings.value.infiniteScrollMaxRows = typeof partial.infiniteScrollMaxRows === "number" && partial.infiniteScrollMaxRows >= 1000 && partial.infiniteScrollMaxRows <= 50000 ? Math.round(partial.infiniteScrollMaxRows) : DEFAULT_EDITOR_SETTINGS.infiniteScrollMaxRows;
|
editorSettings.value.infiniteScrollMaxRows = typeof partial.infiniteScrollMaxRows === "number" && partial.infiniteScrollMaxRows >= 1000 && partial.infiniteScrollMaxRows <= 50000 ? Math.round(partial.infiniteScrollMaxRows) : DEFAULT_EDITOR_SETTINGS.infiniteScrollMaxRows;
|
||||||
|
|||||||
+2
-1
@@ -74,8 +74,9 @@ test("DataGrid exposes persistent result toolbar slots", () => {
|
|||||||
test("table-data toolbar refresh keeps page size independent from SQL editor settings", () => {
|
test("table-data toolbar refresh keeps page size independent from SQL editor settings", () => {
|
||||||
const dataGrid = source(dataGridPath);
|
const dataGrid = source(dataGridPath);
|
||||||
|
|
||||||
assert.match(dataGrid, /props\.context === "table-data" \? \(props\.pageLimit \?\? tableOpenPageLimit\(\)\) : settingsStore\.editorSettings\.pageSize/);
|
assert.match(dataGrid, /props\.context === "table-data" \? \(props\.pageLimit \?\? tableOpenPageLimit\(settingsStore\.editorSettings\.tableOpenPageSize\)\) : settingsStore\.editorSettings\.pageSize/);
|
||||||
assert.match(dataGrid, /if \(props\.context === "table-data"\) return;[\s\S]*pageSize\.value = normalizeResultPageSize\(value, pageSize\.value\)/);
|
assert.match(dataGrid, /if \(props\.context === "table-data"\) return;[\s\S]*pageSize\.value = normalizeResultPageSize\(value, pageSize\.value\)/);
|
||||||
|
assert.match(dataGrid, /props\.context === "table-data" \? \{ tableOpenPageSize: normalizedSize \} : \{ pageSize: normalizedSize \}/);
|
||||||
assert.match(dataGrid, /emit\("reload", props\.sql, searchText\.value, currentWhereInput\(\), currentOrderBy\(\), pageSize\.value, \(currentPage\.value - 1\) \* pageSize\.value, "refresh"\)/);
|
assert.match(dataGrid, /emit\("reload", props\.sql, searchText\.value, currentWhereInput\(\), currentOrderBy\(\), pageSize\.value, \(currentPage\.value - 1\) \* pageSize\.value, "refresh"\)/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -2584,7 +2584,7 @@ test("data tab execution preserves pagination offset metadata", async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test("data tab default pagination is independent from query result page size", async () => {
|
test("data tab default pagination uses the dedicated table-open page size", async () => {
|
||||||
const restoreStorage = installMemoryStorage();
|
const restoreStorage = installMemoryStorage();
|
||||||
setActivePinia(createPinia());
|
setActivePinia(createPinia());
|
||||||
const connectionStore = useConnectionStore();
|
const connectionStore = useConnectionStore();
|
||||||
@@ -2594,7 +2594,7 @@ test("data tab default pagination is independent from query result page size", a
|
|||||||
let executeBody: any;
|
let executeBody: any;
|
||||||
let preparedPagination = false;
|
let preparedPagination = false;
|
||||||
|
|
||||||
settingsStore.updateEditorSettings({ pageSize: 1000 });
|
settingsStore.updateEditorSettings({ pageSize: 1000, tableOpenPageSize: 500 });
|
||||||
connectionStore.addEphemeralConnection(conn("conn-1"));
|
connectionStore.addEphemeralConnection(conn("conn-1"));
|
||||||
const tabId = store.createTab("conn-1", "db", "users", "data", "public");
|
const tabId = store.createTab("conn-1", "db", "users", "data", "public");
|
||||||
const tab = store.tabs.find((item) => item.id === tabId);
|
const tab = store.tabs.find((item) => item.id === tabId);
|
||||||
@@ -2617,12 +2617,12 @@ test("data tab default pagination is independent from query result page size", a
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await store.executeTabSql(tabId, 'SELECT * FROM "users" LIMIT 100;');
|
await store.executeTabSql(tabId, 'SELECT * FROM "users" LIMIT 500;');
|
||||||
|
|
||||||
assert.equal(preparedPagination, false);
|
assert.equal(preparedPagination, false);
|
||||||
assert.equal(executeBody.maxRows, 100);
|
assert.equal(executeBody.maxRows, 500);
|
||||||
assert.equal(executeBody.fetchSize, 100);
|
assert.equal(executeBody.fetchSize, 500);
|
||||||
assert.equal(tab.resultPageLimit, 100);
|
assert.equal(tab.resultPageLimit, 500);
|
||||||
assert.equal(tab.resultPageOffset, 0);
|
assert.equal(tab.resultPageOffset, 0);
|
||||||
} finally {
|
} finally {
|
||||||
globalThis.fetch = originalFetch;
|
globalThis.fetch = originalFetch;
|
||||||
|
|||||||
+19
-1
@@ -1,5 +1,6 @@
|
|||||||
import { test } from "vitest";
|
import { test } from "vitest";
|
||||||
import assert from "node:assert/strict";
|
import assert from "node:assert/strict";
|
||||||
|
import { readFileSync } from "node:fs";
|
||||||
import { createPinia, setActivePinia } from "pinia";
|
import { createPinia, setActivePinia } from "pinia";
|
||||||
import { DEFAULT_SQL_FORMATTER_SETTINGS } from "../../apps/desktop/src/lib/sql/sqlFormatterConfig.ts";
|
import { DEFAULT_SQL_FORMATTER_SETTINGS } from "../../apps/desktop/src/lib/sql/sqlFormatterConfig.ts";
|
||||||
import { DEFAULT_TABLE_COLUMN_TEMPLATE_FIELDS } from "../../apps/desktop/src/lib/table/tableColumnTemplates.ts";
|
import { DEFAULT_TABLE_COLUMN_TEMPLATE_FIELDS } from "../../apps/desktop/src/lib/table/tableColumnTemplates.ts";
|
||||||
@@ -48,8 +49,25 @@ test("normalizes saved query result page size", () => {
|
|||||||
assert.equal(normalizeEditorSettings({ pageSize: 0 }).pageSize, 100);
|
assert.equal(normalizeEditorSettings({ pageSize: 0 }).pageSize, 100);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("uses dedicated default row limit for table opens", () => {
|
test("normalizes the dedicated default row limit for table opens", () => {
|
||||||
|
assert.equal(DEFAULT_EDITOR_SETTINGS.tableOpenPageSize, 100);
|
||||||
|
assert.equal(normalizeEditorSettings({ tableOpenPageSize: 1000 }).tableOpenPageSize, 1000);
|
||||||
|
assert.equal(normalizeEditorSettings({ tableOpenPageSize: 200000 }).tableOpenPageSize, 100000);
|
||||||
|
assert.equal(normalizeEditorSettings({ tableOpenPageSize: 0 }).tableOpenPageSize, 100);
|
||||||
assert.equal(tableOpenPageLimit(), 100);
|
assert.equal(tableOpenPageLimit(), 100);
|
||||||
|
assert.equal(tableOpenPageLimit(1000), 1000);
|
||||||
|
assert.equal(tableOpenPageLimit(0), 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("shows the table-open page size control in the Data settings tab", () => {
|
||||||
|
const source = readFileSync("apps/desktop/src/components/editor/EditorSettingsDialog.vue", "utf8");
|
||||||
|
const dataSectionStart = source.indexOf("activeSettingsTab === 'data'");
|
||||||
|
const nextSectionStart = source.indexOf("activeSettingsTab === 'shortcuts'", dataSectionStart);
|
||||||
|
const control = source.indexOf('id="table-open-page-size"');
|
||||||
|
|
||||||
|
assert.ok(dataSectionStart >= 0);
|
||||||
|
assert.ok(nextSectionStart > dataSectionStart);
|
||||||
|
assert.ok(control > dataSectionStart && control < nextSectionStart);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("defaults export batch size to 2000 rows", () => {
|
test("defaults export batch size to 2000 rows", () => {
|
||||||
|
|||||||
Reference in new issue
Block a user