fix(console): clarify Pilot Agent host-console unavailability (#1868)

Replace the generic upgrade message on Pilot Agent nodes with transport-specific
copy while preserving DAP-remote behavior.

- Add resolveHostConsoleLockMessage() to return Pilot-specific copy when
  nodeMode === 'pilot_agent'; otherwise keep generic upgrade message.
- Update ViewRouter to use the helper in the locked branch.
- Add unit tests for the new helper and component behavior.
- Sync docs/features/host-console.mdx to reflect the Pilot Agent message.

Closes #1855
This commit is contained in:
Anso
2026-08-29 03:30:53 +00:00
committed by GitHub
parent 48f010475b
commit 49940311ba
5 changed files with 122 additions and 12 deletions
@@ -4,7 +4,7 @@ import { Skeleton } from '@/components/ui/skeleton';
import { useAuth } from '@/context/AuthContext';
import { useLicense } from '@/context/LicenseContext';
import { useNodes } from '@/context/NodeContext';
import { resolveHostConsoleCapability } from '@/lib/routing/hostConsoleCapability';
import { resolveHostConsoleCapability, resolveHostConsoleLockMessage } from '@/lib/routing/hostConsoleCapability';
import { LockCard } from '../ui/LockCard';
import { CapabilityGate } from '../CapabilityGate';
import { HubOnlyGate } from '../HubOnlyGate';
@@ -207,17 +207,16 @@ export function ViewRouter({
});
if (capState === 'loading') return <ViewSkeleton />;
if (capState === 'locked') {
const nodeName = activeNode.name;
const version = activeNodeMeta?.version;
let versionHint = `${nodeName} does not advertise this capability.`;
if (version && version !== 'unknown' && version !== '0.0.0-dev') {
versionHint = `${nodeName} is running v${version}.`;
}
const { title, body } = resolveHostConsoleLockMessage({
nodeMode: activeNode.mode,
nodeName: activeNode.name,
version: activeNodeMeta?.version,
});
return (
<LockCard
icon={Unplug}
title="Host Console is not available on this node"
body={`${versionHint} Upgrade the node to use this feature.`}
title={title}
body={body}
/>
);
}
@@ -128,12 +128,25 @@ describe('ViewRouter host-console', () => {
it('shows a lock card for Community + legacy remote without mounting HostConsole', () => {
vi.mocked(NodeContext.useNodes).mockReturnValue({
activeNode: { id: 2, name: 'Legacy', type: 'remote' },
activeNode: { id: 2, name: 'Legacy', type: 'remote', mode: 'proxy' },
activeNodeMeta: { version: '0.95.0', capabilities: ['host-console'], fetchedAt: 1 },
} as unknown as ReturnType<typeof NodeContext.useNodes>);
render(<ViewRouter {...baseProps} />);
expect(screen.queryByTestId('host-console')).toBeNull();
expect(screen.getByText(/Host Console is not available on this node/i)).toBeTruthy();
expect(screen.getByText(/Legacy is running v0\.95\.0\. Upgrade the node to use this feature\./i)).toBeTruthy();
});
it('shows Pilot-specific copy for a pilot_agent node without mounting HostConsole', () => {
vi.mocked(NodeContext.useNodes).mockReturnValue({
activeNode: { id: 4, name: 'Pilot', type: 'remote', mode: 'pilot_agent' },
activeNodeMeta: { version: '0.97.1', capabilities: [], fetchedAt: 1 },
} as unknown as ReturnType<typeof NodeContext.useNodes>);
render(<ViewRouter {...baseProps} />);
expect(screen.queryByTestId('host-console')).toBeNull();
expect(screen.getByText(/Host Console is not available through Pilot Agent yet/i)).toBeTruthy();
expect(screen.getByText(/Host Console is currently available on the local node and Distributed API Proxy remotes\./i)).toBeTruthy();
expect(screen.queryByText(/Upgrade the node to use this feature\./i)).toBeNull();
});
it('mounts Host Console for Admiral + legacy remote after meta resolves', async () => {