Skip to content

Commit 2f5f6eb

Browse files
committed
feat: show entity description as the label when available
Prefer an entity's description (e.g. a component's host OS string 'Ubuntu 24.04.4 LTS on x86_64') over the raw name/hostname for the tree node label and the component detail header. The hostname/id stays discoverable via the tree node tooltip and the detail path. Falls back to the name when there is no description.
1 parent 3b1b1e7 commit 2f5f6eb

4 files changed

Lines changed: 43 additions & 3 deletions

File tree

src/components/EntityDetailPanel.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -778,7 +778,9 @@ export function EntityDetailPanel({ onConnectClick, viewMode = 'entity', onEntit
778778
{getEntityTypeIcon()}
779779
</div>
780780
<div>
781-
<CardTitle className="text-xl">{selectedEntity.name}</CardTitle>
781+
<CardTitle className="text-xl">
782+
{selectedEntity.description || selectedEntity.name}
783+
</CardTitle>
782784
<CardDescription className="flex items-center gap-2">
783785
<Badge variant="outline">{selectedEntity.type}</Badge>
784786
<span className="text-muted-foreground"></span>

src/components/EntityTreeNode.test.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,35 @@ describe('EntityTreeNode lifecycle lamp', () => {
7070
expect(screen.queryByLabelText(/status:/i)).not.toBeInTheDocument();
7171
});
7272
});
73+
74+
describe('EntityTreeNode label', () => {
75+
beforeEach(() => {
76+
useAppStore.setState({ statusByEntity: {}, expandedPaths: [], loadingPaths: [], selectedPath: null });
77+
});
78+
afterEach(() => cleanup());
79+
80+
it('shows the entity description as the label when present', () => {
81+
useAppStore.setState({ fetchEntityStatus: vi.fn() } as never);
82+
render(
83+
<EntityTreeNode
84+
node={
85+
{
86+
id: 'a3d9',
87+
name: 'a3d9',
88+
type: 'component',
89+
path: '/server/a3d9',
90+
description: 'Ubuntu 24.04.4 LTS on x86_64',
91+
} as never
92+
}
93+
depth={0}
94+
/>
95+
);
96+
expect(screen.getByText('Ubuntu 24.04.4 LTS on x86_64')).toBeInTheDocument();
97+
});
98+
99+
it('falls back to the name when there is no description', () => {
100+
useAppStore.setState({ fetchEntityStatus: vi.fn() } as never);
101+
render(<EntityTreeNode node={{ id: 'talker', name: 'talker', type: 'app', path: '/x/talker' } as never} depth={0} />);
102+
expect(screen.getByText('talker')).toBeInTheDocument();
103+
});
104+
});

src/components/EntityTreeNode.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,8 +261,12 @@ export function EntityTreeNode({ node, depth }: EntityTreeNodeProps) {
261261
/>
262262
)}
263263

264-
<span className="text-sm truncate flex-1">
265-
{typeof node.name === 'string' ? node.name : String(node.name || node.id || '')}
264+
<span
265+
className="text-sm truncate flex-1"
266+
title={typeof node.name === 'string' ? node.name : node.id}
267+
>
268+
{(typeof node.description === 'string' && node.description) ||
269+
(typeof node.name === 'string' ? node.name : String(node.name || node.id || ''))}
266270
</span>
267271

268272
{/* Topic direction indicators */}

src/lib/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ export interface SovdEntity {
126126
id: string;
127127
/** Display name */
128128
name: string;
129+
/** Optional human-friendly description (e.g. the host OS for a component). */
130+
description?: string;
129131
/** Entity type (e.g., "component", "application", "signal") */
130132
type: string;
131133
/** API path for this entity */

0 commit comments

Comments
 (0)