@nexus-ai-fs/tui 0.9.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -0
- package/package.json +48 -0
- package/src/app.tsx +349 -0
- package/src/index.tsx +137 -0
- package/src/opentui-env.d.ts +61 -0
- package/src/panels/access/access-panel.tsx +597 -0
- package/src/panels/access/alert-list.tsx +77 -0
- package/src/panels/access/constraint-creator.tsx +128 -0
- package/src/panels/access/constraint-list.tsx +72 -0
- package/src/panels/access/credential-list.tsx +68 -0
- package/src/panels/access/delegation-chain-view.tsx +110 -0
- package/src/panels/access/delegation-completer.tsx +120 -0
- package/src/panels/access/delegation-creator.tsx +237 -0
- package/src/panels/access/delegation-list.tsx +74 -0
- package/src/panels/access/fraud-score-view.tsx +94 -0
- package/src/panels/access/manifest-creator.tsx +167 -0
- package/src/panels/access/manifest-list.tsx +105 -0
- package/src/panels/access/namespace-config-view.tsx +525 -0
- package/src/panels/access/permission-checker.tsx +231 -0
- package/src/panels/agents/agent-status-view.tsx +196 -0
- package/src/panels/agents/agents-panel.tsx +493 -0
- package/src/panels/agents/delegation-list.tsx +154 -0
- package/src/panels/agents/inbox-view.tsx +96 -0
- package/src/panels/agents/trajectories-tab.tsx +40 -0
- package/src/panels/api-console/api-console-panel.tsx +189 -0
- package/src/panels/api-console/codegen-viewer.tsx +36 -0
- package/src/panels/api-console/codegen.ts +112 -0
- package/src/panels/api-console/endpoint-list.tsx +57 -0
- package/src/panels/api-console/request-builder.tsx +69 -0
- package/src/panels/api-console/response-viewer.tsx +54 -0
- package/src/panels/connectors/available-tab.tsx +357 -0
- package/src/panels/connectors/connector-row.tsx +121 -0
- package/src/panels/connectors/connectors-panel.tsx +88 -0
- package/src/panels/connectors/error-parser.ts +116 -0
- package/src/panels/connectors/mounted-tab.tsx +179 -0
- package/src/panels/connectors/skills-tab.tsx +235 -0
- package/src/panels/connectors/template-generator.ts +211 -0
- package/src/panels/connectors/write-tab.tsx +514 -0
- package/src/panels/events/audit-tab.tsx +69 -0
- package/src/panels/events/audit-trail.tsx +75 -0
- package/src/panels/events/connector-detail.tsx +49 -0
- package/src/panels/events/connector-list.tsx +73 -0
- package/src/panels/events/connectors-tab.tsx +92 -0
- package/src/panels/events/event-replay.tsx +80 -0
- package/src/panels/events/events-panel.tsx +414 -0
- package/src/panels/events/events-tab.tsx +212 -0
- package/src/panels/events/lock-list.tsx +54 -0
- package/src/panels/events/locks-tab.tsx +103 -0
- package/src/panels/events/mcl-replay.tsx +77 -0
- package/src/panels/events/mcl-tab.tsx +83 -0
- package/src/panels/events/operations-tab-wrapper.tsx +62 -0
- package/src/panels/events/operations-tab.tsx +41 -0
- package/src/panels/events/replay-tab.tsx +76 -0
- package/src/panels/events/secrets-audit.tsx +64 -0
- package/src/panels/events/secrets-tab.tsx +75 -0
- package/src/panels/events/subscription-list.tsx +54 -0
- package/src/panels/events/subscriptions-tab.tsx +82 -0
- package/src/panels/files/file-aspects.tsx +93 -0
- package/src/panels/files/file-editor.tsx +160 -0
- package/src/panels/files/file-explorer-keybindings.ts +468 -0
- package/src/panels/files/file-explorer-panel.tsx +545 -0
- package/src/panels/files/file-lineage.tsx +163 -0
- package/src/panels/files/file-list-item.tsx +28 -0
- package/src/panels/files/file-metadata.tsx +62 -0
- package/src/panels/files/file-preview.tsx +108 -0
- package/src/panels/files/file-schema.tsx +89 -0
- package/src/panels/files/file-tree-node.tsx +44 -0
- package/src/panels/files/file-tree.tsx +169 -0
- package/src/panels/files/share-links-tab.tsx +33 -0
- package/src/panels/files/uploads-tab.tsx +45 -0
- package/src/panels/payments/approval-list.tsx +83 -0
- package/src/panels/payments/balance-card.tsx +43 -0
- package/src/panels/payments/budget-card.tsx +70 -0
- package/src/panels/payments/payments-panel.tsx +451 -0
- package/src/panels/payments/policy-list.tsx +64 -0
- package/src/panels/payments/reservation-list.tsx +78 -0
- package/src/panels/payments/transaction-list.tsx +103 -0
- package/src/panels/payments/transfer-form.tsx +109 -0
- package/src/panels/search/column-search.tsx +79 -0
- package/src/panels/search/knowledge-view.tsx +100 -0
- package/src/panels/search/memory-list.tsx +197 -0
- package/src/panels/search/playbook-list.tsx +77 -0
- package/src/panels/search/rlm-answer-view.tsx +105 -0
- package/src/panels/search/search-panel.tsx +405 -0
- package/src/panels/search/search-results.tsx +116 -0
- package/src/panels/stack/stack-panel.tsx +474 -0
- package/src/panels/versions/conflicts-tab.tsx +59 -0
- package/src/panels/versions/entry-detail.tsx +89 -0
- package/src/panels/versions/transaction-actions.tsx +34 -0
- package/src/panels/versions/transaction-list.tsx +90 -0
- package/src/panels/versions/versions-panel.tsx +276 -0
- package/src/panels/workflows/execution-list.tsx +102 -0
- package/src/panels/workflows/scheduler-view.tsx +135 -0
- package/src/panels/workflows/workflow-list.tsx +88 -0
- package/src/panels/workflows/workflows-panel.tsx +295 -0
- package/src/panels/zones/brick-detail.tsx +136 -0
- package/src/panels/zones/brick-list.tsx +56 -0
- package/src/panels/zones/cache-tab.tsx +118 -0
- package/src/panels/zones/drift-view.tsx +97 -0
- package/src/panels/zones/mcp-mounts-tab.tsx +38 -0
- package/src/panels/zones/memories-tab.tsx +37 -0
- package/src/panels/zones/reindex-status.tsx +84 -0
- package/src/panels/zones/workspaces-tab.tsx +37 -0
- package/src/panels/zones/zone-list.tsx +73 -0
- package/src/panels/zones/zones-panel.tsx +559 -0
- package/src/services/command-runner.ts +303 -0
- package/src/shared/accessibility-announcements.ts +44 -0
- package/src/shared/action-registry.ts +466 -0
- package/src/shared/brick-states.ts +91 -0
- package/src/shared/command-palette.ts +35 -0
- package/src/shared/components/announcement-bar.tsx +30 -0
- package/src/shared/components/app-confirm-dialog.tsx +29 -0
- package/src/shared/components/breadcrumb.tsx +21 -0
- package/src/shared/components/brick-gate.tsx +60 -0
- package/src/shared/components/command-output.tsx +95 -0
- package/src/shared/components/command-palette.tsx +97 -0
- package/src/shared/components/confirm-dialog.tsx +61 -0
- package/src/shared/components/diff-viewer.tsx +219 -0
- package/src/shared/components/empty-state.tsx +36 -0
- package/src/shared/components/error-bar.tsx +60 -0
- package/src/shared/components/error-boundary.tsx +53 -0
- package/src/shared/components/help-overlay.tsx +99 -0
- package/src/shared/components/identity-switcher.tsx +168 -0
- package/src/shared/components/loading-indicator.tsx +40 -0
- package/src/shared/components/pagination-bar.tsx +68 -0
- package/src/shared/components/pre-connection-screen.tsx +398 -0
- package/src/shared/components/scroll-indicator.tsx +46 -0
- package/src/shared/components/side-nav-utils.ts +68 -0
- package/src/shared/components/side-nav.tsx +287 -0
- package/src/shared/components/spinner.tsx +26 -0
- package/src/shared/components/status-bar.tsx +117 -0
- package/src/shared/components/styled-text.tsx +72 -0
- package/src/shared/components/sub-tab-bar-utils.ts +100 -0
- package/src/shared/components/sub-tab-bar.tsx +40 -0
- package/src/shared/components/tab-bar-utils.ts +36 -0
- package/src/shared/components/tab-bar.tsx +50 -0
- package/src/shared/components/text-input.tsx +73 -0
- package/src/shared/components/tooltip.tsx +53 -0
- package/src/shared/components/virtual-list.tsx +93 -0
- package/src/shared/components/welcome-screen.tsx +111 -0
- package/src/shared/hooks/use-api.ts +10 -0
- package/src/shared/hooks/use-brick-available.ts +42 -0
- package/src/shared/hooks/use-confirm.ts +66 -0
- package/src/shared/hooks/use-connection-state.ts +67 -0
- package/src/shared/hooks/use-copy.ts +31 -0
- package/src/shared/hooks/use-fresh-server.ts +62 -0
- package/src/shared/hooks/use-keyboard.ts +58 -0
- package/src/shared/hooks/use-list-navigation.ts +106 -0
- package/src/shared/hooks/use-swr.ts +117 -0
- package/src/shared/hooks/use-tab-fallback.ts +32 -0
- package/src/shared/hooks/use-text-input.ts +113 -0
- package/src/shared/hooks/use-visible-tabs.ts +61 -0
- package/src/shared/lib/circular-buffer.ts +82 -0
- package/src/shared/lib/clipboard.ts +14 -0
- package/src/shared/nav-items.ts +73 -0
- package/src/shared/navigation.ts +110 -0
- package/src/shared/status-breadcrumb.ts +74 -0
- package/src/shared/syntax-style.ts +3 -0
- package/src/shared/tab-visibility.ts +15 -0
- package/src/shared/text-style.ts +23 -0
- package/src/shared/theme.ts +179 -0
- package/src/shared/utils/format-size.ts +20 -0
- package/src/shared/utils/format-text.ts +10 -0
- package/src/shared/utils/format-time.ts +72 -0
- package/src/shared/utils/lru-cache.ts +75 -0
- package/src/stores/access-store-types.ts +154 -0
- package/src/stores/access-store.ts +674 -0
- package/src/stores/agents-store.ts +404 -0
- package/src/stores/announcement-store.ts +46 -0
- package/src/stores/api-console-store.ts +476 -0
- package/src/stores/connectors-store.ts +434 -0
- package/src/stores/create-api-action.ts +140 -0
- package/src/stores/delegation-store.ts +300 -0
- package/src/stores/error-store.ts +102 -0
- package/src/stores/events-store.ts +163 -0
- package/src/stores/files-store.ts +630 -0
- package/src/stores/first-run-store.ts +34 -0
- package/src/stores/global-store.ts +255 -0
- package/src/stores/infra-store.ts +461 -0
- package/src/stores/knowledge-store.ts +358 -0
- package/src/stores/lineage-store.ts +126 -0
- package/src/stores/mcp-store.ts +147 -0
- package/src/stores/payments-store.ts +545 -0
- package/src/stores/search-store-types.ts +155 -0
- package/src/stores/search-store.ts +656 -0
- package/src/stores/share-link-store.ts +151 -0
- package/src/stores/stack-store.ts +352 -0
- package/src/stores/ui-store.ts +161 -0
- package/src/stores/upload-store.ts +131 -0
- package/src/stores/versions-store.ts +355 -0
- package/src/stores/workflows-store.ts +402 -0
- package/src/stores/workspace-store.ts +185 -0
- package/src/stores/zones-store.ts +378 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Connector capabilities detail view.
|
|
3
|
+
*
|
|
4
|
+
* Shown when Enter is pressed on a selected connector.
|
|
5
|
+
* Fetches and displays capabilities from GET /api/v2/connectors/{name}/capabilities.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React from "react";
|
|
9
|
+
import { Spinner } from "../../shared/components/spinner.js";
|
|
10
|
+
|
|
11
|
+
export interface ConnectorDetailProps {
|
|
12
|
+
readonly connectorName: string;
|
|
13
|
+
readonly capabilities: unknown | null;
|
|
14
|
+
readonly loading: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function ConnectorDetail({
|
|
18
|
+
connectorName,
|
|
19
|
+
capabilities,
|
|
20
|
+
loading,
|
|
21
|
+
}: ConnectorDetailProps): React.ReactNode {
|
|
22
|
+
if (loading) {
|
|
23
|
+
return <Spinner label={`Loading capabilities for ${connectorName}...`} />;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (capabilities === null || capabilities === undefined) {
|
|
27
|
+
return <text>{`No capabilities data for ${connectorName}`}</text>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Render capabilities as formatted JSON lines (truncated to prevent huge renders)
|
|
31
|
+
const json = JSON.stringify(capabilities, null, 2);
|
|
32
|
+
const display = json.length > 5000 ? json.slice(0, 5000) + "\n... (truncated)" : json;
|
|
33
|
+
const lines = display.split("\n");
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<box flexDirection="column" height="100%" width="100%">
|
|
37
|
+
<box height={1} width="100%">
|
|
38
|
+
<text>{`Capabilities: ${connectorName}`}</text>
|
|
39
|
+
</box>
|
|
40
|
+
<scrollbox flexGrow={1} width="100%">
|
|
41
|
+
{lines.map((line, i) => (
|
|
42
|
+
<box key={i} height={1} width="100%">
|
|
43
|
+
<text>{` ${line}`}</text>
|
|
44
|
+
</box>
|
|
45
|
+
))}
|
|
46
|
+
</scrollbox>
|
|
47
|
+
</box>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Connector list view: shows registered connectors with status and capabilities.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import React, { useCallback } from "react";
|
|
6
|
+
import type { Connector } from "../../stores/infra-store.js";
|
|
7
|
+
import { Spinner } from "../../shared/components/spinner.js";
|
|
8
|
+
import { EmptyState } from "../../shared/components/empty-state.js";
|
|
9
|
+
import { VirtualList } from "../../shared/components/virtual-list.js";
|
|
10
|
+
|
|
11
|
+
const VIEWPORT_HEIGHT = 20;
|
|
12
|
+
|
|
13
|
+
const STATUS_ICON: Record<string, string> = {
|
|
14
|
+
active: "●",
|
|
15
|
+
inactive: "○",
|
|
16
|
+
error: "✗",
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export function ConnectorList({
|
|
20
|
+
connectors,
|
|
21
|
+
selectedIndex,
|
|
22
|
+
loading,
|
|
23
|
+
}: {
|
|
24
|
+
readonly connectors: readonly Connector[];
|
|
25
|
+
readonly selectedIndex: number;
|
|
26
|
+
readonly loading: boolean;
|
|
27
|
+
}): React.ReactNode {
|
|
28
|
+
if (loading) {
|
|
29
|
+
return <Spinner label="Loading connectors..." />;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (connectors.length === 0) {
|
|
33
|
+
return (
|
|
34
|
+
<EmptyState
|
|
35
|
+
message="No connectors registered."
|
|
36
|
+
hint="Register a connector via the API: POST /api/v2/connectors"
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const renderConnector = useCallback(
|
|
42
|
+
(conn: Connector, i: number) => {
|
|
43
|
+
const prefix = i === selectedIndex ? "> " : " ";
|
|
44
|
+
const icon = STATUS_ICON[conn.status] ?? "?";
|
|
45
|
+
const name = conn.name.padEnd(20).slice(0, 20);
|
|
46
|
+
const type = conn.type.padEnd(13).slice(0, 13);
|
|
47
|
+
const caps = conn.capabilities.join(", ");
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<box key={conn.connector_id} height={1} width="100%">
|
|
51
|
+
<text>{`${prefix}${icon} ${name} ${type} ${caps}`}</text>
|
|
52
|
+
</box>
|
|
53
|
+
);
|
|
54
|
+
},
|
|
55
|
+
[selectedIndex],
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<box height="100%" width="100%" flexDirection="column">
|
|
60
|
+
{/* Header */}
|
|
61
|
+
<box height={1} width="100%">
|
|
62
|
+
<text>{" St Name Type Capabilities"}</text>
|
|
63
|
+
</box>
|
|
64
|
+
|
|
65
|
+
<VirtualList
|
|
66
|
+
items={connectors}
|
|
67
|
+
renderItem={renderConnector}
|
|
68
|
+
viewportHeight={VIEWPORT_HEIGHT}
|
|
69
|
+
selectedIndex={selectedIndex}
|
|
70
|
+
/>
|
|
71
|
+
</box>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Connectors tab: list view with detail expansion.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from events-panel.tsx (Issue 2A).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React, { useState, useEffect } from "react";
|
|
8
|
+
import { useInfraStore } from "../../stores/infra-store.js";
|
|
9
|
+
import { useKeyboard } from "../../shared/hooks/use-keyboard.js";
|
|
10
|
+
import { listNavigationBindings } from "../../shared/hooks/use-list-navigation.js";
|
|
11
|
+
import { useApi } from "../../shared/hooks/use-api.js";
|
|
12
|
+
import { ConnectorList } from "./connector-list.js";
|
|
13
|
+
import { ConnectorDetail } from "./connector-detail.js";
|
|
14
|
+
|
|
15
|
+
const HELP_LIST = "j/k:navigate Enter:capabilities r:refresh Tab:switch tab";
|
|
16
|
+
const HELP_DETAIL = "Escape:back r:refresh Tab:switch tab";
|
|
17
|
+
|
|
18
|
+
interface ConnectorsTabProps {
|
|
19
|
+
readonly tabBindings: Readonly<Record<string, () => void>>;
|
|
20
|
+
readonly overlayActive: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function ConnectorsTab({ tabBindings, overlayActive }: ConnectorsTabProps): React.ReactNode {
|
|
24
|
+
const client = useApi();
|
|
25
|
+
const [detailView, setDetailView] = useState(false);
|
|
26
|
+
|
|
27
|
+
const connectors = useInfraStore((s) => s.connectors);
|
|
28
|
+
const connectorsLoading = useInfraStore((s) => s.connectorsLoading);
|
|
29
|
+
const selectedConnectorIndex = useInfraStore((s) => s.selectedConnectorIndex);
|
|
30
|
+
const setSelectedConnectorIndex = useInfraStore((s) => s.setSelectedConnectorIndex);
|
|
31
|
+
const connectorCapabilities = useInfraStore((s) => s.connectorCapabilities);
|
|
32
|
+
const capabilitiesLoading = useInfraStore((s) => s.capabilitiesLoading);
|
|
33
|
+
const fetchConnectors = useInfraStore((s) => s.fetchConnectors);
|
|
34
|
+
const fetchConnectorCapabilities = useInfraStore((s) => s.fetchConnectorCapabilities);
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (client) { fetchConnectors(client); setDetailView(false); }
|
|
38
|
+
}, [client, fetchConnectors]);
|
|
39
|
+
|
|
40
|
+
const listNav = listNavigationBindings({
|
|
41
|
+
getIndex: () => selectedConnectorIndex,
|
|
42
|
+
setIndex: (i) => setSelectedConnectorIndex(i),
|
|
43
|
+
getLength: () => connectors.length,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
useKeyboard(
|
|
47
|
+
overlayActive
|
|
48
|
+
? {}
|
|
49
|
+
: {
|
|
50
|
+
...listNav,
|
|
51
|
+
...tabBindings,
|
|
52
|
+
return: () => {
|
|
53
|
+
if (client) {
|
|
54
|
+
const conn = connectors[selectedConnectorIndex];
|
|
55
|
+
if (conn) {
|
|
56
|
+
void fetchConnectorCapabilities(conn.name, client);
|
|
57
|
+
setDetailView(true);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
escape: () => {
|
|
62
|
+
if (detailView) setDetailView(false);
|
|
63
|
+
},
|
|
64
|
+
r: () => {
|
|
65
|
+
if (client) { fetchConnectors(client); setDetailView(false); }
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<box height="100%" width="100%" flexDirection="column">
|
|
72
|
+
<box flexGrow={1} width="100%" borderStyle="single">
|
|
73
|
+
{detailView && connectors[selectedConnectorIndex] ? (
|
|
74
|
+
<ConnectorDetail
|
|
75
|
+
connectorName={connectors[selectedConnectorIndex]!.name}
|
|
76
|
+
capabilities={connectorCapabilities}
|
|
77
|
+
loading={capabilitiesLoading}
|
|
78
|
+
/>
|
|
79
|
+
) : (
|
|
80
|
+
<ConnectorList
|
|
81
|
+
connectors={connectors}
|
|
82
|
+
selectedIndex={selectedConnectorIndex}
|
|
83
|
+
loading={connectorsLoading}
|
|
84
|
+
/>
|
|
85
|
+
)}
|
|
86
|
+
</box>
|
|
87
|
+
<box height={1} width="100%">
|
|
88
|
+
<text>{detailView ? HELP_DETAIL : HELP_LIST}</text>
|
|
89
|
+
</box>
|
|
90
|
+
</box>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Historical event replay sub-view.
|
|
3
|
+
*
|
|
4
|
+
* Shows events from GET /api/v2/events/replay with filtering by
|
|
5
|
+
* event type, path pattern, agent ID, and since timestamp.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React from "react";
|
|
9
|
+
import { useKnowledgeStore } from "../../stores/knowledge-store.js";
|
|
10
|
+
import type { EventReplayEntry } from "../../stores/knowledge-store.js";
|
|
11
|
+
import { Spinner } from "../../shared/components/spinner.js";
|
|
12
|
+
import { EmptyState } from "../../shared/components/empty-state.js";
|
|
13
|
+
import { textStyle } from "../../shared/text-style.js";
|
|
14
|
+
import { formatTimestamp } from "../../shared/utils/format-time.js";
|
|
15
|
+
|
|
16
|
+
export interface EventReplayProps {
|
|
17
|
+
/** Optional event type filter (substring match, client-side). */
|
|
18
|
+
readonly typeFilter?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function EventReplay({ typeFilter }: EventReplayProps): React.ReactNode {
|
|
22
|
+
const entries = useKnowledgeStore((s) => s.eventReplayEntries);
|
|
23
|
+
const loading = useKnowledgeStore((s) => s.eventReplayLoading);
|
|
24
|
+
const hasMore = useKnowledgeStore((s) => s.eventReplayHasMore);
|
|
25
|
+
const error = useKnowledgeStore((s) => s.error);
|
|
26
|
+
|
|
27
|
+
const needle = (typeFilter ?? "").toLowerCase();
|
|
28
|
+
const filtered: readonly EventReplayEntry[] = needle
|
|
29
|
+
? entries.filter((e) => e.event_type.toLowerCase().includes(needle))
|
|
30
|
+
: entries;
|
|
31
|
+
|
|
32
|
+
if (loading && entries.length === 0) {
|
|
33
|
+
return <Spinner label="Loading event replay..." />;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (error) {
|
|
37
|
+
return <text>{`Error: ${error}`}</text>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (entries.length === 0) {
|
|
41
|
+
return (
|
|
42
|
+
<EmptyState
|
|
43
|
+
message="No historical events found."
|
|
44
|
+
hint="Adjust filters or wait for events to be recorded."
|
|
45
|
+
/>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<box flexDirection="column" height="100%" width="100%">
|
|
51
|
+
{/* Summary */}
|
|
52
|
+
<box height={1} width="100%">
|
|
53
|
+
<text style={textStyle({ dim: true })}>
|
|
54
|
+
{` ${filtered.length} event${filtered.length !== 1 ? "s" : ""}${needle ? ` matching "${typeFilter}"` : ""}`}
|
|
55
|
+
</text>
|
|
56
|
+
</box>
|
|
57
|
+
|
|
58
|
+
{/* Header */}
|
|
59
|
+
<box height={1} width="100%">
|
|
60
|
+
<text>{" Event Type Agent Path Time"}</text>
|
|
61
|
+
</box>
|
|
62
|
+
|
|
63
|
+
{/* Rows */}
|
|
64
|
+
<scrollbox flexGrow={1} width="100%">
|
|
65
|
+
{filtered.slice(0, 200).map((e) => {
|
|
66
|
+
const eventType = e.event_type.padEnd(20).slice(0, 20);
|
|
67
|
+
const agent = (e.agent_id ?? "—").padEnd(16).slice(0, 16);
|
|
68
|
+
const path = (e.path ?? "—").padEnd(30).slice(0, 30);
|
|
69
|
+
const time = formatTimestamp(e.timestamp);
|
|
70
|
+
return (
|
|
71
|
+
<box key={e.event_id} height={1} width="100%">
|
|
72
|
+
<text>{` ${eventType} ${agent} ${path} ${time}`}</text>
|
|
73
|
+
</box>
|
|
74
|
+
);
|
|
75
|
+
})}
|
|
76
|
+
{hasMore && <text style={textStyle({ dim: true })}>{" ... more events available"}</text>}
|
|
77
|
+
</scrollbox>
|
|
78
|
+
</box>
|
|
79
|
+
);
|
|
80
|
+
}
|