feat(sidebar): show connection note next to label with tight comment spacing

This commit is contained in:
t8y2 2026-08-06 02:10:27 +08:00
parent 67e6b3f32d
commit 9dbbfb4a06
No known key found for this signature in database
9 changed files with 37 additions and 17 deletions

View File

@ -4660,9 +4660,9 @@ onUnmounted(() => {
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="comment-inline">{{ t("settings.sidebarObjectInfoModeCommentInline") }}</SelectItem>
<SelectItem value="comment-aligned">{{ t("settings.sidebarObjectInfoModeCommentAligned") }}</SelectItem>
<SelectItem value="comment-right">{{ t("settings.sidebarObjectInfoModeCommentRight") }}</SelectItem>
<SelectItem value="comment-inline">{{ t("settings.sidebarObjectInfoModeCommentInline") }}</SelectItem>
<SelectItem value="size">{{ t("settings.sidebarObjectInfoModeSize") }}</SelectItem>
<SelectItem value="hidden">{{ t("settings.sidebarObjectInfoModeHidden") }}</SelectItem>
</SelectContent>

View File

@ -428,6 +428,7 @@ const detailTooltip = computed(() => {
{ label: t("connection.user"), value: cleanTooltipValue(config.username) },
{ label: t("connection.type"), value: config.driver_label || config.driver_profile || config.db_type },
{ label: t("connection.databaseInfo.productVersion"), value: cleanTooltipValue(config.database_info?.productVersion) },
{ label: t("connection.note"), value: cleanTooltipValue(config.note), multiline: true },
].filter((row) => row.value);
return { rows };
}
@ -612,7 +613,9 @@ function formattedObjectStorage(): string {
return formatSidebarObjectStorage(activeNode.value.sizeBytes);
}
const alignedCommentLabelWidth = computed(() => (settingsStore.editorSettings.sidebarObjectInfoMode === "comment-aligned" ? props.commentLabelWidth : undefined));
// aligned label
// aligned inline comment label
const alignedCommentLabelWidth = computed(() => (settingsStore.editorSettings.sidebarObjectInfoMode === "comment-aligned" && activeNode.value.type !== "connection" ? props.commentLabelWidth : undefined));
function alignedCommentLeadingStyle(): { width: string } | undefined {
const width = alignedCommentLeadingWidth(alignedCommentLabelWidth.value, canTreeNodePin(activeNode.value.type));
@ -627,7 +630,13 @@ const usesFullWidthLabel = computed(() => usesFullWidthTreeLabel(activeNode.valu
const rowWidthClass = computed(() => (usesFullWidthLabel.value ? "w-max min-w-full" : "w-full min-w-0"));
const labelWidthClass = computed(() => treeLabelWidthClass({ fullWidth: usesFullWidthLabel.value, hasTrailingComment: hasTrailingMetadata(), hasInlineAction: isPinned.value }));
const labelWidthClass = computed(() => {
// aligned leading comment label flex-1 leading
// inline/right leading label shrink comment label
// label flex-1 leading comment
const alignLeading = alignedCommentLabelWidth.value !== undefined;
return treeLabelWidthClass({ fullWidth: usesFullWidthLabel.value, hasTrailingComment: hasTrailingMetadata(), hasInlineAction: isPinned.value, alignLeading });
});
watch(() => [isRightAlignedComment(), visibleLabel(activeNode.value), trailingComment.value, trailingCommentLayoutRef.value, trailingCommentLeadingRef.value], refreshTrailingCommentMeasurement, { flush: "post", immediate: true });
@ -1151,7 +1160,7 @@ function onKeydown(event: KeyboardEvent) {
@keydown.escape.prevent="isRenamingGroup = false"
@click.stop
/>
<span v-else ref="labelRef" :class="[labelWidthClass, { 'flex-1': node.type === 'connection' }]">{{ visibleLabel(node) }}</span>
<span v-else ref="labelRef" :class="[labelWidthClass, { 'flex-1': node.type === 'connection' && !trailingComment }]">{{ visibleLabel(node) }}</span>
<button
v-if="canDragPinnedOrder()"
type="button"
@ -1186,7 +1195,7 @@ function onKeydown(event: KeyboardEvent) {
{{ t("editor.defaultDatabase") }}
</Badge>
</div>
<span v-if="trailingComment && !isRightAlignedComment()" class="sidebar-object-comment ml-2 min-w-0 flex-1 truncate text-left" :class="{ 'sidebar-object-comment--windows': useWindowsSidebarCommentFont }">{{ trailingComment }}</span>
<span v-if="trailingComment && !isRightAlignedComment()" class="sidebar-object-comment ml-4 min-w-0 flex-1 truncate text-left" :class="{ 'sidebar-object-comment--windows': useWindowsSidebarCommentFont }">{{ trailingComment }}</span>
<span v-if="isRightAlignedComment() && trailingCommentMaxWidth > 0" class="min-w-0 flex-1" aria-hidden="true" />
<span
v-if="isRightAlignedComment() && trailingCommentMaxWidth > 0"

View File

@ -7,8 +7,10 @@ describe("sidebar tree item layout", () => {
expect(usesFullWidthTreeLabel("table", true, true)).toBe(false);
});
it("lets a table name consume the available row width before truncating", () => {
expect(treeLabelWidthClass({ fullWidth: false, hasTrailingComment: true })).toBe("min-w-0 flex-1 truncate");
it("lets a table name consume the available row width before truncating when aligned", () => {
expect(treeLabelWidthClass({ fullWidth: false, hasTrailingComment: true, alignLeading: true })).toBe("min-w-0 flex-1 truncate");
// inline/right 模式 label 不撑满,让 comment 紧跟
expect(treeLabelWidthClass({ fullWidth: false, hasTrailingComment: true, alignLeading: false })).toBe("min-w-0 shrink truncate");
});
it("keeps a pinned action next to the name while preserving the aligned comment column", () => {

View File

@ -130,6 +130,8 @@ function makeConnectionNode(config: ConnectionConfig, pinned: boolean): TreeNode
isExpanded: false,
children: [],
pinned,
// 连接备注复用 TreeNode.comment 通道,侧边栏按 sidebarObjectInfoMode 渲染。
comment: config.note || null,
};
}

View File

@ -55,7 +55,7 @@ const pinnableTypes: Set<TreeNodeType> = new Set([
"nacos-namespace",
]);
const commentTypes: Set<TreeNodeType> = new Set(["schema", "table", "view", "materialized_view", "column", "mongo-collection", "vector-collection", "elasticsearch-index"]);
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`;
@ -140,10 +140,13 @@ export function usesFullWidthTreeLabel(type: TreeNodeType, allowHorizontalScroll
return allowHorizontalScroll && !hasTrailingComment && fullWidthLabelTypes.has(type);
}
export function treeLabelWidthClass({ fullWidth, hasTrailingComment, hasInlineAction = false }: { fullWidth: boolean; hasTrailingComment: boolean; hasInlineAction?: boolean }): string {
export function treeLabelWidthClass({ fullWidth, hasTrailingComment, hasInlineAction = false, alignLeading = false }: { fullWidth: boolean; hasTrailingComment: boolean; hasInlineAction?: boolean; alignLeading?: boolean }): string {
if (fullWidth) return "shrink-0 whitespace-nowrap";
if (hasTrailingComment && hasInlineAction) return "min-w-0 shrink truncate";
return hasTrailingComment ? "min-w-0 flex-1 truncate" : "min-w-0 truncate";
// aligned 模式靠 leading 块固定宽度对齐 comment 列label 需 flex-1 撑满 leading 块;
// inline/right 模式 label 用 shrink 让 comment 紧跟,避免 label 撑满把 comment 推到最右。
if (hasTrailingComment) return alignLeading ? "min-w-0 flex-1 truncate" : "min-w-0 shrink truncate";
return "min-w-0 truncate";
}
export function canTreeNodeExpand(type: TreeNodeType): boolean {

View File

@ -21,19 +21,19 @@ describe("normalizeEditorSettings", () => {
expect(normalizeEditorSettings({ regexMaxMatchCount: Number.POSITIVE_INFINITY }).regexMaxMatchCount).toBe(1000);
expect(normalizeEditorSettings({ regexMaxMatchCount: Number.NaN }).regexMaxMatchCount).toBe(1000);
});
it("uses aligned comments by default and preserves legacy comment visibility", () => {
expect(normalizeEditorSettings({}).sidebarObjectInfoMode).toBe("comment-aligned");
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");
expect(normalizeEditorSettings({ sidebarObjectInfoMode: "comment-inline" }).sidebarObjectInfoMode).toBe("comment-inline");
expect(normalizeEditorSettings({ sidebarObjectInfoMode: "comment-right" }).sidebarObjectInfoMode).toBe("comment-right");
expect(normalizeEditorSettings({ sidebarObjectInfoMode: "size" }).sidebarObjectInfoMode).toBe("size");
expect(normalizeEditorSettings({ sidebarTableCommentLayout: "aligned" } as any).sidebarObjectInfoMode).toBe("comment-aligned");
expect(normalizeEditorSettings({ sidebarTableCommentLayout: "hidden" } as any).sidebarObjectInfoMode).toBe("hidden");
expect(normalizeEditorSettings({ sidebarHideTableComments: false } as any).sidebarObjectInfoMode).toBe("comment-aligned");
expect(normalizeEditorSettings({ sidebarHideTableComments: false } as any).sidebarObjectInfoMode).toBe("comment-inline");
expect(normalizeEditorSettings({ sidebarHideTableComments: true } as any).sidebarObjectInfoMode).toBe("hidden");
expect(normalizeEditorSettings({ sidebarHideTableComments: true, sidebarShowDatabaseSizes: true } as any).sidebarObjectInfoMode).toBe("hidden");
expect(normalizeEditorSettings({ sidebarShowDatabaseSizes: true } as any).sidebarObjectInfoMode).toBe("size");
expect(normalizeEditorSettings({ sidebarObjectInfoMode: "invalid" } as any).sidebarObjectInfoMode).toBe("comment-aligned");
expect(normalizeEditorSettings({ sidebarObjectInfoMode: "invalid" } as any).sidebarObjectInfoMode).toBe("comment-inline");
});
it("defaults SQL execution to the current statement and migrates legacy execute-all settings", () => {

View File

@ -2698,6 +2698,7 @@ export const useConnectionStore = defineStore("connection", () => {
existing.label = config.name;
existing.type = "connection";
existing.connectionId = id;
existing.comment = config.note || null;
existing.children = existing.children || [];
} else {
treeNodes.value.push({
@ -2707,6 +2708,7 @@ export const useConnectionStore = defineStore("connection", () => {
connectionId: id,
isExpanded: false,
children: [],
comment: config.note || null,
});
}
return id;

View File

@ -684,7 +684,7 @@ export const DEFAULT_EDITOR_SETTINGS: EditorSettings = {
prefillNewQueryWithSelect: true,
updateNotificationsEnabled: true,
sidebarHiddenTablePrefixes: [],
sidebarObjectInfoMode: "comment-aligned",
sidebarObjectInfoMode: "comment-inline",
sidebarAllowHorizontalScroll: false,
columnFormatters: {},
customColumnFormatters: {},

View File

@ -14,8 +14,10 @@ test("Nacos namespace rows can show the pin action", () => {
assert.equal(canTreeNodePin("nacos-namespace"), true);
});
test("labels with trailing comments consume the available row width", () => {
assert.equal(treeLabelWidthClass({ fullWidth: false, hasTrailingComment: true }), "min-w-0 flex-1 truncate");
test("labels with trailing comments consume the available row width when aligned", () => {
assert.equal(treeLabelWidthClass({ fullWidth: false, hasTrailingComment: true, alignLeading: true }), "min-w-0 flex-1 truncate");
// inline/right 模式 label 不撑满,让 comment 紧跟
assert.equal(treeLabelWidthClass({ fullWidth: false, hasTrailingComment: true, alignLeading: false }), "min-w-0 shrink truncate");
assert.equal(treeLabelWidthClass({ fullWidth: false, hasTrailingComment: false }), "min-w-0 truncate");
});