feat(settings): configure SQL file size limits
This commit is contained in:
34 files changed
+554
-79
No files matched your search
@@ -66,7 +66,7 @@ import { isMacOS, isWindows } from "@/lib/backend/platform";
|
||||
import { isTauriRuntime } from "@/lib/backend/tauriRuntime";
|
||||
import { openQueryResultArchiveFile } from "@/lib/query/queryResultArchiveFile";
|
||||
import { rememberExternalSqlFileTarget, resolveExternalSqlFileTarget, unassociatedExternalSqlFileTarget } from "@/lib/sql/externalSqlFileTarget";
|
||||
import { externalSqlFileOpenErrorMessage, isSqlFilePath, readBrowserSqlFile, sqlFileTitleFromPath } from "@/lib/sql/sqlFileOpen";
|
||||
import { externalSqlFileOpenErrorMessage, externalSqlEditorMaxBytes, isSqlFilePath, readBrowserSqlFile, sqlFileTitleFromPath } from "@/lib/sql/sqlFileOpen";
|
||||
import type { ConnectionConfig, DatabaseType, ObjectSourceKind, QueryTab, TreeNode } from "@/types/database";
|
||||
import { parseConnectionDeepLink, type ConnectionDeepLinkDraft } from "@/lib/connection/connectionDeepLink";
|
||||
import { parseAiConfigDeepLink, type AiConfigDeepLinkDraft } from "@/lib/ai/aiConfigDeepLink";
|
||||
@@ -2001,7 +2001,7 @@ async function openSqlFile() {
|
||||
if (path) {
|
||||
const sqlPath = path as string;
|
||||
openedSqlPath = sqlPath;
|
||||
const snapshot = await api.readExternalSqlFileSnapshot(sqlPath);
|
||||
const snapshot = await api.readExternalSqlFileSnapshot(sqlPath, externalSqlEditorMaxBytes(settingsStore.editorSettings.externalSqlEditorMaxMb));
|
||||
queryStore.updateSql(tab.id, snapshot.content);
|
||||
queryStore.linkExternalSqlPath(tab.id, sqlPath, sqlFileTitleFromPath(sqlPath), snapshot.version);
|
||||
applyExternalSqlFileTarget(tab, sqlPath);
|
||||
@@ -2014,7 +2014,7 @@ async function openSqlFile() {
|
||||
const file = input.files?.[0];
|
||||
if (!file) return;
|
||||
try {
|
||||
queryStore.updateSql(tab.id, await readBrowserSqlFile(file));
|
||||
queryStore.updateSql(tab.id, await readBrowserSqlFile(file, externalSqlEditorMaxBytes(settingsStore.editorSettings.externalSqlEditorMaxMb)));
|
||||
} catch (e: any) {
|
||||
toast(t("toolbar.sqlOpenFailed", { message: externalSqlFileOpenErrorMessage(e, (key, params) => t(key, params)) }), 5000);
|
||||
}
|
||||
@@ -2057,7 +2057,7 @@ async function openSqlFilePath(path: string) {
|
||||
if (!isTauriRuntime()) return;
|
||||
try {
|
||||
await desktopOpenTabsRestorationBarrier?.settled;
|
||||
const snapshot = await api.readExternalSqlFileSnapshot(path);
|
||||
const snapshot = await api.readExternalSqlFileSnapshot(path, externalSqlEditorMaxBytes(settingsStore.editorSettings.externalSqlEditorMaxMb));
|
||||
const target = resolveExternalSqlFileTarget(path, (savedConnectionId) => !!connectionStore.getConfig(savedConnectionId), unassociatedExternalSqlFileTarget());
|
||||
queryStore.openExternalSqlFile(target.connectionId, target.database, path, snapshot.content, snapshot.version, target.catalog, target.schema);
|
||||
} catch (e: any) {
|
||||
@@ -2703,7 +2703,7 @@ async function handleQuickOpenSelect(item: any) {
|
||||
// Handle SQL file types first — they don't require a database connection
|
||||
if (item.type === "sql_file" && item.filePath) {
|
||||
try {
|
||||
const snapshot = await api.readExternalSqlFileSnapshot(item.filePath);
|
||||
const snapshot = await api.readExternalSqlFileSnapshot(item.filePath, externalSqlEditorMaxBytes(settingsStore.editorSettings.externalSqlEditorMaxMb));
|
||||
const target = resolveExternalSqlFileTarget(item.filePath, (savedConnectionId) => !!connectionStore.getConfig(savedConnectionId), unassociatedExternalSqlFileTarget());
|
||||
queryStore.openExternalSqlFile(target.connectionId, target.database, item.filePath, snapshot.content, snapshot.version, target.catalog, target.schema);
|
||||
} catch (e: any) {
|
||||
|
||||
@@ -138,6 +138,8 @@ import {
|
||||
saveMaxAgentTurns,
|
||||
loadMaxRetries,
|
||||
saveMaxRetries,
|
||||
loadSqlFileUploadMaxBytes,
|
||||
saveSqlFileUploadMaxMb,
|
||||
saveWebdavSyncSecretsPreference,
|
||||
saveWebdavSavedPassword,
|
||||
saveSnippetSavedToken,
|
||||
@@ -226,6 +228,7 @@ import { useUiFontFamilyPreview } from "@/composables/useUiFontFamilyPreview";
|
||||
import { DateTimePatterns, normalizeSupportedDateTimePattern } from "@/lib/dataGrid/columnFormatter";
|
||||
import { MAX_RESULT_PAGE_SIZE, MIN_RESULT_PAGE_SIZE } from "@/lib/dataGrid/paginationPageSize";
|
||||
import { MAX_QUERY_RESULT_MAX_ROWS } from "@/lib/dataGrid/queryResultRowLimit";
|
||||
import { MAX_EXTERNAL_SQL_EDITOR_FILE_MB, MIN_EXTERNAL_SQL_EDITOR_FILE_MB, clampExternalSqlEditorMaxMbInput } from "@/lib/sql/sqlFileOpen";
|
||||
import type { PromptTemplate } from "@/types/promptTemplate";
|
||||
import { GLOBAL_INSTRUCTIONS_MAX, PROMPT_TEMPLATE_CONTENT_MAX, PROMPT_TEMPLATE_NAME_MAX, promptTemplateCharacterCount } from "@/types/promptTemplate";
|
||||
import { METADATA_CACHE_HARD_MAX_MEMORY_MB, METADATA_CACHE_MIN_MEMORY_MB, normalizeMetadataCacheMemoryMb } from "@/lib/metadata/metadataRuntimeCache";
|
||||
@@ -512,6 +515,7 @@ const editPageSize = ref(settingsStore.editorSettings.pageSize);
|
||||
const editTableOpenPageSize = ref(settingsStore.editorSettings.tableOpenPageSize);
|
||||
const editQueryResultMaxRowsEnabled = ref(settingsStore.editorSettings.queryResultMaxRowsEnabled);
|
||||
const editQueryResultMaxRows = ref(settingsStore.editorSettings.queryResultMaxRows);
|
||||
const editExternalSqlEditorMaxMb = ref(settingsStore.editorSettings.externalSqlEditorMaxMb);
|
||||
const editInfiniteScroll = ref(settingsStore.editorSettings.infiniteScroll);
|
||||
const editRegexMaxMatchCount = ref(settingsStore.editorSettings.regexMaxMatchCount);
|
||||
const editAutoCalculateTotalRows = ref(settingsStore.editorSettings.autoCalculateTotalRows);
|
||||
@@ -542,6 +546,18 @@ function updateQueryResultMaxRowsInput(event: Event) {
|
||||
editQueryResultMaxRows.value = normalized;
|
||||
}
|
||||
|
||||
function updateExternalSqlEditorMaxMbInput(event: Event) {
|
||||
const input = event.currentTarget as HTMLInputElement;
|
||||
const parsed = Number(input.value);
|
||||
if (!Number.isFinite(parsed) || parsed > MAX_EXTERNAL_SQL_EDITOR_FILE_MB) {
|
||||
input.value = String(editExternalSqlEditorMaxMb.value);
|
||||
return;
|
||||
}
|
||||
const normalized = clampExternalSqlEditorMaxMbInput(input.value);
|
||||
if (input.value !== String(normalized)) input.value = String(normalized);
|
||||
editExternalSqlEditorMaxMb.value = normalized;
|
||||
}
|
||||
|
||||
function sqlVariableSyntaxToggle(key: keyof SqlVariableSyntaxToggles): boolean {
|
||||
return editSqlVariableSyntaxOverrides.value[editSqlVariableSyntaxDatabaseType.value]?.[key] ?? true;
|
||||
}
|
||||
@@ -725,6 +741,7 @@ function currentEditorSettingsDraft(): EditorSettingsDraft {
|
||||
tableOpenPageSize: editTableOpenPageSize.value,
|
||||
queryResultMaxRowsEnabled: editQueryResultMaxRowsEnabled.value,
|
||||
queryResultMaxRows: editQueryResultMaxRows.value,
|
||||
externalSqlEditorMaxMb: editExternalSqlEditorMaxMb.value,
|
||||
infiniteScroll: editInfiniteScroll.value,
|
||||
regexMaxMatchCount: editRegexMaxMatchCount.value,
|
||||
autoCalculateTotalRows: editAutoCalculateTotalRows.value,
|
||||
@@ -1221,6 +1238,7 @@ function syncEditorSettingsDraftFromStore() {
|
||||
editTableOpenPageSize.value = settingsStore.editorSettings.tableOpenPageSize;
|
||||
editQueryResultMaxRowsEnabled.value = settingsStore.editorSettings.queryResultMaxRowsEnabled;
|
||||
editQueryResultMaxRows.value = settingsStore.editorSettings.queryResultMaxRows;
|
||||
editExternalSqlEditorMaxMb.value = settingsStore.editorSettings.externalSqlEditorMaxMb;
|
||||
editInfiniteScroll.value = settingsStore.editorSettings.infiniteScroll;
|
||||
editRegexMaxMatchCount.value = settingsStore.editorSettings.regexMaxMatchCount;
|
||||
editAutoCalculateTotalRows.value = settingsStore.editorSettings.autoCalculateTotalRows;
|
||||
@@ -1441,6 +1459,9 @@ function applyEditorSettingsKeysToRefs(draft: EditorSettingsDraft, keys: readonl
|
||||
case "queryResultMaxRows":
|
||||
editQueryResultMaxRows.value = draft.queryResultMaxRows;
|
||||
break;
|
||||
case "externalSqlEditorMaxMb":
|
||||
editExternalSqlEditorMaxMb.value = draft.externalSqlEditorMaxMb;
|
||||
break;
|
||||
case "infiniteScroll":
|
||||
editInfiniteScroll.value = draft.infiniteScroll;
|
||||
break;
|
||||
@@ -1900,6 +1921,7 @@ function resetDefaultsForTab(tab: SettingsCategory) {
|
||||
editTableOpenPageSize.value = DEFAULT_EDITOR_SETTINGS.tableOpenPageSize;
|
||||
editQueryResultMaxRowsEnabled.value = DEFAULT_EDITOR_SETTINGS.queryResultMaxRowsEnabled;
|
||||
editQueryResultMaxRows.value = DEFAULT_EDITOR_SETTINGS.queryResultMaxRows;
|
||||
editExternalSqlEditorMaxMb.value = DEFAULT_EDITOR_SETTINGS.externalSqlEditorMaxMb;
|
||||
editInfiniteScroll.value = DEFAULT_EDITOR_SETTINGS.infiniteScroll;
|
||||
editRegexMaxMatchCount.value = DEFAULT_EDITOR_SETTINGS.regexMaxMatchCount;
|
||||
editAutoCalculateTotalRows.value = DEFAULT_EDITOR_SETTINGS.autoCalculateTotalRows;
|
||||
@@ -1987,6 +2009,7 @@ function resetAllDefaults() {
|
||||
editTableOpenPageSize.value = DEFAULT_EDITOR_SETTINGS.tableOpenPageSize;
|
||||
editQueryResultMaxRowsEnabled.value = DEFAULT_EDITOR_SETTINGS.queryResultMaxRowsEnabled;
|
||||
editQueryResultMaxRows.value = DEFAULT_EDITOR_SETTINGS.queryResultMaxRows;
|
||||
editExternalSqlEditorMaxMb.value = DEFAULT_EDITOR_SETTINGS.externalSqlEditorMaxMb;
|
||||
editInfiniteScroll.value = DEFAULT_EDITOR_SETTINGS.infiniteScroll;
|
||||
editRegexMaxMatchCount.value = DEFAULT_EDITOR_SETTINGS.regexMaxMatchCount;
|
||||
editAutoCalculateTotalRows.value = DEFAULT_EDITOR_SETTINGS.autoCalculateTotalRows;
|
||||
@@ -2368,6 +2391,7 @@ const settingsCategoryNav = computed<{ value: SettingsCategory; label: string }[
|
||||
{ value: "formatter", label: t("settings.sqlFormatterTab") },
|
||||
{ value: "navigation", label: t("settings.navigationTab") },
|
||||
{ value: "data", label: t("settings.dataTab") },
|
||||
{ value: "sqlFile", label: t("settings.sqlFileSizeTab") },
|
||||
...(isWeb ? [] : [{ value: "backups" as const, label: t("databaseBackup.title") }]),
|
||||
{ value: "tunnels", label: t("settings.tunnelsTab") },
|
||||
{ value: "shortcuts", label: t("settings.shortcutsTab") },
|
||||
@@ -2378,7 +2402,7 @@ const settingsCategoryNav = computed<{ value: SettingsCategory; label: string }[
|
||||
...(isWeb ? [{ value: "security" as const, label: t("settings.securityTab") }] : []),
|
||||
{ value: "about", label: t("settings.aboutTab") },
|
||||
]);
|
||||
const settingsTabsWithApplyFooter = new Set<SettingsCategory>(["editor", "formatter", "appearance", "navigation", "data", "shortcuts", "snippets"]);
|
||||
const settingsTabsWithApplyFooter = new Set<SettingsCategory>(["editor", "formatter", "appearance", "navigation", "data", "sqlFile", "shortcuts", "snippets"]);
|
||||
|
||||
function hasSettingsApplyFooter(value: SettingsCategory): boolean {
|
||||
return settingsTabsWithApplyFooter.has(value);
|
||||
@@ -3826,6 +3850,7 @@ watch(activeSettingsTab, async (tab) => {
|
||||
await promptTemplateStore.ensureLoaded();
|
||||
editGlobalInstructions.value = promptTemplateStore.globalInstructions;
|
||||
}
|
||||
if (tab === "sqlFile" && isWeb) void loadWebSqlFileUploadMaxMbSetting();
|
||||
if (tab === "about" && !appSupportInfo.value) void refreshAppSupportInfo();
|
||||
if (tab === "appearance") {
|
||||
checkLayoutDescTruncation();
|
||||
@@ -4133,6 +4158,52 @@ function normalizeMaxRetries(value: number | undefined): number {
|
||||
return Math.min(10, Math.max(0, rounded));
|
||||
}
|
||||
|
||||
const editWebSqlFileUploadMaxMb = ref<number | undefined>(undefined);
|
||||
const webSqlFileUploadMaxMbSaving = ref(false);
|
||||
const webSqlFileUploadMaxMbLoaded = ref(false);
|
||||
const webSqlFileUploadMaxMbLoading = ref(false);
|
||||
const webSqlFileUploadMaxMbLoadError = ref("");
|
||||
|
||||
async function loadWebSqlFileUploadMaxMbSetting() {
|
||||
if (webSqlFileUploadMaxMbLoaded.value || webSqlFileUploadMaxMbLoading.value) return;
|
||||
webSqlFileUploadMaxMbLoading.value = true;
|
||||
webSqlFileUploadMaxMbLoadError.value = "";
|
||||
try {
|
||||
const bytes = await loadSqlFileUploadMaxBytes();
|
||||
editWebSqlFileUploadMaxMb.value = Math.round(bytes / (1024 * 1024));
|
||||
webSqlFileUploadMaxMbLoaded.value = true;
|
||||
} catch (e: any) {
|
||||
webSqlFileUploadMaxMbLoadError.value = e?.message || String(e);
|
||||
toast(webSqlFileUploadMaxMbLoadError.value, 5000);
|
||||
} finally {
|
||||
webSqlFileUploadMaxMbLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeWebSqlFileUploadMaxMb(value: number | undefined): number {
|
||||
const rounded = typeof value === "number" && Number.isFinite(value) ? Math.round(value) : 200;
|
||||
return Math.min(MAX_EXTERNAL_SQL_EDITOR_FILE_MB, Math.max(MIN_EXTERNAL_SQL_EDITOR_FILE_MB, rounded));
|
||||
}
|
||||
|
||||
function webSqlFileUploadMaxMbOutOfRange(value: number | undefined): boolean {
|
||||
return typeof value === "number" && (value < MIN_EXTERNAL_SQL_EDITOR_FILE_MB || value > MAX_EXTERNAL_SQL_EDITOR_FILE_MB);
|
||||
}
|
||||
|
||||
async function saveWebSqlFileUploadMaxMbSetting() {
|
||||
if (!webSqlFileUploadMaxMbLoaded.value) return;
|
||||
const clamped = normalizeWebSqlFileUploadMaxMb(editWebSqlFileUploadMaxMb.value);
|
||||
webSqlFileUploadMaxMbSaving.value = true;
|
||||
try {
|
||||
await saveSqlFileUploadMaxMb(clamped);
|
||||
editWebSqlFileUploadMaxMb.value = clamped;
|
||||
toast(t("settings.sqlFileUploadMaxMbSaved"));
|
||||
} catch (e: any) {
|
||||
toast(e?.message || String(e), 5000);
|
||||
} finally {
|
||||
webSqlFileUploadMaxMbSaving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// AI Config Delete Confirmation
|
||||
const aiDeleteConfirmOpen = ref(false);
|
||||
const aiDeleteConfigId = ref<string | null>(null);
|
||||
@@ -7427,6 +7498,55 @@ onUnmounted(() => {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section v-else-if="activeSettingsTab === 'sqlFile'" data-settings-search-id="sqlFile" :class="['flex flex-col gap-5 py-2', settingsSearchTargetClass('sqlFile')]">
|
||||
<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="external-sql-editor-max-mb">
|
||||
{{ t("settings.externalSqlEditorMaxMb") }}
|
||||
</Label>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
{{ t("settings.externalSqlEditorMaxMbDescription", { min: MIN_EXTERNAL_SQL_EDITOR_FILE_MB, max: MAX_EXTERNAL_SQL_EDITOR_FILE_MB }) }}
|
||||
</p>
|
||||
</div>
|
||||
<Input
|
||||
id="external-sql-editor-max-mb"
|
||||
type="number"
|
||||
inputmode="numeric"
|
||||
class="h-7 w-[130px] px-2 text-left text-xs tabular-nums"
|
||||
:min="MIN_EXTERNAL_SQL_EDITOR_FILE_MB"
|
||||
:max="MAX_EXTERNAL_SQL_EDITOR_FILE_MB"
|
||||
:model-value="editExternalSqlEditorMaxMb"
|
||||
@input="updateExternalSqlEditorMaxMbInput"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="isWeb" 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="web-sql-file-upload-max-mb">
|
||||
{{ t("settings.webSqlFileUploadMaxMb") }}
|
||||
</Label>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
{{ t("settings.webSqlFileUploadMaxMbDescription", { min: MIN_EXTERNAL_SQL_EDITOR_FILE_MB, max: MAX_EXTERNAL_SQL_EDITOR_FILE_MB }) }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex shrink-0 items-center gap-2">
|
||||
<Input
|
||||
id="web-sql-file-upload-max-mb"
|
||||
v-model.number="editWebSqlFileUploadMaxMb"
|
||||
type="number"
|
||||
inputmode="numeric"
|
||||
class="h-7 w-[130px] px-2 text-left text-xs tabular-nums"
|
||||
:min="MIN_EXTERNAL_SQL_EDITOR_FILE_MB"
|
||||
:max="MAX_EXTERNAL_SQL_EDITOR_FILE_MB"
|
||||
:disabled="!webSqlFileUploadMaxMbLoaded || webSqlFileUploadMaxMbLoading"
|
||||
:aria-invalid="webSqlFileUploadMaxMbOutOfRange(editWebSqlFileUploadMaxMb)"
|
||||
/>
|
||||
<Button type="button" size="sm" variant="outline" :disabled="!webSqlFileUploadMaxMbLoaded || webSqlFileUploadMaxMbSaving || webSqlFileUploadMaxMbOutOfRange(editWebSqlFileUploadMaxMb)" @click="saveWebSqlFileUploadMaxMbSetting">
|
||||
{{ t("settings.save") }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section v-else-if="activeSettingsTab === 'shortcuts'" data-settings-search-id="shortcuts" :class="['flex flex-col gap-2 py-2', settingsSearchTargetClass('shortcuts')]">
|
||||
<div class="relative">
|
||||
<Search class="pointer-events-none absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
|
||||
|
||||
@@ -10,12 +10,13 @@ import LightTooltip from "@/components/ui/LightTooltip.vue";
|
||||
import CustomContextMenu, { type ContextMenuItem } from "@/components/ui/CustomContextMenu.vue";
|
||||
import { useQueryStore } from "@/stores/queryStore";
|
||||
import { useConnectionStore } from "@/stores/connectionStore";
|
||||
import { useSettingsStore } from "@/stores/settingsStore";
|
||||
import { useToast } from "@/composables/useToast";
|
||||
import { isTauriRuntime } from "@/lib/backend/tauriRuntime";
|
||||
import { translateBackendError } from "@/i18n/backend-errors";
|
||||
import { copyToClipboard } from "@/lib/common/clipboard";
|
||||
import { forgetExternalSqlFileTarget, moveExternalSqlFileTarget, resolveExternalSqlFileTarget, unassociatedExternalSqlFileTarget } from "@/lib/sql/externalSqlFileTarget";
|
||||
import { externalSqlFileOpenErrorMessage, formatSqlFileSize, isExternalSqlFileTooLargeError, isSqlFilePath } from "@/lib/sql/sqlFileOpen";
|
||||
import { externalSqlFileOpenErrorMessage, externalSqlEditorMaxBytes, formatSqlFileSize, isExternalSqlFileTooLargeError, isSqlFilePath } from "@/lib/sql/sqlFileOpen";
|
||||
import * as api from "@/lib/backend/api";
|
||||
import type { SqlFileEntry } from "@/lib/backend/api";
|
||||
import { getSqlFileFilter, getSqlFileFolderPaths, saveSqlFileFilter, saveSqlFileFolderPaths, notifySqlFileFoldersChanged } from "@/lib/sqlFile/sqlFileFolders";
|
||||
@@ -28,6 +29,7 @@ const emit = defineEmits<{
|
||||
const { t } = useI18n();
|
||||
const queryStore = useQueryStore();
|
||||
const connectionStore = useConnectionStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
const { toast } = useToast();
|
||||
|
||||
interface FolderState {
|
||||
@@ -253,7 +255,7 @@ function collectDirPaths(entries: SqlFileEntry[], into: Set<string>) {
|
||||
async function openFile(path: string) {
|
||||
if (!isTauriRuntime()) return;
|
||||
try {
|
||||
const snapshot = await api.readExternalSqlFileSnapshot(path);
|
||||
const snapshot = await api.readExternalSqlFileSnapshot(path, externalSqlEditorMaxBytes(settingsStore.editorSettings.externalSqlEditorMaxMb));
|
||||
const target = resolveExternalSqlFileTarget(path, (savedConnectionId) => !!connectionStore.getConfig(savedConnectionId), unassociatedExternalSqlFileTarget());
|
||||
queryStore.openExternalSqlFile(target.connectionId, target.database, path, snapshot.content, snapshot.version, target.catalog, target.schema);
|
||||
} catch (e: any) {
|
||||
|
||||
@@ -16,6 +16,7 @@ import { useSavedSqlStore } from "@/stores/savedSqlStore";
|
||||
import { useConnectionStore } from "@/stores/connectionStore";
|
||||
import { useQueryStore } from "@/stores/queryStore";
|
||||
import { useSettingsStore } from "@/stores/settingsStore";
|
||||
import { externalSqlEditorMaxBytes } from "@/lib/sql/sqlFileOpen";
|
||||
import { focusSidebarRenameInput } from "@/lib/sidebar/sidebarRenameFocus";
|
||||
import { savedSqlFolderBranchFileCount } from "@/lib/savedSql/savedSqlFolderCounts";
|
||||
import { collectSavedSqlDirectoryImportFiles } from "@/lib/savedSql/savedSqlDirectoryImport";
|
||||
@@ -231,7 +232,7 @@ async function importDirectoryIntoLibrary(targetFolder?: SavedSqlFolder) {
|
||||
takenNamesByFolder.set(folderKey, takenNames);
|
||||
}
|
||||
const path = file.path;
|
||||
const content = await api.readExternalSqlFile(path);
|
||||
const content = await api.readExternalSqlFile(path, externalSqlEditorMaxBytes(settingsStore.editorSettings.externalSqlEditorMaxMb));
|
||||
const displayName = uniqueImportedName(file.name, takenNames);
|
||||
await savedSqlStore.saveFile({
|
||||
connectionId: importTarget.connectionId,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from "vue";
|
||||
import { computed, onMounted, ref, watch } from "vue";
|
||||
import { uuid } from "@/lib/common/utils";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useSqlHighlighter } from "@/composables/useSqlHighlighter";
|
||||
@@ -97,7 +97,21 @@ const terminalError = ref("");
|
||||
const activeExecutionTask = ref<ExportTask | null>(null);
|
||||
const failureDetailsExpanded = ref(false);
|
||||
const refreshedTarget = ref(false);
|
||||
const MAX_WEB_SQL_FILE_BYTES = 200 * 1024 * 1024;
|
||||
const DEFAULT_WEB_SQL_FILE_BYTES = 200 * 1024 * 1024;
|
||||
const webSqlFileUploadMaxBytes = ref(DEFAULT_WEB_SQL_FILE_BYTES);
|
||||
|
||||
// The web server caps SQL file uploads via DBX_SQL_FILE_UPLOAD_MAX_MB; fetch the
|
||||
// effective limit once so the client-side pre-check matches the server rule.
|
||||
onMounted(async () => {
|
||||
if (isDesktopRuntime) return;
|
||||
try {
|
||||
const { loadSqlFileUploadMaxBytes } = await import("@/lib/backend/http");
|
||||
const value = await loadSqlFileUploadMaxBytes();
|
||||
if (Number.isFinite(value) && value > 0) webSqlFileUploadMaxBytes.value = value;
|
||||
} catch {
|
||||
// Fall back to the built-in default; the server still rejects oversized uploads.
|
||||
}
|
||||
});
|
||||
|
||||
// Per-file results accumulated from backend file-boundary events during
|
||||
// multi-file execution. Populated only when previews.length > 1.
|
||||
@@ -285,8 +299,9 @@ async function previewSelectedSqlFile(fileOrPath: string | File) {
|
||||
return previewSqlFile(fileOrPath as string);
|
||||
}
|
||||
const file = fileOrPath as File;
|
||||
if (file.size > MAX_WEB_SQL_FILE_BYTES) {
|
||||
throw new Error(`File too large: ${file.size} bytes (max ${MAX_WEB_SQL_FILE_BYTES} bytes)`);
|
||||
const uploadLimit = webSqlFileUploadMaxBytes.value;
|
||||
if (file.size > uploadLimit) {
|
||||
throw new Error(`File too large: ${file.size} bytes (max ${uploadLimit} bytes)`);
|
||||
}
|
||||
const { previewSqlFile: previewWebSqlFile } = await import("@/lib/backend/http");
|
||||
return previewWebSqlFile(file);
|
||||
|
||||
@@ -4,6 +4,8 @@ import * as api from "@/lib/backend/api";
|
||||
import { isTauriRuntime } from "@/lib/backend/tauriRuntime";
|
||||
import { externalSqlFileContentMatchesBaseline, externalSqlFileMetadataMatches, externalSqlFileVersionWasIgnored } from "@/lib/sql/externalSqlFileChanges";
|
||||
import { useQueryStore } from "@/stores/queryStore";
|
||||
import { useSettingsStore } from "@/stores/settingsStore";
|
||||
import { externalSqlEditorMaxBytes } from "@/lib/sql/sqlFileOpen";
|
||||
import type { ExternalSqlFileSnapshot } from "@/lib/backend/tauri";
|
||||
import type { QueryTab } from "@/types/database";
|
||||
|
||||
@@ -64,6 +66,7 @@ function delay(ms: number) {
|
||||
export function useExternalSqlFileChanges(options: UseExternalSqlFileChangesOptions) {
|
||||
const { t } = useI18n();
|
||||
const queryStore = useQueryStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
const pendingPrompt = ref<ExternalSqlFilePrompt | null>(null);
|
||||
const checkingTabIds = new Set<string>();
|
||||
let promptResolver: ((decision: ExternalSqlFilePromptDecision) => void) | null = null;
|
||||
@@ -83,12 +86,13 @@ export function useExternalSqlFileChanges(options: UseExternalSqlFileChangesOpti
|
||||
}
|
||||
|
||||
async function readStableSnapshot(path: string) {
|
||||
const maxSizeBytes = externalSqlEditorMaxBytes(settingsStore.editorSettings.externalSqlEditorMaxMb);
|
||||
try {
|
||||
return await api.readExternalSqlFileSnapshot(path);
|
||||
return await api.readExternalSqlFileSnapshot(path, maxSizeBytes);
|
||||
} catch (firstError) {
|
||||
await delay(MISSING_FILE_RECHECK_DELAY_MS);
|
||||
try {
|
||||
return await api.readExternalSqlFileSnapshot(path);
|
||||
return await api.readExternalSqlFileSnapshot(path, maxSizeBytes);
|
||||
} catch {
|
||||
throw firstError;
|
||||
}
|
||||
|
||||
@@ -3,12 +3,13 @@ import { uuid } from "@/lib/common/utils";
|
||||
import { isTauriRuntime } from "@/lib/backend/tauriRuntime";
|
||||
import { useConnectionStore } from "@/stores/connectionStore";
|
||||
import { useQueryStore } from "@/stores/queryStore";
|
||||
import { useSettingsStore } from "@/stores/settingsStore";
|
||||
import { useToast } from "@/composables/useToast";
|
||||
import { useLargeSqlFileStreamingFallback } from "@/composables/useLargeSqlFileFallback";
|
||||
import * as api from "@/lib/backend/api";
|
||||
import type { ConnectionConfig, ExternalSqlFileVersion } from "@/types/database";
|
||||
import { detectDatabaseFileType } from "@/lib/database/databaseFileDetection";
|
||||
import { externalSqlFileOpenErrorMessage, readBrowserSqlFile } from "@/lib/sql/sqlFileOpen";
|
||||
import { externalSqlEditorMaxBytes, externalSqlFileOpenErrorMessage, readBrowserSqlFile } from "@/lib/sql/sqlFileOpen";
|
||||
import { resolveExternalSqlFileTarget, unassociatedExternalSqlFileTarget } from "@/lib/sql/externalSqlFileTarget";
|
||||
|
||||
function isSqlFilePath(path: string): boolean {
|
||||
@@ -23,6 +24,7 @@ export function useFileDrop() {
|
||||
const { t } = useI18n();
|
||||
const connectionStore = useConnectionStore();
|
||||
const queryStore = useQueryStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
const { toast } = useToast();
|
||||
const { openInStreamingExecutorOnTooLarge } = useLargeSqlFileStreamingFallback();
|
||||
|
||||
@@ -87,7 +89,7 @@ export function useFileDrop() {
|
||||
|
||||
if (isSqlFilePath(path)) {
|
||||
try {
|
||||
const snapshot = await api.readExternalSqlFileSnapshot(path);
|
||||
const snapshot = await api.readExternalSqlFileSnapshot(path, externalSqlEditorMaxBytes(settingsStore.editorSettings.externalSqlEditorMaxMb));
|
||||
await openDroppedSqlFile(name, snapshot.content, path, snapshot.version);
|
||||
} catch (e: any) {
|
||||
if (!openInStreamingExecutorOnTooLarge(path, e)) {
|
||||
@@ -128,7 +130,7 @@ export function useFileDrop() {
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
if (!isSqlFilePath(file.name)) continue;
|
||||
void readBrowserSqlFile(file)
|
||||
void readBrowserSqlFile(file, externalSqlEditorMaxBytes(settingsStore.editorSettings.externalSqlEditorMaxMb))
|
||||
.then((content) => openDroppedSqlFile(file.name, content))
|
||||
.catch((e: any) => {
|
||||
toast(t("toolbar.sqlOpenFailed", { message: externalSqlFileOpenErrorMessage(e, (key, params) => t(key, params)) }), 5000);
|
||||
|
||||
@@ -6540,6 +6540,7 @@ export default {
|
||||
appearanceTab: "Appearance",
|
||||
navigationTab: "Navigation",
|
||||
dataTab: "Data",
|
||||
sqlFileSizeTab: "SQL File Size",
|
||||
tunnelsTab: "Tunnels",
|
||||
tunnelsDescription: "Reusable SSH / proxy / HTTP tunnel configurations. Configure once, then select the profile from a connection's tunnel tab; edits here apply to every connection using the profile.",
|
||||
tunnelsEmpty: "No tunnel profiles yet. Create one here, then select it in a connection's tunnel settings.",
|
||||
@@ -6741,7 +6742,11 @@ export default {
|
||||
queryResultMaxRowsEnabled: "Limit query result rows",
|
||||
queryResultMaxRowsDescription: "Caps rows returned by queries, table data, stored procedures, and continuous loading.",
|
||||
queryResultMaxRowsTooSmall: "Must be at least the query page size ({pageSize}).",
|
||||
queryResultMaxRowsUnlimitedDescription: "No total row or continuous loading limit. Large results can use substantial memory.",
|
||||
externalSqlEditorMaxMb: "Maximum SQL editor file size",
|
||||
externalSqlEditorMaxMbDescription: "SQL files larger than this are routed to the streaming Execute SQL File dialog instead of the editor ({min}–{max} MB).",
|
||||
webSqlFileUploadMaxMb: "Maximum web SQL file upload size",
|
||||
webSqlFileUploadMaxMbDescription: "Largest SQL file the web server accepts for streaming execution ({min}–{max} MB).",
|
||||
sqlFileUploadMaxMbSaved: "Web SQL file upload size saved.",
|
||||
showColumnCommentsInHeader: "Show column comments under names",
|
||||
showColumnCommentsInHeaderDescription: "Display table column comments directly below grid column names.",
|
||||
showColumnTypesInHeader: "Show column types under names",
|
||||
|
||||
@@ -6131,6 +6131,7 @@ export default withEnglishFallback({
|
||||
appearanceTab: "Apariencia",
|
||||
navigationTab: "Navegación",
|
||||
dataTab: "Datos",
|
||||
sqlFileSizeTab: "Tamaño de archivo SQL",
|
||||
tunnelsTab: "Túneles",
|
||||
tunnelsDescription: "Configuraciones reutilizables de túneles SSH / proxy / HTTP. Configura una vez y selecciona el perfil desde la pestaña de túnel de una conexión; los cambios aquí se aplican a todas las conexiones que usan el perfil.",
|
||||
tunnelsEmpty: "Aún no hay perfiles de túnel. Crea uno aquí y selecciónalo en la configuración de túnel de una conexión.",
|
||||
@@ -6321,7 +6322,11 @@ export default withEnglishFallback({
|
||||
queryResultMaxRowsEnabled: "Limitar filas del resultado",
|
||||
queryResultMaxRowsDescription: "Limita las filas conservadas por consultas, datos de tablas, procedimientos almacenados y carga continua.",
|
||||
queryResultMaxRowsTooSmall: "Debe ser al menos el tamaño de página de consulta ({pageSize}).",
|
||||
queryResultMaxRowsUnlimitedDescription: "Sin límite total de filas ni de carga continua. Los resultados grandes pueden usar mucha memoria.",
|
||||
externalSqlEditorMaxMb: "Tamaño máximo de archivo del editor SQL",
|
||||
externalSqlEditorMaxMbDescription: "Los archivos SQL mayores que esto se envían al diálogo de ejecución por streaming en lugar del editor ({min}–{max} MB).",
|
||||
webSqlFileUploadMaxMb: "Tamaño máximo de carga de archivo SQL web",
|
||||
webSqlFileUploadMaxMbDescription: "Archivo SQL más grande que el servidor web acepta para ejecución en streaming ({min}–{max} MB).",
|
||||
sqlFileUploadMaxMbSaved: "Tamaño de carga de archivo SQL web guardado.",
|
||||
showColumnCommentsInHeader: "Mostrar comentarios bajo los nombres",
|
||||
showColumnCommentsInHeaderDescription: "Muestra los comentarios de columnas directamente debajo del nombre de la columna.",
|
||||
showColumnTypesInHeader: "Mostrar tipos de columna bajo los nombres",
|
||||
|
||||
@@ -6131,6 +6131,7 @@ export default withEnglishFallback({
|
||||
appearanceTab: "Aspetto",
|
||||
navigationTab: "Navigazione",
|
||||
dataTab: "Dati",
|
||||
sqlFileSizeTab: "Dimensione file SQL",
|
||||
tunnelsTab: "Tunnel",
|
||||
tunnelsDescription: "Configurazioni riutilizzabili di tunnel SSH / proxy / HTTP. Configura una volta, poi seleziona il profilo dalla scheda tunnel di una connessione; le modifiche qui si applicano a tutte le connessioni che usano il profilo.",
|
||||
tunnelsEmpty: "Nessun profilo tunnel. Creane uno qui, poi selezionalo nelle impostazioni tunnel di una connessione.",
|
||||
@@ -6321,7 +6322,11 @@ export default withEnglishFallback({
|
||||
queryResultMaxRowsEnabled: "Limita le righe del risultato",
|
||||
queryResultMaxRowsDescription: "Limita le righe conservate da query, dati tabella, stored procedure e caricamento continuo.",
|
||||
queryResultMaxRowsTooSmall: "Deve essere almeno pari alle righe per pagina della query ({pageSize}).",
|
||||
queryResultMaxRowsUnlimitedDescription: "Nessun limite totale di righe o di caricamento continuo. I risultati grandi possono usare molta memoria.",
|
||||
externalSqlEditorMaxMb: "Dimensione massima file dell'editor SQL",
|
||||
externalSqlEditorMaxMbDescription: "I file SQL più grandi vengono inviati alla finestra di esecuzione in streaming invece che all'editor ({min}–{max} MB).",
|
||||
webSqlFileUploadMaxMb: "Dimensione massima di caricamento file SQL web",
|
||||
webSqlFileUploadMaxMbDescription: "File SQL più grande che il server web accetta per l'esecuzione in streaming ({min}–{max} MB).",
|
||||
sqlFileUploadMaxMbSaved: "Dimensione di caricamento file SQL web salvata.",
|
||||
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.",
|
||||
showColumnTypesInHeader: "Mostra i tipi di colonna sotto i nomi",
|
||||
|
||||
@@ -6169,6 +6169,7 @@ export default withEnglishFallback({
|
||||
appearanceTab: "外観",
|
||||
navigationTab: "ナビゲーション",
|
||||
dataTab: "データ",
|
||||
sqlFileSizeTab: "SQLファイルサイズ",
|
||||
tunnelsTab: "トンネル",
|
||||
tunnelsDescription: "再利用可能な SSH / プロキシ / HTTP トンネル設定です。一度設定すれば、接続のトンネルタブからプロファイルを選択するだけで使えます。ここでの編集は、このプロファイルを使用するすべての接続に反映されます。",
|
||||
tunnelsEmpty: "トンネルプロファイルがまだありません。ここで作成し、接続のトンネル設定で選択してください。",
|
||||
@@ -6355,7 +6356,11 @@ export default withEnglishFallback({
|
||||
queryResultMaxRowsEnabled: "クエリ結果の行数を制限",
|
||||
queryResultMaxRowsDescription: "クエリ、テーブルデータ、ストアドプロシージャ、および連続読み込みで保持する合計行数を制限します。",
|
||||
queryResultMaxRowsTooSmall: "クエリのページ行数({pageSize})以上にしてください。",
|
||||
queryResultMaxRowsUnlimitedDescription: "合計行数または連続読み込み数を制限しません。大きな結果は大量のメモリを使用する可能性があります。",
|
||||
externalSqlEditorMaxMb: "SQLエディターの最大ファイルサイズ",
|
||||
externalSqlEditorMaxMbDescription: "このサイズを超えるSQLファイルはエディターではなくストリーミング実行ダイアログに回されます({min}~{max} MB)。",
|
||||
webSqlFileUploadMaxMb: "Web SQLファイルの最大アップロードサイズ",
|
||||
webSqlFileUploadMaxMbDescription: "Webサーバーがストリーミング実行に受け付ける最大のSQLファイルサイズ({min}~{max} MB)。",
|
||||
sqlFileUploadMaxMbSaved: "Web SQLファイルのアップロードサイズを保存しました。",
|
||||
showColumnCommentsInHeader: "列名の下にコメントを表示",
|
||||
showColumnCommentsInHeaderDescription: "グリッド列名の直下にテーブル列コメントを表示します。",
|
||||
showColumnTypesInHeader: "列名の下にデータ型を表示",
|
||||
|
||||
@@ -5866,6 +5866,7 @@ export default withEnglishFallback({
|
||||
appearanceTab: "모양",
|
||||
navigationTab: "탐색",
|
||||
dataTab: "데이터",
|
||||
sqlFileSizeTab: "SQL 파일 크기",
|
||||
tunnelsTab: "터널",
|
||||
tunnelsDescription: "재사용 가능한 SSH/프록시/HTTP 터널 설정입니다. 한 번 구성한 후 연결의 터널 탭에서 프로필을 선택하세요. 여기서의 편집은 이 프로필을 사용하는 모든 연결에 적용됩니다.",
|
||||
tunnelsEmpty: "아직 터널 프로필이 없습니다. 여기서 만든 후 연결의 터널 설정에서 선택하세요.",
|
||||
@@ -6054,7 +6055,11 @@ export default withEnglishFallback({
|
||||
queryResultMaxRowsEnabled: "쿼리 결과 행 수 제한",
|
||||
queryResultMaxRowsDescription: "쿼리, 테이블 데이터, 저장 프로시저 및 연속 로딩에서 유지할 총 행 수를 제한합니다.",
|
||||
queryResultMaxRowsTooSmall: "쿼리 페이지 크기({pageSize}) 이상이어야 합니다.",
|
||||
queryResultMaxRowsUnlimitedDescription: "총 행 수 또는 연속 로딩 수를 제한하지 않습니다. 큰 결과는 많은 메모리를 사용할 수 있습니다.",
|
||||
externalSqlEditorMaxMb: "SQL 편집기 최대 파일 크기",
|
||||
externalSqlEditorMaxMbDescription: "이 크기를 초과하는 SQL 파일은 편집기 대신 스트리밍 실행 대화상자로 전달됩니다({min}–{max} MB).",
|
||||
webSqlFileUploadMaxMb: "웹 SQL 파일 최대 업로드 크기",
|
||||
webSqlFileUploadMaxMbDescription: "웹 서버가 스트리밍 실행에 허용하는 가장 큰 SQL 파일({min}–{max} MB).",
|
||||
sqlFileUploadMaxMbSaved: "웹 SQL 파일 업로드 크기가 저장되었습니다.",
|
||||
showColumnCommentsInHeader: "이름 아래에 컬럼 주석 표시",
|
||||
showColumnCommentsInHeaderDescription: "그리드 컬럼 이름 바로 아래에 테이블 컬럼 주석을 표시합니다.",
|
||||
showColumnTypesInHeader: "이름 아래에 컬럼 타입 표시",
|
||||
|
||||
@@ -6133,6 +6133,7 @@ export default withEnglishFallback({
|
||||
appearanceTab: "Aparência",
|
||||
navigationTab: "Navegação",
|
||||
dataTab: "Dados",
|
||||
sqlFileSizeTab: "Tamanho de arquivo SQL",
|
||||
tunnelsTab: "Túneis",
|
||||
tunnelsDescription: "Configurações reutilizáveis de túneis SSH / proxy / HTTP. Configure uma vez e selecione o perfil na aba de túnel de uma conexão; as edições aqui se aplicam a todas as conexões que usam o perfil.",
|
||||
tunnelsEmpty: "Ainda não há perfis de túnel. Crie um aqui e selecione-o nas configurações de túnel de uma conexão.",
|
||||
@@ -6323,7 +6324,11 @@ export default withEnglishFallback({
|
||||
queryResultMaxRowsEnabled: "Limitar linhas do resultado",
|
||||
queryResultMaxRowsDescription: "Limita as linhas mantidas por consultas, dados de tabelas, procedimentos armazenados e carregamento contínuo.",
|
||||
queryResultMaxRowsTooSmall: "Deve ser pelo menos o tamanho da página da consulta ({pageSize}).",
|
||||
queryResultMaxRowsUnlimitedDescription: "Sem limite total de linhas ou de carregamento contínuo. Resultados grandes podem usar muita memória.",
|
||||
externalSqlEditorMaxMb: "Tamanho máximo de arquivo do editor SQL",
|
||||
externalSqlEditorMaxMbDescription: "Arquivos SQL maiores são enviados para o diálogo de execução em streaming em vez do editor ({min}–{max} MB).",
|
||||
webSqlFileUploadMaxMb: "Tamanho máximo de upload de arquivo SQL web",
|
||||
webSqlFileUploadMaxMbDescription: "Maior arquivo SQL que o servidor web aceita para execução em streaming ({min}–{max} MB).",
|
||||
sqlFileUploadMaxMbSaved: "Tamanho de upload de arquivo SQL web salvo.",
|
||||
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.",
|
||||
showColumnTypesInHeader: "Mostrar tipos de coluna sob os nomes",
|
||||
|
||||
@@ -6426,6 +6426,7 @@ export default withEnglishFallback({
|
||||
appearanceTab: "Görünüm",
|
||||
navigationTab: "Gezinme",
|
||||
dataTab: "Veri",
|
||||
sqlFileSizeTab: "SQL Dosya Boyutu",
|
||||
tunnelsTab: "Tüneller",
|
||||
tunnelsDescription: "Yeniden kullanılabilir SSH / proxy / HTTP tünel yapılandırmaları. Bir kez yapılandırın, sonra bağlantının tünel sekmesinden profili seçin; buradaki değişiklikler profili kullanan her bağlantıda geçerli olur.",
|
||||
tunnelsEmpty: "Henüz tünel profili yok. Burada bir tane oluşturun, ardından bir bağlantının tünel ayarlarından seçin.",
|
||||
@@ -6625,7 +6626,11 @@ export default withEnglishFallback({
|
||||
queryResultMaxRowsEnabled: "Sorgu sonucu satırlarını sınırla",
|
||||
queryResultMaxRowsDescription: "Sorgular, tablo verisi, saklı yordamlar ve sürekli yükleme tarafından döndürülen satırlara üst sınır koyar.",
|
||||
queryResultMaxRowsTooSmall: "En az sorgu sayfa boyutu ({pageSize}) kadar olmalıdır.",
|
||||
queryResultMaxRowsUnlimitedDescription: "Toplam satır veya sürekli yükleme sınırı yok. Büyük sonuçlar çok fazla bellek kullanabilir.",
|
||||
externalSqlEditorMaxMb: "SQL düzenleyici maksimum dosya boyutu",
|
||||
externalSqlEditorMaxMbDescription: "Bu boyuttan büyük SQL dosyaları düzenleyici yerine akış yürütme iletişim kutusuna yönlendirilir ({min}–{max} MB).",
|
||||
webSqlFileUploadMaxMb: "Web SQL dosyası maksimum yükleme boyutu",
|
||||
webSqlFileUploadMaxMbDescription: "Web sunucusunun akış yürütme için kabul ettiği en büyük SQL dosyası ({min}–{max} MB).",
|
||||
sqlFileUploadMaxMbSaved: "Web SQL dosyası yükleme boyutu kaydedildi.",
|
||||
showColumnCommentsInHeader: "Sütun açıklamalarını adların altında göster",
|
||||
showColumnCommentsInHeaderDescription: "Tablo sütun açıklamalarını doğrudan ızgara sütun adlarının altında göster.",
|
||||
showColumnTypesInHeader: "Sütun türlerini adların altında göster",
|
||||
|
||||
@@ -6523,6 +6523,7 @@ export default withEnglishFallback({
|
||||
appearanceTab: "外观",
|
||||
navigationTab: "导航",
|
||||
dataTab: "数据",
|
||||
sqlFileSizeTab: "SQL 文件大小",
|
||||
tunnelsTab: "隧道维护",
|
||||
tunnelsDescription: "可复用的 SSH / 代理 / HTTP 隧道配置。一次配置,之后在连接的隧道页签中选择档案即可;此处的修改会对所有使用该档案的连接生效。",
|
||||
tunnelsEmpty: "还没有隧道档案。先在这里创建,然后在连接的隧道设置中选择使用。",
|
||||
@@ -6724,7 +6725,11 @@ export default withEnglishFallback({
|
||||
queryResultMaxRowsEnabled: "限制查询结果行数",
|
||||
queryResultMaxRowsDescription: "限制查询、表数据、存储过程及连续滚动累计保留的总行数。",
|
||||
queryResultMaxRowsTooSmall: "不能小于查询结果默认每页行数({pageSize})。",
|
||||
queryResultMaxRowsUnlimitedDescription: "不限制返回总行数或连续滚动累计数量,大结果集可能占用较多内存。",
|
||||
externalSqlEditorMaxMb: "SQL 编辑器最大文件大小",
|
||||
externalSqlEditorMaxMbDescription: "超过此大小的 SQL 文件将转交流式执行 SQL 文件对话框而不是编辑器({min}–{max} MB)。",
|
||||
webSqlFileUploadMaxMb: "Web SQL 文件最大上传大小",
|
||||
webSqlFileUploadMaxMbDescription: "Web 服务器接受用于流式执行的最大 SQL 文件({min}–{max} MB)。",
|
||||
sqlFileUploadMaxMbSaved: "Web SQL 文件上传大小已保存。",
|
||||
showColumnCommentsInHeader: "在字段名下方显示注释",
|
||||
showColumnCommentsInHeaderDescription: "把表字段注释直接显示在结果表头字段名下方。",
|
||||
showColumnTypesInHeader: "在字段名下方显示数据类型",
|
||||
|
||||
@@ -5459,6 +5459,7 @@ export default withEnglishFallback({
|
||||
securityTab: "安全",
|
||||
aboutTab: "關於我們",
|
||||
dataTab: "資料",
|
||||
sqlFileSizeTab: "SQL 檔案大小",
|
||||
tunnelsTab: "隧道維護",
|
||||
tunnelsDescription: "可重複使用的 SSH / 代理 / HTTP 隧道設定。一次設定,之後在連線的隧道頁籤中選擇設定檔即可;此處的變更會套用到所有使用該設定檔的連線。",
|
||||
tunnelsEmpty: "還沒有隧道設定檔。先在這裡建立,然後在連線的隧道設定中選擇使用。",
|
||||
@@ -5636,7 +5637,11 @@ export default withEnglishFallback({
|
||||
queryResultMaxRowsEnabled: "限制查詢結果列數",
|
||||
queryResultMaxRowsDescription: "限制查詢、資料表資料、預存程序及連續捲動累計保留的總列數。",
|
||||
queryResultMaxRowsTooSmall: "不能小於查詢結果預設每頁列數({pageSize})。",
|
||||
queryResultMaxRowsUnlimitedDescription: "不限制傳回總列數或連續捲動累計數量,大型結果集可能占用大量記憶體。",
|
||||
externalSqlEditorMaxMb: "SQL 編輯器最大檔案大小",
|
||||
externalSqlEditorMaxMbDescription: "超過此大小的 SQL 檔案將轉交流式執行 SQL 檔案對話方塊而不是編輯器({min}–{max} MB)。",
|
||||
webSqlFileUploadMaxMb: "Web SQL 檔案最大上傳大小",
|
||||
webSqlFileUploadMaxMbDescription: "Web 伺服器接受用於串流執行之最大 SQL 檔案({min}–{max} MB)。",
|
||||
sqlFileUploadMaxMbSaved: "Web SQL 檔案上傳大小已儲存。",
|
||||
showColumnCommentsInHeader: "在欄位名稱下方顯示註解",
|
||||
showColumnCommentsInHeaderDescription: "直接在資料表格欄位名稱下方顯示資料表欄位註解。",
|
||||
showColumnTypesInHeader: "在欄位名稱下方顯示資料類型",
|
||||
|
||||
+45
-1
@@ -1,7 +1,21 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { ExternalSqlFileTooLargeError, externalSqlFileDisplayTitles, externalSqlFileOpenErrorMessage, formatSqlFileSize, isSqlFilePath, MAX_EXTERNAL_SQL_EDITOR_FILE_BYTES, normalizeExternalSqlPath, readBrowserSqlFile } from "@/lib/sql/sqlFileOpen";
|
||||
import {
|
||||
ExternalSqlFileTooLargeError,
|
||||
clampExternalSqlEditorMaxMbInput,
|
||||
externalSqlEditorMaxBytes,
|
||||
externalSqlFileDisplayTitles,
|
||||
externalSqlFileOpenErrorMessage,
|
||||
formatSqlFileSize,
|
||||
isSqlFilePath,
|
||||
MAX_EXTERNAL_SQL_EDITOR_FILE_BYTES,
|
||||
MAX_EXTERNAL_SQL_EDITOR_FILE_MB,
|
||||
MIN_EXTERNAL_SQL_EDITOR_FILE_MB,
|
||||
normalizeExternalSqlEditorMaxMb,
|
||||
normalizeExternalSqlPath,
|
||||
readBrowserSqlFile,
|
||||
} from "@/lib/sql/sqlFileOpen";
|
||||
|
||||
describe("external SQL file paths", () => {
|
||||
it("normalizes Windows separators for identity checks", () => {
|
||||
@@ -41,6 +55,36 @@ describe("external SQL file editor limit", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("honors a custom browser editor limit", async () => {
|
||||
const file = new Blob(["select 1;"]);
|
||||
Object.defineProperty(file, "size", { value: 8 });
|
||||
|
||||
await expect(readBrowserSqlFile(file, 4)).rejects.toMatchObject({
|
||||
name: "ExternalSqlFileTooLargeError",
|
||||
sizeBytes: 8,
|
||||
maxSizeBytes: 4,
|
||||
});
|
||||
});
|
||||
|
||||
it("normalizes the configurable editor size limit in MB", () => {
|
||||
expect(normalizeExternalSqlEditorMaxMb(undefined)).toBe(64);
|
||||
expect(normalizeExternalSqlEditorMaxMb(0)).toBe(MIN_EXTERNAL_SQL_EDITOR_FILE_MB);
|
||||
expect(normalizeExternalSqlEditorMaxMb(128)).toBe(128);
|
||||
expect(normalizeExternalSqlEditorMaxMb(99999)).toBe(MAX_EXTERNAL_SQL_EDITOR_FILE_MB);
|
||||
expect(normalizeExternalSqlEditorMaxMb(12.6)).toBe(13);
|
||||
});
|
||||
|
||||
it("clamps the editor size limit input", () => {
|
||||
expect(clampExternalSqlEditorMaxMbInput("abc")).toBe(MIN_EXTERNAL_SQL_EDITOR_FILE_MB);
|
||||
expect(clampExternalSqlEditorMaxMbInput(0)).toBe(MIN_EXTERNAL_SQL_EDITOR_FILE_MB);
|
||||
expect(clampExternalSqlEditorMaxMbInput(256)).toBe(256);
|
||||
expect(clampExternalSqlEditorMaxMbInput(99999)).toBe(MAX_EXTERNAL_SQL_EDITOR_FILE_MB);
|
||||
});
|
||||
|
||||
it("converts the editor size limit to bytes", () => {
|
||||
expect(externalSqlEditorMaxBytes(64)).toBe(64 * 1024 * 1024);
|
||||
});
|
||||
|
||||
it("formats large file sizes", () => {
|
||||
expect(formatSqlFileSize(64 * 1024 * 1024)).toBe("64.0 MB");
|
||||
expect(formatSqlFileSize(50 * 1024 * 1024 * 1024)).toBe("50.0 GB");
|
||||
|
||||
@@ -313,6 +313,8 @@ export const saveDesktopSettings = forward("saveDesktopSettings");
|
||||
export const loadMcpGlobalPolicy = forward("loadMcpGlobalPolicy");
|
||||
export const saveMcpGlobalPolicy = forward("saveMcpGlobalPolicy");
|
||||
export const loadMaxAgentTurns = forward("loadMaxAgentTurns");
|
||||
export const loadSqlFileUploadMaxBytes = forward("loadSqlFileUploadMaxBytes");
|
||||
export const saveSqlFileUploadMaxMb = forward("saveSqlFileUploadMaxMb");
|
||||
export const saveMaxAgentTurns = forward("saveMaxAgentTurns");
|
||||
export const loadMaxRetries = forward("loadMaxRetries");
|
||||
export const saveMaxRetries = forward("saveMaxRetries");
|
||||
|
||||
@@ -1848,6 +1848,19 @@ export async function loadMaxAgentTurns(): Promise<number> {
|
||||
return get("/api/app-settings/max-agent-turns");
|
||||
}
|
||||
|
||||
export async function loadSqlFileUploadMaxBytes(): Promise<number> {
|
||||
return get("/api/app-settings/sql-file-upload-max-bytes");
|
||||
}
|
||||
|
||||
export async function saveSqlFileUploadMaxMb(sqlFileUploadMaxMb: number): Promise<void> {
|
||||
const res = await fetch(apiUrl("/api/app-settings/sql-file-upload-max-bytes"), {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ sqlFileUploadMaxMb }),
|
||||
});
|
||||
if (!res.ok) throw await backendResponseError(res);
|
||||
}
|
||||
|
||||
export async function saveMaxAgentTurns(maxAgentTurns: number): Promise<void> {
|
||||
const res = await fetch(apiUrl("/api/app-settings/max-agent-turns"), {
|
||||
method: "PUT",
|
||||
@@ -2270,11 +2283,11 @@ export async function pendingOpenAiConfigLinks(): Promise<string[]> {
|
||||
return [];
|
||||
}
|
||||
|
||||
export async function readExternalSqlFile(_path: string): Promise<string> {
|
||||
export async function readExternalSqlFile(_path: string, _maxSizeBytes?: number): Promise<string> {
|
||||
throw new Error("Opening external SQL file paths is only available in the desktop app");
|
||||
}
|
||||
|
||||
export async function readExternalSqlFileSnapshot(_path: string): Promise<import("@/lib/backend/tauri").ExternalSqlFileSnapshot> {
|
||||
export async function readExternalSqlFileSnapshot(_path: string, _maxSizeBytes?: number): Promise<import("@/lib/backend/tauri").ExternalSqlFileSnapshot> {
|
||||
throw new Error("Opening external SQL file paths is only available in the desktop app");
|
||||
}
|
||||
|
||||
|
||||
@@ -717,6 +717,14 @@ export async function loadMaxAgentTurns(): Promise<number> {
|
||||
return invoke("load_max_agent_turns");
|
||||
}
|
||||
|
||||
export async function loadSqlFileUploadMaxBytes(): Promise<number> {
|
||||
return 200 * 1024 * 1024;
|
||||
}
|
||||
|
||||
export async function saveSqlFileUploadMaxMb(_sqlFileUploadMaxMb: number): Promise<void> {
|
||||
// No-op on desktop: SQL files are streamed directly from disk, no server upload cap applies.
|
||||
}
|
||||
|
||||
export async function saveMaxAgentTurns(maxAgentTurns: number): Promise<void> {
|
||||
return invoke("save_max_agent_turns", { maxAgentTurns });
|
||||
}
|
||||
@@ -970,16 +978,16 @@ export type ExternalSqlFileStatus = { kind: "present"; sizeBytes: number; modifi
|
||||
|
||||
export type ExternalSqlFileWriteResult = { kind: "written"; version: ExternalSqlFileVersion } | { kind: "conflict"; currentVersion: ExternalSqlFileVersion } | { kind: "missing" };
|
||||
|
||||
export async function readExternalSqlFileSnapshot(path: string): Promise<ExternalSqlFileSnapshot> {
|
||||
const result = await invoke<{ kind: "content"; content: string; version: ExternalSqlFileVersion } | { kind: "tooLarge"; sizeBytes: number; maxSizeBytes: number }>("read_external_sql_file", { path });
|
||||
export async function readExternalSqlFileSnapshot(path: string, maxSizeBytes?: number): Promise<ExternalSqlFileSnapshot> {
|
||||
const result = await invoke<{ kind: "content"; content: string; version: ExternalSqlFileVersion } | { kind: "tooLarge"; sizeBytes: number; maxSizeBytes: number }>("read_external_sql_file", { path, maxSizeBytes });
|
||||
if (result.kind === "tooLarge") {
|
||||
throw new ExternalSqlFileTooLargeError(result.sizeBytes, result.maxSizeBytes);
|
||||
}
|
||||
return { content: result.content, version: result.version };
|
||||
}
|
||||
|
||||
export async function readExternalSqlFile(path: string): Promise<string> {
|
||||
return (await readExternalSqlFileSnapshot(path)).content;
|
||||
export async function readExternalSqlFile(path: string, maxSizeBytes?: number): Promise<string> {
|
||||
return (await readExternalSqlFileSnapshot(path, maxSizeBytes)).content;
|
||||
}
|
||||
|
||||
export async function inspectExternalSqlFile(path: string): Promise<ExternalSqlFileStatus> {
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { EditorSettings } from "@/stores/settingsStore";
|
||||
import { normalizeBackgroundImageSettings } from "@/lib/app/appBackgroundImage";
|
||||
import { normalizeResultPageSize } from "@/lib/dataGrid/paginationPageSize";
|
||||
import { normalizeQueryResultMaxRows } from "@/lib/dataGrid/queryResultRowLimit";
|
||||
import { normalizeExternalSqlEditorMaxMb } from "@/lib/sql/sqlFileOpen";
|
||||
import { normalizeCompletionTriggerMode } from "@/lib/sql/sqlCompletionTriggerPolicy";
|
||||
import { normalizeRedisKeyTemplates } from "@/lib/redis/redisKeyTemplates";
|
||||
|
||||
@@ -59,6 +60,7 @@ export const EDITOR_SETTINGS_DRAFT_KEYS = [
|
||||
"tableOpenPageSize",
|
||||
"queryResultMaxRowsEnabled",
|
||||
"queryResultMaxRows",
|
||||
"externalSqlEditorMaxMb",
|
||||
"infiniteScroll",
|
||||
"regexMaxMatchCount",
|
||||
"autoCalculateTotalRows",
|
||||
@@ -131,6 +133,7 @@ export function normalizeQueryResultMaxRowsDraft(value: unknown): number {
|
||||
function normalizedDraftValue(key: EditorSettingsDraftKey, value: unknown): unknown {
|
||||
if (key === "pageSize" || key === "tableOpenPageSize") return normalizeTableOpenPageSizeDraft(value);
|
||||
if (key === "queryResultMaxRows") return normalizeQueryResultMaxRowsDraft(value);
|
||||
if (key === "externalSqlEditorMaxMb") return normalizeExternalSqlEditorMaxMb(value);
|
||||
if (key === "completionTriggerMode") return normalizeCompletionTriggerMode(value);
|
||||
if (key === "redisKeyTemplates") return normalizeRedisKeyTemplates(value);
|
||||
if (key === "backgroundImage") return normalizeBackgroundImageSettings(value);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export type SettingsCategory = "editor" | "formatter" | "appearance" | "navigation" | "data" | "backups" | "tunnels" | "shortcuts" | "snippets" | "sync" | "ai" | "mcp" | "security" | "about";
|
||||
export type SettingsCategory = "editor" | "formatter" | "appearance" | "navigation" | "data" | "sqlFile" | "backups" | "tunnels" | "shortcuts" | "snippets" | "sync" | "ai" | "mcp" | "security" | "about";
|
||||
|
||||
export interface SettingsSearchContext {
|
||||
isWeb: boolean;
|
||||
@@ -199,6 +199,8 @@ export const SETTINGS_SEARCH_DEFINITIONS: readonly SettingsSearchDefinition[] =
|
||||
{ id: "data-grid-quick-entry", category: "data", titleKey: "settings.dataGridQuickEntry", descriptionKey: "settings.dataGridQuickEntryDescription", targetId: "data" },
|
||||
{ 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: "sql-file-editor-max-mb", category: "sqlFile", titleKey: "settings.externalSqlEditorMaxMb", descriptionKey: "settings.externalSqlEditorMaxMbDescription", targetId: "sqlFile" },
|
||||
{ id: "sql-file-web-upload-max-mb", category: "sqlFile", titleKey: "settings.webSqlFileUploadMaxMb", descriptionKey: "settings.webSqlFileUploadMaxMbDescription", targetId: "sqlFile", visible: (context) => context.isWeb },
|
||||
{ id: "appearance-toolbar", category: "appearance", titleKey: "settings.toolbarTitle", descriptionKey: "settings.toolbarHiddenHint", targetId: "appearance" },
|
||||
{ id: "appearance-exclusive-sidebar-panels", category: "appearance", titleKey: "settings.exclusiveRightSidebarPanels", descriptionKey: "settings.exclusiveRightSidebarPanelsDescription", targetId: "appearance" },
|
||||
...createToolbarVisibilitySettingsSearchDefinitions(),
|
||||
|
||||
@@ -152,6 +152,7 @@ const SETTINGS_TRANSFER_CATEGORY_KEYS: Record<SettingsTransferCategoryId, readon
|
||||
"tableOpenPageSize",
|
||||
"queryResultMaxRowsEnabled",
|
||||
"queryResultMaxRows",
|
||||
"externalSqlEditorMaxMb",
|
||||
"infiniteScroll",
|
||||
"regexMaxMatchCount",
|
||||
"autoCalculateTotalRows",
|
||||
|
||||
@@ -49,6 +49,25 @@ export function externalSqlFilePaths(paths: string[]): string[] {
|
||||
|
||||
export const MAX_EXTERNAL_SQL_EDITOR_FILE_BYTES = 64 * 1024 * 1024;
|
||||
|
||||
export const MIN_EXTERNAL_SQL_EDITOR_FILE_MB = 1;
|
||||
export const MAX_EXTERNAL_SQL_EDITOR_FILE_MB = 4096;
|
||||
|
||||
export function normalizeExternalSqlEditorMaxMb(value: unknown): number {
|
||||
const parsed = Number(value);
|
||||
if (!Number.isFinite(parsed)) return MAX_EXTERNAL_SQL_EDITOR_FILE_BYTES / (1024 * 1024);
|
||||
return Math.min(MAX_EXTERNAL_SQL_EDITOR_FILE_MB, Math.max(MIN_EXTERNAL_SQL_EDITOR_FILE_MB, Math.round(parsed)));
|
||||
}
|
||||
|
||||
export function externalSqlEditorMaxBytes(maxMb: number): number {
|
||||
return Math.round(maxMb * 1024 * 1024);
|
||||
}
|
||||
|
||||
export function clampExternalSqlEditorMaxMbInput(value: unknown): number {
|
||||
const parsed = Number(value);
|
||||
if (!Number.isFinite(parsed)) return MIN_EXTERNAL_SQL_EDITOR_FILE_MB;
|
||||
return Math.min(MAX_EXTERNAL_SQL_EDITOR_FILE_MB, Math.max(MIN_EXTERNAL_SQL_EDITOR_FILE_MB, Math.round(parsed)));
|
||||
}
|
||||
|
||||
export class ExternalSqlFileTooLargeError extends Error {
|
||||
constructor(
|
||||
readonly sizeBytes: number,
|
||||
@@ -63,9 +82,9 @@ export function isExternalSqlFileTooLargeError(error: unknown): error is Externa
|
||||
return error instanceof ExternalSqlFileTooLargeError;
|
||||
}
|
||||
|
||||
export function readBrowserSqlFile(file: Blob): Promise<string> {
|
||||
if (file.size > MAX_EXTERNAL_SQL_EDITOR_FILE_BYTES) {
|
||||
return Promise.reject(new ExternalSqlFileTooLargeError(file.size, MAX_EXTERNAL_SQL_EDITOR_FILE_BYTES));
|
||||
export function readBrowserSqlFile(file: Blob, maxSizeBytes = MAX_EXTERNAL_SQL_EDITOR_FILE_BYTES): Promise<string> {
|
||||
if (file.size > maxSizeBytes) {
|
||||
return Promise.reject(new ExternalSqlFileTooLargeError(file.size, maxSizeBytes));
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
@@ -436,6 +436,14 @@ describe("normalizeEditorSettings", () => {
|
||||
expect(normalizeEditorSettings({ timeoutInheritanceMigrationVersion: 2 }).timeoutInheritanceMigrationVersion).toBe(2);
|
||||
});
|
||||
|
||||
it("normalizes the external SQL editor size limit", () => {
|
||||
expect(normalizeEditorSettings({}).externalSqlEditorMaxMb).toBe(64);
|
||||
expect(normalizeEditorSettings({ externalSqlEditorMaxMb: 0 }).externalSqlEditorMaxMb).toBe(1);
|
||||
expect(normalizeEditorSettings({ externalSqlEditorMaxMb: 256 }).externalSqlEditorMaxMb).toBe(256);
|
||||
expect(normalizeEditorSettings({ externalSqlEditorMaxMb: 99999 }).externalSqlEditorMaxMb).toBe(4096);
|
||||
expect(normalizeEditorSettings({ externalSqlEditorMaxMb: "128" } as any).externalSqlEditorMaxMb).toBe(128);
|
||||
});
|
||||
|
||||
it("normalizes toolbar item settings from older saved settings", () => {
|
||||
const settings = normalizeEditorSettings({
|
||||
toolbarItems: {
|
||||
|
||||
@@ -12,6 +12,7 @@ import { DATA_GRID_TEXT_FILTER_PANEL_HEIGHT_DEFAULT, normalizeDataGridTextFilter
|
||||
import { DATA_GRID_TYPE_COLOR_SCHEME_AUTO_ID, type DataGridTypeColorScheme, normalizeActiveDataGridTypeColorSchemeId, normalizeDataGridTypeColorSchemes } from "@/lib/dataGrid/dataGridTypeColorScheme";
|
||||
import { normalizeResultPageSize } from "@/lib/dataGrid/paginationPageSize";
|
||||
import { DEFAULT_QUERY_RESULT_MAX_ROWS, normalizeQueryResultMaxRows } from "@/lib/dataGrid/queryResultRowLimit";
|
||||
import { normalizeExternalSqlEditorMaxMb } from "@/lib/sql/sqlFileOpen";
|
||||
import { normalizeConnectTimeoutSecs, normalizeQueryTimeoutSecs } from "@/lib/connection/timeoutLimits";
|
||||
import { needsTabNavigationHistoryShortcutMigration, normalizeShortcutSettings, type ShortcutSettings } from "@/lib/editor/shortcutRegistry";
|
||||
import type { SavedSqlOpenTargetMode } from "@/lib/savedSql/savedSqlExecutionTarget";
|
||||
@@ -768,6 +769,7 @@ export interface EditorSettings {
|
||||
tableOpenPageSize: number;
|
||||
queryResultMaxRowsEnabled: boolean;
|
||||
queryResultMaxRows: number;
|
||||
externalSqlEditorMaxMb: number;
|
||||
infiniteScroll: boolean;
|
||||
/** Preserved for downgrade compatibility; current clients use queryResultMaxRows. */
|
||||
infiniteScrollMaxRows: number;
|
||||
@@ -1004,6 +1006,7 @@ export const DEFAULT_EDITOR_SETTINGS: EditorSettings = {
|
||||
tableOpenPageSize: 100,
|
||||
queryResultMaxRowsEnabled: true,
|
||||
queryResultMaxRows: DEFAULT_QUERY_RESULT_MAX_ROWS,
|
||||
externalSqlEditorMaxMb: 64,
|
||||
infiniteScroll: false,
|
||||
infiniteScrollMaxRows: 5000,
|
||||
flatteningMultiLineText: false,
|
||||
@@ -1458,6 +1461,7 @@ export function normalizeEditorSettings(settings: Partial<EditorSettings>, exist
|
||||
tableOpenPageSize: normalizeResultPageSize(settings.tableOpenPageSize, DEFAULT_EDITOR_SETTINGS.tableOpenPageSize),
|
||||
queryResultMaxRowsEnabled: settings.queryResultMaxRowsEnabled !== false,
|
||||
queryResultMaxRows: normalizeQueryResultMaxRows(settings.queryResultMaxRows),
|
||||
externalSqlEditorMaxMb: normalizeExternalSqlEditorMaxMb(settings.externalSqlEditorMaxMb),
|
||||
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,
|
||||
flatteningMultiLineText: settings.flatteningMultiLineText ?? DEFAULT_EDITOR_SETTINGS.flatteningMultiLineText,
|
||||
@@ -2184,6 +2188,7 @@ export const useSettingsStore = defineStore("settings", () => {
|
||||
if (partial.tableOpenPageSize !== undefined) editorSettings.value.tableOpenPageSize = normalizeResultPageSize(partial.tableOpenPageSize, DEFAULT_EDITOR_SETTINGS.tableOpenPageSize);
|
||||
if (partial.queryResultMaxRowsEnabled !== undefined) editorSettings.value.queryResultMaxRowsEnabled = Boolean(partial.queryResultMaxRowsEnabled);
|
||||
if (partial.queryResultMaxRows !== undefined) editorSettings.value.queryResultMaxRows = normalizeQueryResultMaxRows(partial.queryResultMaxRows, editorSettings.value.queryResultMaxRows);
|
||||
if (partial.externalSqlEditorMaxMb !== undefined) editorSettings.value.externalSqlEditorMaxMb = normalizeExternalSqlEditorMaxMb(partial.externalSqlEditorMaxMb);
|
||||
if (partial.infiniteScroll !== undefined) editorSettings.value.infiniteScroll = partial.infiniteScroll;
|
||||
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;
|
||||
|
||||
Reference in new issue
Block a user