feat(sidebar): show invalid object status marker in tree

This commit is contained in:
Elias 2026-08-07 02:53:51 +08:00 committed by GitHub
parent 4efe579d90
commit c32f92a902
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 50 additions and 4 deletions

View File

@ -35,6 +35,7 @@ import {
Archive,
Square,
X,
CircleX,
RefreshCw,
} from "@lucide/vue";
import { useConnectionStore } from "@/stores/connectionStore";
@ -1102,7 +1103,7 @@ function onKeydown(event: KeyboardEvent) {
</div>
<div v-else @contextmenu="onTreeItemContextMenu">
<LightTooltip :text="displayLabel(node)" :disabled="isTooltipDisabled()" side="right" :side-offset="8" :delay="0" :close-delay="30" :surface="detailTooltip ? 'popover' : 'foreground'">
<LightTooltip :text="visibleLabel(node)" :disabled="isTooltipDisabled()" side="right" :side-offset="8" :delay="0" :close-delay="30" :surface="detailTooltip ? 'popover' : 'foreground'">
<div
ref="rowRef"
class="group flex items-center gap-2 py-1 px-2 cursor-pointer relative outline-none"
@ -1145,9 +1146,12 @@ function onKeydown(event: KeyboardEvent) {
</button>
</template>
<span v-else class="w-3.5 h-3.5 shrink-0" />
<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" />
<span class="relative flex h-3.5 w-3.5 shrink-0" :class="{ 'overflow-visible': node.valid === false }">
<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="h-3.5 w-3.5 shrink-0 animate-spin text-primary" />
<component v-else :is="getIconInfo(node)?.icon || Database" class="h-3.5 w-3.5 shrink-0" :class="databaseOpenVisual.iconClass" />
<CircleX v-if="node.valid === false" data-invalid-object-indicator="true" class="pointer-events-none absolute -right-1 -bottom-1 h-2.5 w-2.5 rounded-full bg-background text-destructive stroke-[3]" aria-hidden="true" />
</span>
<div ref="trailingCommentLayoutRef" :class="hasTrailingMetadata() ? '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' : formattedObjectStorage() ? 'flex min-w-0 flex-1 items-center gap-2' : 'contents'" :style="alignedCommentLeadingStyle()">
<input

View File

@ -137,4 +137,46 @@ describe("TreeItem load-more activation", () => {
expect(host.handleRowClick).not.toHaveBeenCalled();
});
it("shows the invalid marker for objects reported as invalid", async () => {
const node: TreeNode = {
id: "connection-1:app:dbo:broken_proc",
label: "broken_proc",
type: "procedure",
connectionId: "connection-1",
database: "app",
schema: "dbo",
valid: false,
};
const { row } = await mountTreeItem(node);
expect(row.textContent).toContain("broken_proc · INVALID");
expect(row.querySelector('[data-invalid-object-indicator="true"]')).not.toBeNull();
});
it("does not show the invalid marker for valid or unknown-status objects", async () => {
const validNode: TreeNode = {
id: "connection-1:app:dbo:healthy_proc",
label: "healthy_proc",
type: "procedure",
connectionId: "connection-1",
database: "app",
schema: "dbo",
valid: true,
};
const unknownNode: TreeNode = {
...validNode,
id: "connection-1:app:dbo:unknown_proc",
label: "unknown_proc",
valid: null,
};
const valid = await mountTreeItem(validNode);
expect(valid.row.textContent).not.toContain("INVALID");
expect(valid.row.querySelector('[data-invalid-object-indicator="true"]')).toBeNull();
const unknown = await mountTreeItem(unknownNode);
expect(unknown.row.textContent).not.toContain("INVALID");
expect(unknown.row.querySelector('[data-invalid-object-indicator="true"]')).toBeNull();
});
});