feat(sidebar): add indentation and font size settings

This commit is contained in:
Domye authored and GitHub committed 2026-08-15 14:44:35 +08:00
1 parent 98df975614
commit 745483cd6c
16 files changed
+164 -13

No files matched your search

@@ -47,6 +47,10 @@ import {
type CustomTheme,
type ClickTableNavigationTarget,
type SqlCompletionTriggerMode,
SIDEBAR_INDENT_MIN,
SIDEBAR_INDENT_MAX,
SIDEBAR_FONT_SIZE_MIN,
SIDEBAR_FONT_SIZE_MAX,
} from "@/stores/settingsStore";
import { createRunStatementButtonDom, loadEditorTheme, editorFontTheme } from "@/lib/editor/editorThemes";
import { orderAiConfigsForDisplay } from "@/lib/ai/aiConfigOrdering";
@@ -406,6 +410,8 @@ const editUpdateNotificationsEnabled = ref(settingsStore.editorSettings.updateNo
const editSidebarHiddenTablePrefixes = ref(settingsStore.editorSettings.sidebarHiddenTablePrefixes.join("\n"));
const editSidebarObjectInfoMode = ref<SidebarObjectInfoMode>(settingsStore.editorSettings.sidebarObjectInfoMode);
const editSidebarAllowHorizontalScroll = ref(settingsStore.editorSettings.sidebarAllowHorizontalScroll);
const editSidebarIndent = ref(settingsStore.editorSettings.sidebarIndent);
const editSidebarFontSize = ref(settingsStore.editorSettings.sidebarFontSize);
const editExportBatchSize = ref(settingsStore.editorSettings.exportBatchSize);
const editGlobalDateTimeDisplayFormat = ref(settingsStore.editorSettings.globalDateTimeDisplayFormat);
const editGlobalDateTimeExportFormat = ref(settingsStore.editorSettings.globalDateTimeExportFormat);
@@ -526,6 +532,8 @@ function currentEditorSettingsDraft(): EditorSettingsDraft {
updateNotificationsEnabled: editUpdateNotificationsEnabled.value,
sidebarObjectInfoMode: editSidebarObjectInfoMode.value,
sidebarAllowHorizontalScroll: editSidebarAllowHorizontalScroll.value,
sidebarIndent: editSidebarIndent.value,
sidebarFontSize: editSidebarFontSize.value,
sidebarHiddenTablePrefixes: normalizeSidebarHiddenTablePrefixes(editSidebarHiddenTablePrefixes.value),
exportBatchSize: editExportBatchSize.value,
globalDateTimeDisplayFormat: editGlobalDateTimeDisplayFormat.value,
@@ -808,6 +816,8 @@ function syncEditorSettingsDraftFromStore() {
editSidebarHiddenTablePrefixes.value = settingsStore.editorSettings.sidebarHiddenTablePrefixes.join("\n");
editSidebarObjectInfoMode.value = settingsStore.editorSettings.sidebarObjectInfoMode;
editSidebarAllowHorizontalScroll.value = settingsStore.editorSettings.sidebarAllowHorizontalScroll;
editSidebarIndent.value = settingsStore.editorSettings.sidebarIndent;
editSidebarFontSize.value = settingsStore.editorSettings.sidebarFontSize;
editExportBatchSize.value = settingsStore.editorSettings.exportBatchSize;
editGlobalDateTimeDisplayFormat.value = settingsStore.editorSettings.globalDateTimeDisplayFormat;
editGlobalDateTimeExportFormat.value = settingsStore.editorSettings.globalDateTimeExportFormat;
@@ -1023,6 +1033,8 @@ function resetDefaultsForTab(tab: SettingsCategory) {
editUpdateNotificationsEnabled.value = DEFAULT_EDITOR_SETTINGS.updateNotificationsEnabled;
editSidebarObjectInfoMode.value = DEFAULT_EDITOR_SETTINGS.sidebarObjectInfoMode;
editSidebarAllowHorizontalScroll.value = DEFAULT_EDITOR_SETTINGS.sidebarAllowHorizontalScroll;
editSidebarIndent.value = DEFAULT_EDITOR_SETTINGS.sidebarIndent;
editSidebarFontSize.value = DEFAULT_EDITOR_SETTINGS.sidebarFontSize;
editSidebarHiddenTablePrefixes.value = DEFAULT_EDITOR_SETTINGS.sidebarHiddenTablePrefixes.join("\n");
editToolbarItems.value = { ...DEFAULT_EDITOR_SETTINGS.toolbarItems };
} else if (tab === "data") {
@@ -1132,6 +1144,8 @@ function resetAllDefaults() {
editUpdateNotificationsEnabled.value = DEFAULT_EDITOR_SETTINGS.updateNotificationsEnabled;
editSidebarObjectInfoMode.value = DEFAULT_EDITOR_SETTINGS.sidebarObjectInfoMode;
editSidebarAllowHorizontalScroll.value = DEFAULT_EDITOR_SETTINGS.sidebarAllowHorizontalScroll;
editSidebarIndent.value = DEFAULT_EDITOR_SETTINGS.sidebarIndent;
editSidebarFontSize.value = DEFAULT_EDITOR_SETTINGS.sidebarFontSize;
editSidebarHiddenTablePrefixes.value = DEFAULT_EDITOR_SETTINGS.sidebarHiddenTablePrefixes.join("\n");
editExportBatchSize.value = DEFAULT_EDITOR_SETTINGS.exportBatchSize;
editGlobalDateTimeDisplayFormat.value = DEFAULT_EDITOR_SETTINGS.globalDateTimeDisplayFormat;
@@ -4751,6 +4765,52 @@ onUnmounted(() => {
</div>
<Switch id="sidebar-allow-horizontal-scroll" v-model="editSidebarAllowHorizontalScroll" />
</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="sidebar-indent">{{ t("settings.sidebarIndent") }}</Label>
<p class="text-xs text-muted-foreground">
{{ t("settings.sidebarIndentDescription") }}
</p>
</div>
<Input
id="sidebar-indent"
type="number"
class="w-24 text-right"
:min="SIDEBAR_INDENT_MIN"
:max="SIDEBAR_INDENT_MAX"
:step="2"
:model-value="editSidebarIndent"
@update:model-value="
(value: string | number) => {
const n = typeof value === 'string' ? parseInt(value) : value;
if (!isNaN(n)) editSidebarIndent = n;
}
"
/>
</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="sidebar-font-size">{{ t("settings.sidebarFontSize") }}</Label>
<p class="text-xs text-muted-foreground">
{{ t("settings.sidebarFontSizeDescription") }}
</p>
</div>
<Input
id="sidebar-font-size"
type="number"
class="w-24 text-right"
:min="SIDEBAR_FONT_SIZE_MIN"
:max="SIDEBAR_FONT_SIZE_MAX"
:step="1"
:model-value="editSidebarFontSize"
@update:model-value="
(value: string | number) => {
const n = typeof value === 'string' ? parseInt(value) : value;
if (!isNaN(n)) editSidebarFontSize = n;
}
"
/>
</div>
<div class="space-y-2">
<Label for="sidebar-hidden-table-prefixes">{{ t("settings.sidebarHiddenTablePrefixes") }}</Label>
<textarea
@@ -82,6 +82,7 @@ const showConnectedConnectionsOnly = ref(false);
const isDisconnectingAllActiveConnections = ref(false);
const searchInputRef = ref<HTMLInputElement>();
const rootRef = ref<HTMLElement>();
const sidebarRootStyle = computed<Record<string, string>>(() => ({ fontSize: `${settingsStore.editorSettings.sidebarFontSize}px` }));
const pointerInsideTree = ref(false);
const treeScrollerRef = ref<InstanceType<typeof RecycleScroller> | null>(null);
const plainTreeScrollerRef = ref<HTMLElement | null>(null);
@@ -691,7 +692,7 @@ function measureSidebarTreeContentWidth() {
if (!context) return;
const style = window.getComputedStyle(rootRef.value);
context.font = style.font || `${style.fontWeight} ${style.fontSize} ${style.fontFamily}`;
sidebarTreeContentWidth.value = sidebarTreeNaturalContentWidth(sidebarTreeNaturalWidthItems.value, (text) => context.measureText(text).width);
sidebarTreeContentWidth.value = sidebarTreeNaturalContentWidth(sidebarTreeNaturalWidthItems.value, (text) => context.measureText(text).width, settingsStore.editorSettings.sidebarIndent);
void nextTick(scheduleSidebarScrollMetricsUpdate);
}
@@ -705,7 +706,15 @@ function scheduleSidebarTreeContentWidthMeasure() {
}
watch(
[flatNodes, () => settingsStore.editorSettings.sidebarObjectInfoMode, () => settingsStore.editorSettings.sidebarShowConnectionNotes, () => settingsStore.editorSettings.sidebarHiddenTablePrefixes, () => settingsStore.editorSettings.uiFontFamily, () => settingsStore.editorSettings.uiScale],
[
flatNodes,
() => settingsStore.editorSettings.sidebarObjectInfoMode,
() => settingsStore.editorSettings.sidebarShowConnectionNotes,
() => settingsStore.editorSettings.sidebarHiddenTablePrefixes,
() => settingsStore.editorSettings.uiFontFamily,
() => settingsStore.editorSettings.uiScale,
() => settingsStore.editorSettings.sidebarFontSize,
],
scheduleSidebarCommentLabelMeasure,
{
flush: "post",
@@ -713,7 +722,7 @@ watch(
},
);
watch([sidebarTreeNaturalWidthItems, () => settingsStore.editorSettings.uiFontFamily, () => settingsStore.editorSettings.uiScale], scheduleSidebarTreeContentWidthMeasure, {
watch([sidebarTreeNaturalWidthItems, () => settingsStore.editorSettings.uiFontFamily, () => settingsStore.editorSettings.uiScale, () => settingsStore.editorSettings.sidebarIndent, () => settingsStore.editorSettings.sidebarFontSize], scheduleSidebarTreeContentWidthMeasure, {
flush: "post",
immediate: true,
});
@@ -1988,7 +1997,7 @@ defineExpose({ focusSearch, createNewGroup, collapseAllTreeNodes });
</script>
<template>
<div ref="rootRef" class="h-full min-h-0 flex flex-col text-sm select-none" @pointerenter="pointerInsideTree = true" @pointerleave="pointerInsideTree = false">
<div ref="rootRef" class="h-full min-h-0 flex flex-col select-none" :style="sidebarRootStyle" @pointerenter="pointerInsideTree = true" @pointerleave="pointerInsideTree = false">
<SidebarTreeRuntimeHost
:ref="bindSidebarTreeRuntimeHost"
:node="sidebarTreeRuntimeInitialNode"
@@ -742,7 +742,7 @@ const labelWidthClass = computed(() => {
watch(() => [isRightAlignedComment(), visibleLabel(activeNode.value), trailingComment.value, trailingCommentLayoutRef.value, trailingCommentLeadingRef.value], refreshTrailingCommentMeasurement, { flush: "post", immediate: true });
const paddingLeft = computed(() => treeItemPaddingLeft(props.depth));
const paddingLeft = computed(() => treeItemPaddingLeft(props.depth, settingsStore.editorSettings.sidebarIndent));
const tableSearchParentId = computed(() => activeNode.value.tableSearchParentId || "");
@@ -1424,8 +1424,9 @@ function onKeydown(event: KeyboardEvent) {
<style>
.sidebar-object-comment {
color: var(--muted-foreground);
font-size: 12px;
line-height: 1rem;
/* Relative to the sidebar tree root font size so comments follow the sidebarFontSize setting. */
font-size: 0.85em;
line-height: 1.25;
opacity: 0.6;
/* Sidebar rows repaint on hover; avoid heavier font shaping and fallback here. */
text-rendering: auto;
@@ -1439,7 +1440,7 @@ function onKeydown(event: KeyboardEvent) {
.sidebar-object-comment--windows {
font-family: "Microsoft YaHei UI", "Microsoft YaHei", "Segoe UI", system-ui, sans-serif;
font-size: 14px;
font-size: 1em;
font-weight: 500;
opacity: 1;
}
+4
View File
@@ -5838,6 +5838,10 @@ export default {
sidebarObjectInfoModeHidden: "None",
sidebarAllowHorizontalScroll: "Allow sidebar horizontal scroll",
sidebarAllowHorizontalScrollDescription: "Show long table, view, and collection names in full by allowing horizontal sidebar scrolling.",
sidebarIndent: "Sidebar indentation",
sidebarIndentDescription: "Horizontal offset added per tree depth level, in pixels.",
sidebarFontSize: "Sidebar font size",
sidebarFontSizeDescription: "Font size for the sidebar object tree, in pixels. Independent of the editor font size.",
snippetsDescription: "Customize SQL snippet templates triggered in the editor.",
snippetsAdd: "Add Snippet",
snippetsLabel: "Label",
+4
View File
@@ -5988,6 +5988,10 @@ export default withEnglishFallback({
syncSnippetMigrateLegacyCleanupRequired: "Se creó el fragmento cifrado, pero no se pudo eliminar el fragmento heredado {id}. Elimínelo manualmente y rote las credenciales que podrían haberse expuesto.",
syncSnippetRetryLegacyCleanup: "Reintentar limpieza heredada",
syncSnippetLegacyCleanupSuccess: "Se eliminó el fragmento heredado de texto sin formato {id}.",
sidebarIndent: "Sangría de la barra lateral",
sidebarIndentDescription: "Desplazamiento en píxeles de la sangría para cada nivel del árbol.",
sidebarFontSize: "Tamaño de fuente de la barra lateral",
sidebarFontSizeDescription: "Tamaño de fuente (en píxeles) del árbol de objetos de la barra lateral, independiente del tamaño de fuente del editor.",
},
driverStore: {
jreDirRemoveFailed: "No se pudo eliminar el directorio JRE antiguo: {path} (error original: {error})",
+4
View File
@@ -5988,6 +5988,10 @@ export default withEnglishFallback({
syncSnippetMigrateLegacyCleanupRequired: "Lo snippet crittografato è stato creato, ma non è stato possibile eliminare lo snippet legacy {id}. Eliminalo manualmente e ruota le credenziali che potrebbero essere state esposte.",
syncSnippetRetryLegacyCleanup: "Riprova pulizia legacy",
syncSnippetLegacyCleanupSuccess: "Lo snippet legacy in testo semplice {id} è stato eliminato.",
sidebarIndent: "Indentazione della barra laterale",
sidebarIndentDescription: "Offset in pixel per l'indentazione di ogni livello dell'albero.",
sidebarFontSize: "Dimensione del carattere della barra laterale",
sidebarFontSizeDescription: "Dimensione del carattere (in pixel) per l'albero degli oggetti della barra laterale, indipendente dalla dimensione del carattere dell'editor.",
},
driverStore: {
jreDirRemoveFailed: "Impossibile rimuovere la vecchia directory JRE: {path} (errore originale: {error})",
+4
View File
@@ -6041,6 +6041,10 @@ export default withEnglishFallback({
completionTriggerModeManual: "手動のみ",
completionTriggerModeRequirePrefix: "識別子入力後",
completionTriggerModePositional: "スマート位置",
sidebarIndent: "サイドバーのインデント",
sidebarIndentDescription: "各ツリー階層のインデントのピクセルオフセット。",
sidebarFontSize: "サイドバーのフォントサイズ",
sidebarFontSizeDescription: "サイドバーのオブジェクトツリーのフォントサイズ(ピクセル)。エディターのフォントサイズとは独立しています。",
},
driverStore: {
jreDirRemoveFailed: "古い JRE ディレクトリを削除できませんでした: {path}(元のエラー: {error})",
+4
View File
@@ -5990,6 +5990,10 @@ export default withEnglishFallback({
syncSnippetMigrateLegacyCleanupRequired: "O snippet criptografado foi criado, mas não foi possível excluir o snippet legado {id}. Exclua-o manualmente e altere as credenciais que possam ter sido expostas.",
syncSnippetRetryLegacyCleanup: "Tentar limpeza legada novamente",
syncSnippetLegacyCleanupSuccess: "O snippet legado em texto simples {id} foi removido.",
sidebarIndent: "Indentação da barra lateral",
sidebarIndentDescription: "O deslocamento em pixels da indentação para cada nível da árvore.",
sidebarFontSize: "Tamanho da fonte da barra lateral",
sidebarFontSizeDescription: "Tamanho da fonte (em pixels) da árvore de objetos da barra lateral, independente do tamanho da fonte do editor.",
},
driverStore: {
jreDirRemoveFailed: "Não foi possível remover o diretório JRE antigo: {path} (erro original: {error})",
+4
View File
@@ -5824,6 +5824,10 @@ export default withEnglishFallback({
sidebarObjectInfoModeHidden: "不显示",
sidebarAllowHorizontalScroll: "允许侧边栏横向滚动",
sidebarAllowHorizontalScrollDescription: "完整显示较长的表、视图和集合名称;默认关闭以保留省略号截断。",
sidebarIndent: "侧边栏缩进",
sidebarIndentDescription: "每个树层级缩进的像素偏移量。",
sidebarFontSize: "侧边栏字体大小",
sidebarFontSizeDescription: "侧边栏对象树的字体大小(像素),独立于编辑器字体大小。",
snippetsDescription: "自定义编辑器中触发的 SQL 代码片段模板。",
snippetsAdd: "添加片段",
snippetsLabel: "显示名",
+4
View File
@@ -5328,6 +5328,10 @@ export default withEnglishFallback({
syncSnippetMigrateLegacyCleanupRequired: "已建立加密程式碼片段,但無法刪除舊程式碼片段 {id}。請手動刪除它,並輪換可能已暴露的憑據。",
syncSnippetRetryLegacyCleanup: "重試清理舊版程式碼片段",
syncSnippetLegacyCleanupSuccess: "已刪除舊版純文字程式碼片段 {id}。",
sidebarIndent: "側邊欄縮排",
sidebarIndentDescription: "每個樹層級縮排的像素位移量。",
sidebarFontSize: "側邊欄字型大小",
sidebarFontSizeDescription: "側邊欄物件樹的字型大小(像素),獨立於編輯器字型大小。",
},
driverStore: {
jreDirRemoveFailed: "無法刪除舊的 JRE 目錄:{path}(原始錯誤:{error})",
@@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest";
import { alignedCommentLeadingWidth, alignedSidebarCommentLabelWidths, canTreeNodeShowExpander, sidebarTreeNaturalContentWidth, sidebarTreeNodeComment, trailingCommentAvailableWidth, treeLabelWidthClass, usesFullWidthTreeLabel } from "@/lib/sidebar/sidebarTreeItemLayout";
import { alignedCommentLeadingWidth, alignedSidebarCommentLabelWidths, canTreeNodeShowExpander, sidebarTreeNaturalContentWidth, sidebarTreeNodeComment, trailingCommentAvailableWidth, treeItemPaddingLeft, treeLabelWidthClass, usesFullWidthTreeLabel } from "@/lib/sidebar/sidebarTreeItemLayout";
import type { TreeNode } from "@/types/database";
describe("sidebar tree item layout", () => {
@@ -91,4 +91,16 @@ describe("sidebar tree item layout", () => {
it("returns zero when no tree row uses natural width", () => {
expect(sidebarTreeNaturalContentWidth([{ depth: 2, label: "commented", usesNaturalWidth: false }], (text) => text.length * 7)).toBe(0);
});
it("applies a configurable per-depth indent to rows and natural-width measurement", () => {
// Default keeps the historical 16px per level.
expect(treeItemPaddingLeft(2)).toBe("40px");
expect(treeItemPaddingLeft(2, 24)).toBe("56px");
expect(treeItemPaddingLeft(0, 24)).toBe("8px");
const items = [{ depth: 4, label: "nested", usesNaturalWidth: true, trailingWidth: 20 }];
const measure = (text: string) => text.length * 7;
expect(sidebarTreeNaturalContentWidth(items, measure, 16)).toBe(4 * 16 + 8 + 54 + "nested".length * 7 + 20);
expect(sidebarTreeNaturalContentWidth(items, measure, 32)).toBe(4 * 32 + 8 + 54 + "nested".length * 7 + 20);
});
});
@@ -63,6 +63,8 @@ export const EDITOR_SETTINGS_DRAFT_KEYS = [
"updateNotificationsEnabled",
"sidebarObjectInfoMode",
"sidebarAllowHorizontalScroll",
"sidebarIndent",
"sidebarFontSize",
"sidebarHiddenTablePrefixes",
"exportBatchSize",
"exportRowLimitEnabled",
@@ -167,6 +167,8 @@ export const SETTINGS_SEARCH_DEFINITIONS: readonly SettingsSearchDefinition[] =
{ id: "navigation-open-database-on-single-click", category: "navigation", titleKey: "settings.sidebarOpenDatabaseOnSingleClick", descriptionKey: "settings.sidebarOpenDatabaseOnSingleClickDescription", targetId: "navigation" },
{ id: "navigation-tabs-restore", category: "navigation", titleKey: "settings.openTabsRestoreMode", descriptionKey: "settings.openTabsRestoreModeDescription", targetId: "navigation" },
{ id: "navigation-sidebar-scroll", category: "navigation", titleKey: "settings.sidebarAllowHorizontalScroll", descriptionKey: "settings.sidebarAllowHorizontalScrollDescription", targetId: "navigation" },
{ id: "navigation-sidebar-indent", category: "navigation", titleKey: "settings.sidebarIndent", descriptionKey: "settings.sidebarIndentDescription", targetId: "navigation" },
{ id: "navigation-sidebar-font-size", category: "navigation", titleKey: "settings.sidebarFontSize", descriptionKey: "settings.sidebarFontSizeDescription", targetId: "navigation" },
{ id: "navigation-hidden-tables", category: "navigation", titleKey: "settings.sidebarHiddenTablePrefixes", descriptionKey: "settings.sidebarHiddenTablePrefixesDescription", targetId: "navigation" },
{ id: "navigation-table-page-size", category: "navigation", titleKey: "settings.sidebarTablePageSize", descriptionKey: "settings.sidebarTablePageSizeDescription", targetId: "navigation" },
{ id: "navigation-disconnect-tabs", category: "navigation", titleKey: "settings.disconnectTabHandlingMode", descriptionKey: "settings.disconnectTabHandlingModeDescription", targetId: "navigation" },
@@ -63,8 +63,10 @@ const pinnableTypes: Set<TreeNodeType> = new Set([
const commentTypes: Set<TreeNodeType> = new Set(["connection", "schema", "table", "view", "materialized_view", "column", "mongo-collection", "vector-collection", "elasticsearch-index"]);
export function treeItemPaddingLeft(depth: number): string {
return `${depth * 16 + 8}px`;
export const SIDEBAR_INDENT_DEFAULT_PX = 16;
export function treeItemPaddingLeft(depth: number, indentPx = SIDEBAR_INDENT_DEFAULT_PX): string {
return `${depth * indentPx + 8}px`;
}
export const trailingCommentGapPx = 8;
@@ -97,11 +99,11 @@ export interface SidebarTreeNaturalWidthItem {
// Right padding, expander/icon widths and the two flex gaps before the label.
const sidebarTreeRowChromeWidth = 54;
export function sidebarTreeNaturalContentWidth(items: readonly SidebarTreeNaturalWidthItem[], measureText: (text: string) => number): number {
export function sidebarTreeNaturalContentWidth(items: readonly SidebarTreeNaturalWidthItem[], measureText: (text: string) => number, indentPx = SIDEBAR_INDENT_DEFAULT_PX): number {
let width = 0;
for (const item of items) {
if (!item.usesNaturalWidth) continue;
const paddingLeft = item.depth * 16 + 8;
const paddingLeft = item.depth * indentPx + 8;
width = Math.max(width, Math.ceil(paddingLeft + sidebarTreeRowChromeWidth + measureText(item.label) + (item.trailingWidth ?? 0)));
}
return width;
+11
View File
@@ -43,6 +43,17 @@ describe("normalizeEditorSettings", () => {
expect(normalizeEditorSettings({ regexMaxMatchCount: Number.POSITIVE_INFINITY }).regexMaxMatchCount).toBe(1000);
expect(normalizeEditorSettings({ regexMaxMatchCount: Number.NaN }).regexMaxMatchCount).toBe(1000);
});
it("defaults and bounds the sidebar indent and font size", () => {
expect(normalizeEditorSettings({}).sidebarIndent).toBe(16);
expect(normalizeEditorSettings({}).sidebarFontSize).toBe(14);
expect(normalizeEditorSettings({ sidebarIndent: 24, sidebarFontSize: 18 }).sidebarIndent).toBe(24);
expect(normalizeEditorSettings({ sidebarIndent: 24, sidebarFontSize: 18 }).sidebarFontSize).toBe(18);
expect(normalizeEditorSettings({ sidebarIndent: 999, sidebarFontSize: 1 } as any).sidebarIndent).toBe(32);
expect(normalizeEditorSettings({ sidebarIndent: 999, sidebarFontSize: 1 } as any).sidebarFontSize).toBe(9);
expect(normalizeEditorSettings({ sidebarIndent: 1.4, sidebarFontSize: 13.6 } as any).sidebarIndent).toBe(4);
expect(normalizeEditorSettings({ sidebarIndent: 1.4, sidebarFontSize: 13.6 } as any).sidebarFontSize).toBe(14);
});
it("uses inline comments by default and preserves legacy comment visibility", () => {
expect(normalizeEditorSettings({}).sidebarObjectInfoMode).toBe("comment-inline");
expect(normalizeEditorSettings({ sidebarObjectInfoMode: "comment-aligned" }).sidebarObjectInfoMode).toBe("comment-aligned");
+24
View File
@@ -418,6 +418,12 @@ export type ResultRunDisplayMode = (typeof RESULT_RUN_DISPLAY_MODES)[number];
export const TABLE_FONT_SIZE_MIN = 8;
export const TABLE_FONT_SIZE_MAX = 16;
export const TABLE_FONT_SIZE_DEFAULT = 13;
export const SIDEBAR_FONT_SIZE_MIN = 9;
export const SIDEBAR_FONT_SIZE_MAX = 24;
export const SIDEBAR_FONT_SIZE_DEFAULT = 14;
export const SIDEBAR_INDENT_MIN = 4;
export const SIDEBAR_INDENT_MAX = 32;
export const SIDEBAR_INDENT_DEFAULT = 16;
const DISCONNECT_TAB_HANDLING_MODES = ["close-tabs", "keep-tabs-clear-results", "keep-tabs-keep-results"] as const;
export type DisconnectTabHandlingMode = (typeof DISCONNECT_TAB_HANDLING_MODES)[number];
@@ -587,6 +593,8 @@ export interface EditorSettings {
sidebarObjectInfoMode: SidebarObjectInfoMode;
sidebarShowConnectionNotes: boolean;
sidebarAllowHorizontalScroll: boolean;
sidebarIndent: number;
sidebarFontSize: number;
columnFormatters: Record<string, ColumnFormatterConfig>;
customColumnFormatters: Record<string, CustomColumnFormatterConfig>;
globalDateTimeDisplayFormat: string;
@@ -786,6 +794,8 @@ export const DEFAULT_EDITOR_SETTINGS: EditorSettings = {
sidebarObjectInfoMode: "comment-inline",
sidebarShowConnectionNotes: false,
sidebarAllowHorizontalScroll: false,
sidebarIndent: SIDEBAR_INDENT_DEFAULT,
sidebarFontSize: SIDEBAR_FONT_SIZE_DEFAULT,
columnFormatters: {},
customColumnFormatters: {},
globalDateTimeDisplayFormat: "",
@@ -872,6 +882,16 @@ function normalizeTableFontSize(value: unknown): number {
return Math.min(TABLE_FONT_SIZE_MAX, Math.max(TABLE_FONT_SIZE_MIN, Math.round(value)));
}
function normalizeSidebarFontSize(value: unknown): number {
if (typeof value !== "number" || !Number.isFinite(value)) return SIDEBAR_FONT_SIZE_DEFAULT;
return Math.min(SIDEBAR_FONT_SIZE_MAX, Math.max(SIDEBAR_FONT_SIZE_MIN, Math.round(value)));
}
function normalizeSidebarIndent(value: unknown): number {
if (typeof value !== "number" || !Number.isFinite(value)) return SIDEBAR_INDENT_DEFAULT;
return Math.min(SIDEBAR_INDENT_MAX, Math.max(SIDEBAR_INDENT_MIN, Math.round(value)));
}
function normalizeUpdateDownloadSource(value: unknown): UpdateDownloadSource {
// Preserve the intent of users who previously selected the mainland-China mirror.
if (value === "atomgit") return "cnb";
@@ -1168,6 +1188,8 @@ export function normalizeEditorSettings(settings: Partial<EditorSettings>, exist
),
sidebarShowConnectionNotes: settings.sidebarShowConnectionNotes === true,
sidebarAllowHorizontalScroll: settings.sidebarAllowHorizontalScroll ?? DEFAULT_EDITOR_SETTINGS.sidebarAllowHorizontalScroll,
sidebarIndent: normalizeSidebarIndent(settings.sidebarIndent),
sidebarFontSize: normalizeSidebarFontSize(settings.sidebarFontSize),
columnFormatters: normalizeColumnFormatters(settings.columnFormatters),
customColumnFormatters: normalizeCustomColumnFormatters(settings.customColumnFormatters),
globalDateTimeDisplayFormat: normalizeGlobalDateTimePattern(settings.globalDateTimeDisplayFormat),
@@ -1712,6 +1734,8 @@ export const useSettingsStore = defineStore("settings", () => {
if (partial.sidebarObjectInfoMode !== undefined) editorSettings.value.sidebarObjectInfoMode = normalizeSidebarObjectInfoMode(partial.sidebarObjectInfoMode);
if (partial.sidebarShowConnectionNotes !== undefined) editorSettings.value.sidebarShowConnectionNotes = partial.sidebarShowConnectionNotes === true;
if (partial.sidebarAllowHorizontalScroll !== undefined) editorSettings.value.sidebarAllowHorizontalScroll = partial.sidebarAllowHorizontalScroll;
if (partial.sidebarIndent !== undefined) editorSettings.value.sidebarIndent = normalizeSidebarIndent(partial.sidebarIndent);
if (partial.sidebarFontSize !== undefined) editorSettings.value.sidebarFontSize = normalizeSidebarFontSize(partial.sidebarFontSize);
if (partial.columnFormatters !== undefined) editorSettings.value.columnFormatters = partial.columnFormatters;
if (partial.customColumnFormatters !== undefined) editorSettings.value.customColumnFormatters = partial.customColumnFormatters;
if (partial.globalDateTimeDisplayFormat !== undefined) editorSettings.value.globalDateTimeDisplayFormat = normalizeGlobalDateTimePattern(partial.globalDateTimeDisplayFormat);