feat(sidebar): add configurable object metadata display
This commit is contained in:
29 files changed
+889
-143
No files matched your search
@@ -39,6 +39,7 @@ import {
|
||||
type InterfaceLayout,
|
||||
type DisconnectTabHandlingMode,
|
||||
type OpenTabsRestoreMode,
|
||||
type SidebarObjectInfoMode,
|
||||
type SqlSemanticDiagnosticsMode,
|
||||
type UpdateDownloadSource,
|
||||
type CustomThemeColors,
|
||||
@@ -356,7 +357,7 @@ const editReuseDataTab = ref(settingsStore.editorSettings.reuseDataTab);
|
||||
const editPrefillNewQueryWithSelect = ref(settingsStore.editorSettings.prefillNewQueryWithSelect);
|
||||
const editUpdateNotificationsEnabled = ref(settingsStore.editorSettings.updateNotificationsEnabled);
|
||||
const editSidebarHiddenTablePrefixes = ref(settingsStore.editorSettings.sidebarHiddenTablePrefixes.join("\n"));
|
||||
const editSidebarHideTableComments = ref(settingsStore.editorSettings.sidebarHideTableComments);
|
||||
const editSidebarObjectInfoMode = ref<SidebarObjectInfoMode>(settingsStore.editorSettings.sidebarObjectInfoMode);
|
||||
const editSidebarAllowHorizontalScroll = ref(settingsStore.editorSettings.sidebarAllowHorizontalScroll);
|
||||
const editExportBatchSize = ref(settingsStore.editorSettings.exportBatchSize);
|
||||
const editGlobalDateTimeDisplayFormat = ref(settingsStore.editorSettings.globalDateTimeDisplayFormat);
|
||||
@@ -456,7 +457,7 @@ function currentEditorSettingsDraft(): EditorSettingsDraft {
|
||||
reuseDataTab: editReuseDataTab.value,
|
||||
prefillNewQueryWithSelect: editPrefillNewQueryWithSelect.value,
|
||||
updateNotificationsEnabled: editUpdateNotificationsEnabled.value,
|
||||
sidebarHideTableComments: editSidebarHideTableComments.value,
|
||||
sidebarObjectInfoMode: editSidebarObjectInfoMode.value,
|
||||
sidebarAllowHorizontalScroll: editSidebarAllowHorizontalScroll.value,
|
||||
sidebarHiddenTablePrefixes: normalizeSidebarHiddenTablePrefixes(editSidebarHiddenTablePrefixes.value),
|
||||
exportBatchSize: editExportBatchSize.value,
|
||||
@@ -709,7 +710,7 @@ function syncEditorSettingsDraftFromStore() {
|
||||
editPrefillNewQueryWithSelect.value = settingsStore.editorSettings.prefillNewQueryWithSelect;
|
||||
editUpdateNotificationsEnabled.value = settingsStore.editorSettings.updateNotificationsEnabled;
|
||||
editSidebarHiddenTablePrefixes.value = settingsStore.editorSettings.sidebarHiddenTablePrefixes.join("\n");
|
||||
editSidebarHideTableComments.value = settingsStore.editorSettings.sidebarHideTableComments;
|
||||
editSidebarObjectInfoMode.value = settingsStore.editorSettings.sidebarObjectInfoMode;
|
||||
editSidebarAllowHorizontalScroll.value = settingsStore.editorSettings.sidebarAllowHorizontalScroll;
|
||||
editExportBatchSize.value = settingsStore.editorSettings.exportBatchSize;
|
||||
editGlobalDateTimeDisplayFormat.value = settingsStore.editorSettings.globalDateTimeDisplayFormat;
|
||||
@@ -817,6 +818,7 @@ async function persistSettings() {
|
||||
const sidebarTablePageSizeChanged = editSidebarTablePageSize.value !== (settingsStore.desktopSettings.sidebar_table_page_size ?? DEFAULT_SIDEBAR_TABLE_PAGE_SIZE);
|
||||
if (Object.keys(editorSettingsPatch).length > 0) {
|
||||
settingsStore.updateEditorSettings(editorSettingsPatch);
|
||||
await settingsStore.persistEditorSettings();
|
||||
editEditorSettingsBase.value = editorSettingsDraftFromSettings(settingsStore.editorSettings);
|
||||
}
|
||||
await settingsStore.updateDesktopSettings({
|
||||
@@ -907,7 +909,7 @@ function resetDefaultsForTab(tab: SettingsCategory) {
|
||||
editReuseDataTab.value = DEFAULT_EDITOR_SETTINGS.reuseDataTab;
|
||||
editPrefillNewQueryWithSelect.value = DEFAULT_EDITOR_SETTINGS.prefillNewQueryWithSelect;
|
||||
editUpdateNotificationsEnabled.value = DEFAULT_EDITOR_SETTINGS.updateNotificationsEnabled;
|
||||
editSidebarHideTableComments.value = DEFAULT_EDITOR_SETTINGS.sidebarHideTableComments;
|
||||
editSidebarObjectInfoMode.value = DEFAULT_EDITOR_SETTINGS.sidebarObjectInfoMode;
|
||||
editSidebarAllowHorizontalScroll.value = DEFAULT_EDITOR_SETTINGS.sidebarAllowHorizontalScroll;
|
||||
editSidebarHiddenTablePrefixes.value = DEFAULT_EDITOR_SETTINGS.sidebarHiddenTablePrefixes.join("\n");
|
||||
editToolbarItems.value = { ...DEFAULT_EDITOR_SETTINGS.toolbarItems };
|
||||
@@ -992,7 +994,7 @@ function resetAllDefaults() {
|
||||
editReuseDataTab.value = DEFAULT_EDITOR_SETTINGS.reuseDataTab;
|
||||
editPrefillNewQueryWithSelect.value = DEFAULT_EDITOR_SETTINGS.prefillNewQueryWithSelect;
|
||||
editUpdateNotificationsEnabled.value = DEFAULT_EDITOR_SETTINGS.updateNotificationsEnabled;
|
||||
editSidebarHideTableComments.value = DEFAULT_EDITOR_SETTINGS.sidebarHideTableComments;
|
||||
editSidebarObjectInfoMode.value = DEFAULT_EDITOR_SETTINGS.sidebarObjectInfoMode;
|
||||
editSidebarAllowHorizontalScroll.value = DEFAULT_EDITOR_SETTINGS.sidebarAllowHorizontalScroll;
|
||||
editSidebarHiddenTablePrefixes.value = DEFAULT_EDITOR_SETTINGS.sidebarHiddenTablePrefixes.join("\n");
|
||||
editExportBatchSize.value = DEFAULT_EDITOR_SETTINGS.exportBatchSize;
|
||||
@@ -4002,14 +4004,24 @@ onUnmounted(cleanupPreviewEditor);
|
||||
{{ t(`settings.${disconnectTabHandlingModeDescriptionKey}`) }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-4 rounded-md border bg-muted/20 px-3 py-2">
|
||||
<div class="space-y-2 rounded-md border bg-muted/20 px-3 py-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<Label for="sidebar-hide-table-comments">{{ t("settings.sidebarHideTableComments") }}</Label>
|
||||
<HelpTooltip :label="t('settings.sidebarHideTableComments')">
|
||||
{{ t("settings.sidebarHideTableCommentsDescription") }}
|
||||
<Label for="sidebar-object-info-mode">{{ t("settings.sidebarObjectInfoMode") }}</Label>
|
||||
<HelpTooltip :label="t('settings.sidebarObjectInfoMode')">
|
||||
{{ t("settings.sidebarObjectInfoModeDescription") }}
|
||||
</HelpTooltip>
|
||||
</div>
|
||||
<Switch id="sidebar-hide-table-comments" v-model="editSidebarHideTableComments" />
|
||||
<Select :model-value="editSidebarObjectInfoMode" @update:model-value="(value) => (editSidebarObjectInfoMode = value as SidebarObjectInfoMode)">
|
||||
<SelectTrigger id="sidebar-object-info-mode" class="w-full">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="comment-aligned">{{ t("settings.sidebarObjectInfoModeCommentAligned") }}</SelectItem>
|
||||
<SelectItem value="comment-inline">{{ t("settings.sidebarObjectInfoModeCommentInline") }}</SelectItem>
|
||||
<SelectItem value="size">{{ t("settings.sidebarObjectInfoModeSize") }}</SelectItem>
|
||||
<SelectItem value="hidden">{{ t("settings.sidebarObjectInfoModeHidden") }}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-4 rounded-md border bg-muted/20 px-3 py-2">
|
||||
<div class="flex items-center gap-2">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, nextTick, watch, provide, onMounted, onUnmounted, type Component, type ComponentPublicInstance, type CSSProperties } from "vue";
|
||||
import { ref, shallowRef, computed, nextTick, watch, provide, onMounted, onUnmounted, type Component, type ComponentPublicInstance, type CSSProperties } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { Search, X, ListFilter, ListOrdered, ArrowDownAZ, ArrowUpZA, Crosshair, Server, Database, FolderTree, Table2, Eye, RotateCcw } from "@lucide/vue";
|
||||
import { useConnectionStore } from "@/stores/connectionStore";
|
||||
@@ -38,6 +38,9 @@ import type { SidebarDangerDialogRequest } from "@/lib/sidebar/sidebarDangerDial
|
||||
import { resetSidebarTreeDialogState } from "./sidebarTreeDialogState";
|
||||
import { SidebarDangerConfirmDialog, SidebarDdlViewDialog, SidebarObjectSourceDialog, SidebarProcedureExecutionDialog, SidebarVisibleDatabasesDialog, SidebarVisibleSchemasDialog } from "./sidebarAsyncDialogs";
|
||||
import { sortConnectionListForDisplay } from "@/lib/sidebar/connectionListSort";
|
||||
import { sidebarDisplayTableName } from "@/lib/sidebar/sidebarTableNameDisplay";
|
||||
import { alignedSidebarCommentLabelWidths, isSidebarCommentAlignableNode, sidebarTreeNodeComment } from "@/lib/sidebar/sidebarTreeItemLayout";
|
||||
import { sidebarTableStorageScopes, supportsSidebarTableStorage } from "@/lib/sidebar/sidebarDatabaseStorage";
|
||||
|
||||
const { t } = useI18n();
|
||||
const store = useConnectionStore();
|
||||
@@ -357,6 +360,64 @@ const flatNodes = computed<FlatTreeNode[]>(() =>
|
||||
activeQueries: store.sidebarTableSearchQueries,
|
||||
}),
|
||||
);
|
||||
|
||||
const sidebarCommentLabelWidths = shallowRef(new Map<string, number>());
|
||||
let sidebarCommentMeasureFrame = 0;
|
||||
const sidebarTableNameDisplayTypes = new Set<TreeNodeType>(["table", "view", "materialized_view", "mongo-collection", "vector-collection", "elasticsearch-index"]);
|
||||
|
||||
function sidebarCommentLabel(node: TreeNode): string {
|
||||
const label = sidebarTableNameDisplayTypes.has(node.type) ? sidebarDisplayTableName(node.label, settingsStore.editorSettings.sidebarHiddenTablePrefixes) : node.label;
|
||||
return node.valid === false ? `${label} · INVALID` : label;
|
||||
}
|
||||
|
||||
function measureSidebarCommentLabelWidths() {
|
||||
sidebarCommentMeasureFrame = 0;
|
||||
if (settingsStore.editorSettings.sidebarObjectInfoMode !== "comment-aligned" || typeof document === "undefined" || !rootRef.value) {
|
||||
sidebarCommentLabelWidths.value = new Map();
|
||||
return;
|
||||
}
|
||||
|
||||
const context = document.createElement("canvas").getContext("2d");
|
||||
if (!context) return;
|
||||
const style = window.getComputedStyle(rootRef.value);
|
||||
context.font = style.font || `${style.fontWeight} ${style.fontSize} ${style.fontFamily}`;
|
||||
sidebarCommentLabelWidths.value = alignedSidebarCommentLabelWidths(
|
||||
flatNodes.value.map(({ id, depth, node }) => ({
|
||||
id,
|
||||
depth,
|
||||
alignable: isSidebarCommentAlignableNode(node),
|
||||
hasComment: !!sidebarTreeNodeComment(node),
|
||||
labelWidth: context.measureText(sidebarCommentLabel(node)).width,
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
function scheduleSidebarCommentLabelMeasure() {
|
||||
if (typeof window === "undefined") {
|
||||
measureSidebarCommentLabelWidths();
|
||||
return;
|
||||
}
|
||||
if (sidebarCommentMeasureFrame) window.cancelAnimationFrame(sidebarCommentMeasureFrame);
|
||||
sidebarCommentMeasureFrame = window.requestAnimationFrame(measureSidebarCommentLabelWidths);
|
||||
}
|
||||
|
||||
watch([flatNodes, () => settingsStore.editorSettings.sidebarObjectInfoMode, () => settingsStore.editorSettings.sidebarHiddenTablePrefixes, () => settingsStore.editorSettings.uiFontFamily, () => settingsStore.editorSettings.uiScale], scheduleSidebarCommentLabelMeasure, {
|
||||
flush: "post",
|
||||
immediate: true,
|
||||
});
|
||||
|
||||
const visibleSidebarTableStorageScopes = computed(() => {
|
||||
if (settingsStore.editorSettings.sidebarObjectInfoMode !== "size") return [];
|
||||
return sidebarTableStorageScopes(flatNodes.value.map(({ node }) => node)).filter((scope) => supportsSidebarTableStorage(store.getConfig(scope.connectionId)));
|
||||
});
|
||||
|
||||
watch(
|
||||
visibleSidebarTableStorageScopes,
|
||||
(scopes) => {
|
||||
for (const scope of scopes) void store.loadSidebarTableStorage(scope);
|
||||
},
|
||||
{ flush: "post", immediate: true },
|
||||
);
|
||||
// Build all lookup tables in one linear pass whenever the visible tree changes.
|
||||
// Selection, scrolling and sticky headers then avoid repeated full-array scans.
|
||||
const flatTreeIndex = computed(() =>
|
||||
@@ -1306,6 +1367,7 @@ onUnmounted(() => {
|
||||
sidebarScrollbarResizeObserver?.disconnect();
|
||||
window.cancelAnimationFrame(sidebarScrollbarAnimationFrame);
|
||||
window.clearTimeout(sidebarScrollingTimer);
|
||||
if (sidebarCommentMeasureFrame) window.cancelAnimationFrame(sidebarCommentMeasureFrame);
|
||||
});
|
||||
|
||||
defineExpose({ focusSearch, createNewGroup, collapseAllTreeNodes });
|
||||
@@ -1413,6 +1475,7 @@ defineExpose({ focusSearch, createNewGroup, collapseAllTreeNodes });
|
||||
:drag-disabled="isFiltering || isConnectionListAlphabeticallySorted"
|
||||
:pending-rename="pendingRenameGroupId === item.node.id"
|
||||
:highlighted="highlightedNodeId === item.node.id"
|
||||
:comment-label-width="sidebarCommentLabelWidths.get(item.node.id)"
|
||||
@context-menu="(event, node) => openSidebarContextMenu(event, node, contextMenuSlot.onContextMenu)"
|
||||
@rename-started="pendingRenameGroupId = null"
|
||||
@group-created="startRenamingCreatedGroup"
|
||||
@@ -1420,7 +1483,7 @@ defineExpose({ focusSearch, createNewGroup, collapseAllTreeNodes });
|
||||
</template>
|
||||
</RecycleScroller>
|
||||
<div v-if="stickyNode" class="sticky-database-header pointer-events-auto absolute inset-x-0 top-0 z-[5] border-b border-border/60" :style="stickyHeaderStyle">
|
||||
<TreeItem :node="stickyNode.node" :depth="stickyNode.depth" :drag-disabled="true" @context-menu="(event, node) => openSidebarContextMenu(event, node, contextMenuSlot.onContextMenu)" />
|
||||
<TreeItem :node="stickyNode.node" :depth="stickyNode.depth" :drag-disabled="true" :comment-label-width="sidebarCommentLabelWidths.get(stickyNode.node.id)" @context-menu="(event, node) => openSidebarContextMenu(event, node, contextMenuSlot.onContextMenu)" />
|
||||
</div>
|
||||
<div v-if="hasSidebarVerticalOverflow" ref="sidebarScrollbarTrackRef" class="sidebar-tree-scrollbar" :class="{ 'sidebar-tree-scrollbar--scrolling': isScrollingSidebar, 'sidebar-tree-scrollbar--dragging': isDraggingSidebarScrollbar }" @pointerdown="onSidebarScrollbarTrackPointerDown">
|
||||
<div class="sidebar-tree-scrollbar__thumb" :style="sidebarScrollbarThumbStyle" @pointerdown.stop="onSidebarScrollbarThumbPointerDown" />
|
||||
@@ -1436,6 +1499,7 @@ defineExpose({ focusSearch, createNewGroup, collapseAllTreeNodes });
|
||||
:drag-disabled="isFiltering || isConnectionListAlphabeticallySorted"
|
||||
:pending-rename="pendingRenameGroupId === item.node.id"
|
||||
:highlighted="highlightedNodeId === item.id"
|
||||
:comment-label-width="sidebarCommentLabelWidths.get(item.node.id)"
|
||||
@context-menu="(event, node) => openSidebarContextMenu(event, node, contextMenuSlot.onContextMenu)"
|
||||
@rename-started="pendingRenameGroupId = null"
|
||||
@group-created="startRenamingCreatedGroup"
|
||||
|
||||
@@ -44,8 +44,9 @@ import { Badge } from "@/components/ui/badge";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import LightTooltip from "@/components/ui/LightTooltip.vue";
|
||||
import type { ColumnInfo, ConnectionConfig, DatabaseType, TreeNode, TreeNodeType } from "@/types/database";
|
||||
import { canTreeNodeShowExpander, trailingCommentAvailableWidth, trailingCommentGapPx, treeItemPaddingLeft, treeLabelWidthClass, usesFullWidthTreeLabel } from "@/lib/sidebar/sidebarTreeItemLayout";
|
||||
import { canTreeNodeShowExpander, sidebarTreeNodeComment, treeItemPaddingLeft, treeLabelWidthClass, usesFullWidthTreeLabel } from "@/lib/sidebar/sidebarTreeItemLayout";
|
||||
import { clearActiveTableReferencePayload, createTableReferencePayload, createTableReferenceDropEvent, setActiveTableReferencePayload, type QueryEditorTableReferencePayload } from "@/lib/editor/queryEditorTableDrop";
|
||||
import { formatSidebarObjectStorage } from "@/lib/sidebar/sidebarDatabaseStorage";
|
||||
import { dataTabOpenModeFromTreeClick } from "@/lib/sidebar/dataTabOpenPolicy";
|
||||
import { effectiveDatabaseTypeForConnection } from "@/lib/database/jdbcDialect";
|
||||
import { hexToRgba } from "@/lib/common/color";
|
||||
@@ -68,22 +69,12 @@ const labelRef = ref<HTMLElement>();
|
||||
|
||||
const rowRef = ref<HTMLElement>();
|
||||
|
||||
const trailingCommentLayoutRef = ref<HTMLElement>();
|
||||
|
||||
const trailingCommentLeadingRef = ref<HTMLElement>();
|
||||
|
||||
const trailingCommentMaxWidth = ref(0);
|
||||
|
||||
const labelOverflowing = ref(false);
|
||||
|
||||
let labelResizeObserver: ResizeObserver | null = null;
|
||||
|
||||
let trailingCommentResizeObserver: ResizeObserver | null = null;
|
||||
|
||||
let labelMeasureFrame = 0;
|
||||
|
||||
let trailingCommentMeasureFrame = 0;
|
||||
|
||||
function cancelLabelOverflowMeasure() {
|
||||
if (!labelMeasureFrame) return;
|
||||
window.cancelAnimationFrame(labelMeasureFrame);
|
||||
@@ -150,6 +141,7 @@ const props = defineProps<{
|
||||
dragDisabled?: boolean;
|
||||
pendingRename?: boolean;
|
||||
highlighted?: boolean;
|
||||
commentLabelWidth?: number;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -549,71 +541,26 @@ const isNodeDefaultDatabase = computed(
|
||||
);
|
||||
|
||||
const trailingComment = computed(() => {
|
||||
if (settingsStore.editorSettings.sidebarHideTableComments) return null;
|
||||
if (activeNode.value.type === "column" && activeNode.value.meta && "comment" in activeNode.value.meta) return (activeNode.value.meta as any).comment || null;
|
||||
if ((activeNode.value.type === "schema" || activeNode.value.type === "table" || activeNode.value.type === "view" || activeNode.value.type === "mongo-collection" || activeNode.value.type === "vector-collection" || activeNode.value.type === "elasticsearch-index") && activeNode.value.comment) {
|
||||
return activeNode.value.comment;
|
||||
}
|
||||
return null;
|
||||
if (settingsStore.editorSettings.sidebarObjectInfoMode !== "comment-inline" && settingsStore.editorSettings.sidebarObjectInfoMode !== "comment-aligned") return null;
|
||||
return sidebarTreeNodeComment(activeNode.value);
|
||||
});
|
||||
|
||||
function cancelTrailingCommentMeasure() {
|
||||
if (!trailingCommentMeasureFrame) return;
|
||||
window.cancelAnimationFrame(trailingCommentMeasureFrame);
|
||||
trailingCommentMeasureFrame = 0;
|
||||
function formattedObjectStorage(): string {
|
||||
if (settingsStore.editorSettings.sidebarObjectInfoMode !== "size" || (activeNode.value.type !== "database" && activeNode.value.type !== "table" && activeNode.value.type !== "materialized_view")) return "";
|
||||
return formatSidebarObjectStorage(activeNode.value.sizeBytes);
|
||||
}
|
||||
|
||||
function measureTrailingCommentLayout() {
|
||||
const container = trailingCommentLayoutRef.value;
|
||||
const leading = trailingCommentLeadingRef.value;
|
||||
if (!trailingComment.value || !container || !leading) {
|
||||
trailingCommentMaxWidth.value = 0;
|
||||
return;
|
||||
}
|
||||
const alignedCommentLabelWidth = computed(() => (settingsStore.editorSettings.sidebarObjectInfoMode === "comment-aligned" ? props.commentLabelWidth : undefined));
|
||||
|
||||
// The leading group keeps the complete table name ahead of the comment.
|
||||
// Only the width remaining after that name and the fixed gap may be used
|
||||
// by the comment; once it reaches zero, the comment is hidden.
|
||||
trailingCommentMaxWidth.value = trailingCommentAvailableWidth(container.clientWidth, leading.scrollWidth);
|
||||
function hasTrailingMetadata(): boolean {
|
||||
return !!trailingComment.value || !!formattedObjectStorage();
|
||||
}
|
||||
|
||||
function scheduleTrailingCommentMeasure() {
|
||||
if (typeof window === "undefined") {
|
||||
measureTrailingCommentLayout();
|
||||
return;
|
||||
}
|
||||
cancelTrailingCommentMeasure();
|
||||
trailingCommentMeasureFrame = window.requestAnimationFrame(() => {
|
||||
trailingCommentMeasureFrame = 0;
|
||||
measureTrailingCommentLayout();
|
||||
});
|
||||
}
|
||||
|
||||
function refreshTrailingCommentMeasurement() {
|
||||
trailingCommentResizeObserver?.disconnect();
|
||||
trailingCommentResizeObserver = null;
|
||||
|
||||
if (!trailingComment.value || !trailingCommentLayoutRef.value || !trailingCommentLeadingRef.value) {
|
||||
trailingCommentMaxWidth.value = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
scheduleTrailingCommentMeasure();
|
||||
if (typeof ResizeObserver !== "undefined") {
|
||||
trailingCommentResizeObserver = new ResizeObserver(scheduleTrailingCommentMeasure);
|
||||
trailingCommentResizeObserver.observe(trailingCommentLayoutRef.value);
|
||||
}
|
||||
}
|
||||
|
||||
// Keep comment rows constrained to the sidebar. When space is tight, the
|
||||
// comment truncates before the table name instead of creating a large gap.
|
||||
const usesFullWidthLabel = computed(() => usesFullWidthTreeLabel(activeNode.value.type, settingsStore.editorSettings.sidebarAllowHorizontalScroll, !!trailingComment.value));
|
||||
const usesFullWidthLabel = computed(() => usesFullWidthTreeLabel(activeNode.value.type, settingsStore.editorSettings.sidebarAllowHorizontalScroll, hasTrailingMetadata()));
|
||||
|
||||
const rowWidthClass = computed(() => (usesFullWidthLabel.value ? "w-max min-w-full" : "w-full min-w-0"));
|
||||
|
||||
const labelWidthClass = computed(() => treeLabelWidthClass({ fullWidth: usesFullWidthLabel.value, hasTrailingComment: !!trailingComment.value }));
|
||||
|
||||
watch(() => [trailingComment.value, visibleLabel(activeNode.value), trailingCommentLayoutRef.value, trailingCommentLeadingRef.value], refreshTrailingCommentMeasurement, { flush: "post", immediate: true });
|
||||
const labelWidthClass = computed(() => treeLabelWidthClass({ fullWidth: usesFullWidthLabel.value, hasTrailingComment: hasTrailingMetadata() }));
|
||||
|
||||
const paddingLeft = computed(() => treeItemPaddingLeft(props.depth));
|
||||
|
||||
@@ -921,8 +868,6 @@ watch(
|
||||
onBeforeUnmount(() => {
|
||||
stopPasteHandlerRegistration();
|
||||
handleMouseLeave();
|
||||
trailingCommentResizeObserver?.disconnect();
|
||||
cancelTrailingCommentMeasure();
|
||||
finishTableReferenceDrag();
|
||||
});
|
||||
|
||||
@@ -1058,8 +1003,8 @@ function onKeydown(event: KeyboardEvent) {
|
||||
<DatabaseIcon v-if="node.type === 'connection'" :db-type="connectionIconType(node.connectionId)" class="h-3.5 w-3.5 shrink-0" />
|
||||
<Loader2 v-else-if="node.type === 'load-more' && node.isLoading" class="w-3.5 h-3.5 shrink-0 animate-spin text-primary" />
|
||||
<component v-else :is="getIconInfo(node)?.icon || Database" class="w-3.5 h-3.5 shrink-0" :class="databaseOpenVisual.iconClass" />
|
||||
<div ref="trailingCommentLayoutRef" :class="trailingComment ? 'flex flex-1 min-w-0 items-center' : 'contents'">
|
||||
<div ref="trailingCommentLeadingRef" :class="trailingComment ? 'flex max-w-full min-w-0 shrink-0 items-center gap-2' : 'contents'">
|
||||
<div :class="hasTrailingMetadata() ? 'flex flex-1 min-w-0 items-center' : 'contents'">
|
||||
<div :class="trailingComment ? 'flex max-w-full min-w-0 shrink-0 items-center gap-2' : formattedObjectStorage() ? 'flex min-w-0 flex-1 items-center gap-2' : 'contents'" :style="alignedCommentLabelWidth ? { width: `${alignedCommentLabelWidth}px` } : undefined">
|
||||
<input
|
||||
v-if="isRenamingGroup"
|
||||
ref="renameInputRef"
|
||||
@@ -1084,20 +1029,14 @@ function onKeydown(event: KeyboardEvent) {
|
||||
{{ t("editor.defaultDatabase") }}
|
||||
</Badge>
|
||||
</div>
|
||||
<span v-if="trailingComment && trailingCommentMaxWidth > 0" class="min-w-0 flex-1" aria-hidden="true" />
|
||||
<span
|
||||
v-if="trailingComment && trailingCommentMaxWidth > 0"
|
||||
class="sidebar-object-comment min-w-0 shrink-0 truncate text-left"
|
||||
:class="{ 'sidebar-object-comment--windows': useWindowsSidebarCommentFont }"
|
||||
:style="{ marginLeft: `${trailingCommentGapPx}px`, maxWidth: `${trailingCommentMaxWidth}px` }"
|
||||
>{{ trailingComment }}</span
|
||||
>
|
||||
<span v-if="trailingComment" class="sidebar-object-comment ml-2 min-w-0 flex-1 truncate text-left" :class="{ 'sidebar-object-comment--windows': useWindowsSidebarCommentFont }">{{ trailingComment }}</span>
|
||||
</div>
|
||||
<span v-if="node.type === 'connection' && node.connectionId && connectionStore.connectedIds.has(node.connectionId)" class="w-1.5 h-1.5 rounded-full bg-green-500 shrink-0" />
|
||||
<span v-if="databaseOpenVisual.showsIndicator" class="w-1.5 h-1.5 rounded-full bg-green-500 shrink-0" />
|
||||
<Badge v-if="isConnectionReadonly" variant="secondary" class="h-4 px-1.5 text-[10px] gap-0.5"><Lock class="w-2.5 h-2.5" />{{ t("connection.readOnlyBadge") }}</Badge>
|
||||
<ConnectionErrorIndicator v-if="node.type === 'connection'" :connection-id="node.connectionId" trigger-class="h-4 w-4" />
|
||||
<Pin v-if="isPinned" class="w-3 h-3 shrink-0 text-primary fill-current" aria-hidden="true" />
|
||||
<span v-if="formattedObjectStorage()" class="ml-auto shrink-0 text-right text-xs tabular-nums text-muted-foreground">{{ formattedObjectStorage() }}</span>
|
||||
<button
|
||||
v-if="isConnecting"
|
||||
type="button"
|
||||
@@ -1145,11 +1084,6 @@ function onKeydown(event: KeyboardEvent) {
|
||||
font-size: 10px;
|
||||
line-height: 1rem;
|
||||
opacity: 0.6;
|
||||
/* Use the comment's natural width whenever the row has room for it. */
|
||||
width: max-content;
|
||||
max-width: 100%;
|
||||
/* Preserve table names when a narrow row needs to truncate its comment. */
|
||||
flex-shrink: 999;
|
||||
/* Sidebar rows repaint on hover; avoid heavier font shaping and fallback here. */
|
||||
text-rendering: auto;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user