@agent-relay/dashboard 2.0.82 → 2.0.84
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/out/404.html +1 -1
- package/out/_next/static/chunks/1028-da5d75e35d1420f1.js +1 -0
- package/out/_next/static/chunks/1528-78b17000a7e10bc6.js +2 -0
- package/out/_next/static/chunks/1695-4a5d33ba715e09b4.js +1 -0
- package/out/_next/static/chunks/1705-36c2180d00a4a569.js +1 -0
- package/out/_next/static/chunks/1dd3208c-e1f87c7b3dc1a820.js +1 -0
- package/out/_next/static/chunks/3663-47290254b8f6f5dd.js +1 -0
- package/out/_next/static/chunks/3677-4b225baf4801d9b9.js +73 -0
- package/out/_next/static/chunks/5118-7e8ada2df38eef07.js +1 -0
- package/out/_next/static/chunks/5888-15cbe97c90ed5fae.js +1 -0
- package/out/_next/static/chunks/6773-a45343a98df3abb5.js +1 -0
- package/out/_next/static/chunks/6940-b824612b605e79b3.js +9 -0
- package/out/_next/static/chunks/7894-f4a15249082a680d.js +1 -0
- package/out/_next/static/chunks/9175-b3617c1e5cbfed0e.js +1 -0
- package/out/_next/static/chunks/9372-1a804b8d08c7a236.js +1 -0
- package/out/_next/static/chunks/{ab6c8a12-0a58072fbb505134.js → ab6c8a12-91438a812d94ecf0.js} +1 -1
- package/out/_next/static/chunks/app/_not-found/page-8e8842f82d204726.js +1 -0
- package/out/_next/static/chunks/app/about/page-b78577a7da8fa459.js +1 -0
- package/out/_next/static/chunks/app/app/[[...slug]]/page-3dffd65b6344f53e.js +1 -0
- package/out/_next/static/chunks/app/app/onboarding/page-b89be9aa6264a5e1.js +1 -0
- package/out/_next/static/chunks/app/blog/go-to-bed-wake-up-to-a-finished-product/page-fbd00893ef69e499.js +1 -0
- package/out/_next/static/chunks/app/blog/let-them-cook-multi-agent-orchestration/page-de2ea13649d0b6d3.js +1 -0
- package/out/_next/static/chunks/app/blog/page-a08e263c57a156fa.js +1 -0
- package/out/_next/static/chunks/app/careers/page-02228e1d6969b232.js +1 -0
- package/out/_next/static/chunks/app/changelog/page-1b5c1d79efc6e53a.js +1 -0
- package/out/_next/static/chunks/app/cloud/link/page-99654edffffb3af2.js +1 -0
- package/out/_next/static/chunks/app/complete-profile/page-59d146e5ddeafc5c.js +1 -0
- package/out/_next/static/chunks/app/connect-repos/page-995e16a976a6632c.js +1 -0
- package/out/_next/static/chunks/app/contact/page-273396a5ad57bcee.js +1 -0
- package/out/_next/static/chunks/app/dev/cli-tools/page-a71b80dcb2d5fc8d.js +1 -0
- package/out/_next/static/chunks/app/dev/log-viewer/page-46a6151ae1be0796.js +1 -0
- package/out/_next/static/chunks/app/docs/page-7c7cb603b24b7c40.js +1 -0
- package/out/_next/static/chunks/app/history/page-0c5cab1dab4e8886.js +1 -0
- package/out/_next/static/chunks/app/layout-96d72ba8ef8a43a0.js +1 -0
- package/out/_next/static/chunks/app/login/page-0ccbab34213df842.js +1 -0
- package/out/_next/static/chunks/app/metrics/page-8616272aeab9c8b0.js +1 -0
- package/out/_next/static/chunks/app/page-09ce10603ad9a251.js +1 -0
- package/out/_next/static/chunks/app/pricing/page-91c975079120c941.js +1 -0
- package/out/_next/static/chunks/app/privacy/{page-c21d51ac2dee3a88.js → page-a49ab271cc686644.js} +1 -1
- package/out/_next/static/chunks/app/providers/{page-59114505f4353512.js → page-d775d6eb5bc29e96.js} +1 -1
- package/out/_next/static/chunks/app/providers/setup/[provider]/page-ec4ef3cd80de807e.js +1 -0
- package/out/_next/static/chunks/app/security/page-d9da9bd9191e8f95.js +1 -0
- package/out/_next/static/chunks/app/signup/page-930eca0bf5fd299d.js +1 -0
- package/out/_next/static/chunks/app/terms/page-3e4827620b98613c.js +1 -0
- package/out/_next/static/chunks/framework-648e1ae7da590300.js +1 -0
- package/out/_next/static/chunks/{main-acb1b24265295d6a.js → main-2b1990080c292d92.js} +1 -1
- package/out/_next/static/chunks/main-app-9f6b7ff9e754a8f5.js +1 -0
- package/out/_next/static/chunks/pages/_app-a077b72e02273ab1.js +1 -0
- package/out/_next/static/chunks/pages/_error-84001666436a04e4.js +1 -0
- package/out/_next/static/chunks/{webpack-dd93b81e2659669c.js → webpack-7586035f1585f2db.js} +1 -1
- package/out/_next/static/css/eb9fc69d1e3d2bed.css +1 -0
- package/out/_next/static/{IxfA6RZu4trcsEMYlkQra → g3G0LMdB7lxcrU5mdM54m}/_buildManifest.js +1 -1
- package/out/about.html +2 -2
- package/out/about.txt +2 -2
- package/out/app/onboarding.html +1 -1
- package/out/app/onboarding.txt +2 -2
- package/out/app.html +1 -1
- package/out/app.txt +2 -2
- package/out/blog/go-to-bed-wake-up-to-a-finished-product.html +3 -3
- package/out/blog/go-to-bed-wake-up-to-a-finished-product.txt +1 -1
- package/out/blog/let-them-cook-multi-agent-orchestration.html +2 -2
- package/out/blog/let-them-cook-multi-agent-orchestration.txt +2 -2
- package/out/blog.html +2 -2
- package/out/blog.txt +1 -1
- package/out/careers.html +2 -2
- package/out/careers.txt +2 -2
- package/out/changelog.html +2 -2
- package/out/changelog.txt +2 -2
- package/out/cloud/link.html +1 -1
- package/out/cloud/link.txt +2 -2
- package/out/complete-profile.html +2 -2
- package/out/complete-profile.txt +2 -2
- package/out/connect-repos.html +1 -1
- package/out/connect-repos.txt +2 -2
- package/out/contact.html +2 -2
- package/out/contact.txt +2 -2
- package/out/dev/cli-tools.html +1 -0
- package/out/dev/cli-tools.txt +7 -0
- package/out/dev/log-viewer.html +23 -0
- package/out/dev/log-viewer.txt +7 -0
- package/out/docs.html +2 -2
- package/out/docs.txt +2 -2
- package/out/history.html +1 -1
- package/out/history.txt +2 -2
- package/out/index.html +1 -1
- package/out/index.txt +2 -2
- package/out/login.html +2 -2
- package/out/login.txt +2 -2
- package/out/metrics.html +1 -1
- package/out/metrics.txt +2 -2
- package/out/pricing.html +2 -2
- package/out/pricing.txt +2 -2
- package/out/privacy.html +2 -2
- package/out/privacy.txt +2 -2
- package/out/providers/setup/claude.html +1 -1
- package/out/providers/setup/claude.txt +2 -2
- package/out/providers/setup/codex.html +1 -1
- package/out/providers/setup/codex.txt +2 -2
- package/out/providers/setup/cursor.html +1 -1
- package/out/providers/setup/cursor.txt +2 -2
- package/out/providers.html +1 -1
- package/out/providers.txt +2 -2
- package/out/security.html +2 -2
- package/out/security.txt +2 -2
- package/out/signup.html +2 -2
- package/out/signup.txt +2 -2
- package/out/terms.html +2 -2
- package/out/terms.txt +2 -2
- package/package.json +5 -1
- package/src/adapters/DashboardConfigProvider.tsx +56 -0
- package/src/adapters/cloudFetchAdapter.ts +278 -0
- package/src/adapters/index.ts +3 -0
- package/src/adapters/types.ts +508 -0
- package/src/app/app/[[...slug]]/DashboardPageClient.tsx +67 -18
- package/src/app/app/onboarding/page.tsx +870 -170
- package/src/app/cloud/link/page.tsx +14 -6
- package/src/app/connect-repos/page.tsx +9 -3
- package/src/app/dev/cli-tools/page.tsx +130 -0
- package/src/app/dev/log-viewer/MockLogViewer.tsx +132 -0
- package/src/app/dev/log-viewer/fixtures.ts +110 -0
- package/src/app/dev/log-viewer/page.tsx +288 -0
- package/src/app/history/page.tsx +28 -12
- package/src/app/page.tsx +1 -1
- package/src/app/providers/setup/[provider]/ProviderSetupClient.tsx +209 -59
- package/src/components/AgentCard.tsx +4 -4
- package/src/components/AgentLogPreview.tsx +2 -38
- package/src/components/App.tsx +441 -2624
- package/src/components/CliToolHarness.test.tsx +83 -0
- package/src/components/CliToolHarness.tsx +292 -0
- package/src/components/CoordinatorPanel.tsx +13 -6
- package/src/components/LogViewer.tsx +2 -42
- package/src/components/ProviderAuthFlow.tsx +201 -81
- package/src/components/ProvisioningProgress.tsx +1 -1
- package/src/components/ReactionChips.tsx +2 -1
- package/src/components/SpawnModal.test.tsx +51 -18
- package/src/components/SpawnModal.tsx +175 -207
- package/src/components/TerminalProviderSetup.tsx +1 -1
- package/src/components/ThreadPanel.tsx +2 -0
- package/src/components/WorkspaceContext.tsx +7 -19
- package/src/components/XTermLogViewer.tsx +190 -27
- package/src/components/channels/ChannelMessageList.tsx +94 -4
- package/src/components/channels/ChannelViewV1.tsx +35 -11
- package/src/components/channels/api.ts +21 -20
- package/src/components/channels/types.ts +16 -0
- package/src/components/hooks/index.ts +0 -19
- package/src/components/hooks/useMessages.test.ts +80 -0
- package/src/components/hooks/useMessages.ts +13 -4
- package/src/components/hooks/useOrchestrator.ts +1 -1
- package/src/components/hooks/usePresence.ts +45 -6
- package/src/components/hooks/useThread.ts +83 -46
- package/src/components/hooks/useTrajectory.ts +62 -5
- package/src/components/hooks/useWebSocket.test.ts +358 -0
- package/src/components/hooks/useWebSocket.ts +243 -5
- package/src/components/index.ts +2 -14
- package/src/components/layout/Header.tsx +9 -15
- package/src/components/layout/Sidebar.tsx +1 -8
- package/src/components/settings/SettingsPage.tsx +108 -47
- package/src/components/settings/index.ts +0 -3
- package/src/landing/blogData.ts +1 -1
- package/src/lib/agent-merge.test.ts +2 -2
- package/src/lib/api.ts +8 -38
- package/src/lib/identity.test.ts +139 -0
- package/src/lib/identity.ts +48 -0
- package/src/lib/relaycastMessageAdapters.test.ts +182 -0
- package/src/lib/relaycastMessageAdapters.ts +105 -0
- package/src/lib/sanitize-logs.test.ts +227 -0
- package/src/lib/sanitize-logs.ts +202 -0
- package/src/providers/AgentProvider.tsx +799 -0
- package/src/providers/ChannelProvider.tsx +528 -0
- package/src/providers/CloudWorkspaceProvider.tsx +402 -0
- package/src/providers/MessageProvider.tsx +875 -0
- package/src/providers/RelayConfigProvider.tsx +94 -0
- package/src/providers/SendProvider.tsx +497 -0
- package/src/providers/SettingsProvider.tsx +247 -0
- package/src/providers/index.ts +26 -0
- package/src/types/index.ts +10 -10
- package/out/_next/static/chunks/11-9a2993a37266dcb3.js +0 -9
- package/out/_next/static/chunks/118-ae2b650136a5a5fc.js +0 -1
- package/out/_next/static/chunks/1dd3208c-40ab0fc0f60392b8.js +0 -1
- package/out/_next/static/chunks/202-fc0763dd7488e58f.js +0 -1
- package/out/_next/static/chunks/259-83b77fa1b91ba5aa.js +0 -1
- package/out/_next/static/chunks/407-0c82986cf79c8ecb.js +0 -1
- package/out/_next/static/chunks/528-f5f676996d613c25.js +0 -2
- package/out/_next/static/chunks/663-ddb04081febc3678.js +0 -1
- package/out/_next/static/chunks/687-88b6b139a6bb0e2e.js +0 -1
- package/out/_next/static/chunks/695-51d25b1988644374.js +0 -1
- package/out/_next/static/chunks/773-54a2641043c81e55.js +0 -1
- package/out/_next/static/chunks/app/_not-found/page-6da9b72091e5b511.js +0 -1
- package/out/_next/static/chunks/app/about/page-fff7c6457683f243.js +0 -1
- package/out/_next/static/chunks/app/app/[[...slug]]/page-f7eca1b66fb4249b.js +0 -1
- package/out/_next/static/chunks/app/app/onboarding/page-129abc5da2e67971.js +0 -1
- package/out/_next/static/chunks/app/blog/go-to-bed-wake-up-to-a-finished-product/page-5d5f28fd126b692f.js +0 -1
- package/out/_next/static/chunks/app/blog/let-them-cook-multi-agent-orchestration/page-b194f207fbd91862.js +0 -1
- package/out/_next/static/chunks/app/blog/page-b9bd9d8703fca76a.js +0 -1
- package/out/_next/static/chunks/app/careers/page-a4bd8d5f4de8f4eb.js +0 -1
- package/out/_next/static/chunks/app/changelog/page-9a1f6ad1743d63c5.js +0 -1
- package/out/_next/static/chunks/app/cloud/link/page-0844c5699b027c3b.js +0 -1
- package/out/_next/static/chunks/app/complete-profile/page-39ed5a67916beb87.js +0 -1
- package/out/_next/static/chunks/app/connect-repos/page-297eddee0c39f2a3.js +0 -1
- package/out/_next/static/chunks/app/contact/page-3c1dd8690217fade.js +0 -1
- package/out/_next/static/chunks/app/docs/page-1875e981f2c3fd13.js +0 -1
- package/out/_next/static/chunks/app/history/page-2d5c5695c9e8b40c.js +0 -1
- package/out/_next/static/chunks/app/layout-0a4b99656da25511.js +0 -1
- package/out/_next/static/chunks/app/login/page-f69c076f5a6fc520.js +0 -1
- package/out/_next/static/chunks/app/metrics/page-bebbee055669a17e.js +0 -1
- package/out/_next/static/chunks/app/page-0ee604f7070d14c0.js +0 -1
- package/out/_next/static/chunks/app/pricing/page-eeae7d594af333b6.js +0 -1
- package/out/_next/static/chunks/app/providers/setup/[provider]/page-daf9b3e05e77ae19.js +0 -1
- package/out/_next/static/chunks/app/security/page-cd562730fe84a0a2.js +0 -1
- package/out/_next/static/chunks/app/signup/page-c242ca08101a84ff.js +0 -1
- package/out/_next/static/chunks/app/terms/page-c7001720e7941dc6.js +0 -1
- package/out/_next/static/chunks/framework-3664cab31236a9fa.js +0 -1
- package/out/_next/static/chunks/main-app-7f73a939a312a228.js +0 -1
- package/out/_next/static/chunks/pages/_app-10a93ab5b7c32eb3.js +0 -1
- package/out/_next/static/chunks/pages/_error-2d792b2a41857be4.js +0 -1
- package/out/_next/static/css/8968d98ed4c4d33f.css +0 -1
- package/src/components/BillingResult.tsx +0 -447
- package/src/components/CloudSessionProvider.tsx +0 -130
- package/src/components/SessionExpiredModal.tsx +0 -128
- package/src/components/WorkspaceStatusIndicator.tsx +0 -396
- package/src/components/hooks/useSession.ts +0 -209
- package/src/components/hooks/useWorkspaceMembers.ts +0 -132
- package/src/components/hooks/useWorkspaceStatus.ts +0 -237
- package/src/components/settings/BillingSettingsPanel.tsx +0 -564
- package/src/components/settings/TeamSettingsPanel.tsx +0 -560
- package/src/components/settings/WorkspaceSettingsPanel.tsx +0 -1368
- package/src/lib/cloudApi.ts +0 -893
- /package/out/_next/static/{IxfA6RZu4trcsEMYlkQra → g3G0LMdB7lxcrU5mdM54m}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* /dev/log-viewer — Isolated test page for the log viewer components.
|
|
5
|
+
*
|
|
6
|
+
* Renders mock data through both inline (sanitized text) and the production
|
|
7
|
+
* XTermLogViewer (full ANSI) side by side. Supports:
|
|
8
|
+
* - Static edge-case fixtures (always available)
|
|
9
|
+
* - Real worker logs loaded dynamically from /api/logs/:name
|
|
10
|
+
* No WebSocket or auth required — XTermLogViewer runs in mock mode.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import React, { useState, useEffect } from 'react';
|
|
14
|
+
import { InlineMockViewer } from './MockLogViewer';
|
|
15
|
+
import { XTermLogViewer } from '../../../components/XTermLogViewer';
|
|
16
|
+
import { STATIC_FIXTURES, rawLogToFixture, type LogFixture } from './fixtures';
|
|
17
|
+
|
|
18
|
+
interface LogAgent {
|
|
19
|
+
name: string;
|
|
20
|
+
loading?: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default function DevLogViewerPage() {
|
|
24
|
+
const [fixtures, setFixtures] = useState<LogFixture[]>(STATIC_FIXTURES);
|
|
25
|
+
const [selectedFixture, setSelectedFixture] = useState<LogFixture>(STATIC_FIXTURES[0]);
|
|
26
|
+
const [streaming, setStreaming] = useState(false);
|
|
27
|
+
const [reloadKey, setReloadKey] = useState(0);
|
|
28
|
+
const [availableAgents, setAvailableAgents] = useState<LogAgent[]>([]);
|
|
29
|
+
const [loadingAgents, setLoadingAgents] = useState(true);
|
|
30
|
+
|
|
31
|
+
// Resolve API base: check ?api= query param, otherwise try relative /api
|
|
32
|
+
const getApiBase = () => {
|
|
33
|
+
if (typeof window === 'undefined') return '';
|
|
34
|
+
const params = new URLSearchParams(window.location.search);
|
|
35
|
+
return params.get('api') || '';
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// Fetch available log agents from the server
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
let cancelled = false;
|
|
41
|
+
|
|
42
|
+
(async () => {
|
|
43
|
+
try {
|
|
44
|
+
const apiBase = getApiBase();
|
|
45
|
+
const res = await fetch(`${apiBase}/api/logs`);
|
|
46
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
47
|
+
const data = await res.json();
|
|
48
|
+
if (cancelled) return;
|
|
49
|
+
|
|
50
|
+
// Filter out step-* logs (internal orchestration) — show named agents only
|
|
51
|
+
const agents: string[] = (data.agents || []).filter(
|
|
52
|
+
(name: string) => !name.startsWith('step-')
|
|
53
|
+
);
|
|
54
|
+
setAvailableAgents(agents.map((name) => ({ name })));
|
|
55
|
+
} catch {
|
|
56
|
+
// Server not available — just use static fixtures
|
|
57
|
+
console.warn('Could not fetch log agents from /api/logs — using static fixtures only');
|
|
58
|
+
} finally {
|
|
59
|
+
if (!cancelled) setLoadingAgents(false);
|
|
60
|
+
}
|
|
61
|
+
})();
|
|
62
|
+
|
|
63
|
+
return () => { cancelled = true; };
|
|
64
|
+
}, []);
|
|
65
|
+
|
|
66
|
+
// Load a real log file from the server
|
|
67
|
+
const loadAgentLog = async (agentName: string) => {
|
|
68
|
+
// Check if already loaded
|
|
69
|
+
const existing = fixtures.find((f) => f.name === agentName);
|
|
70
|
+
if (existing) {
|
|
71
|
+
setSelectedFixture(existing);
|
|
72
|
+
setReloadKey((k) => k + 1);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Mark as loading
|
|
77
|
+
setAvailableAgents((prev) =>
|
|
78
|
+
prev.map((a) => (a.name === agentName ? { ...a, loading: true } : a))
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const apiBase = getApiBase();
|
|
83
|
+
const res = await fetch(`${apiBase}/api/logs/${encodeURIComponent(agentName)}`);
|
|
84
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
85
|
+
const data = await res.json();
|
|
86
|
+
|
|
87
|
+
if (!data.found || !data.content) {
|
|
88
|
+
console.warn(`No log content found for ${agentName}`);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const fixture = rawLogToFixture(agentName, data.content);
|
|
93
|
+
setFixtures((prev) => [...prev, fixture]);
|
|
94
|
+
setSelectedFixture(fixture);
|
|
95
|
+
setReloadKey((k) => k + 1);
|
|
96
|
+
} catch (err) {
|
|
97
|
+
console.error(`Failed to load log for ${agentName}:`, err);
|
|
98
|
+
} finally {
|
|
99
|
+
setAvailableAgents((prev) =>
|
|
100
|
+
prev.map((a) => (a.name === agentName ? { ...a, loading: false } : a))
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const handleFixtureChange = (fixture: LogFixture) => {
|
|
106
|
+
setSelectedFixture(fixture);
|
|
107
|
+
setReloadKey((k) => k + 1);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const handleReplay = () => {
|
|
111
|
+
setReloadKey((k) => k + 1);
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// Convert LogFixtureLine[] to mockData format for XTermLogViewer
|
|
115
|
+
const mockData = selectedFixture.lines.map((line) => ({
|
|
116
|
+
content: line.content,
|
|
117
|
+
delay: line.delay,
|
|
118
|
+
}));
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<div className="min-h-screen bg-[#0a0c10] text-[#c9d1d9]">
|
|
122
|
+
{/* Header */}
|
|
123
|
+
<div className="border-b border-[#21262d] bg-[#0d1117]">
|
|
124
|
+
<div className="max-w-[1600px] mx-auto px-6 py-4">
|
|
125
|
+
<div className="flex items-center justify-between">
|
|
126
|
+
<div>
|
|
127
|
+
<h1 className="text-lg font-semibold text-white flex items-center gap-2">
|
|
128
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" className="text-accent-cyan">
|
|
129
|
+
<polyline points="4 17 10 11 4 5" />
|
|
130
|
+
<line x1="12" y1="19" x2="20" y2="19" />
|
|
131
|
+
</svg>
|
|
132
|
+
Log Viewer Test Page
|
|
133
|
+
</h1>
|
|
134
|
+
<p className="text-sm text-[#8b949e] mt-1">
|
|
135
|
+
Isolated rendering tests — static fixtures + real worker logs
|
|
136
|
+
</p>
|
|
137
|
+
</div>
|
|
138
|
+
<span className="px-2 py-1 rounded-md bg-[#d29922]/20 text-[#d29922] text-xs font-medium uppercase tracking-wider">
|
|
139
|
+
Dev Only
|
|
140
|
+
</span>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
|
|
145
|
+
{/* Controls */}
|
|
146
|
+
<div className="border-b border-[#21262d] bg-[#0d1117]/50">
|
|
147
|
+
<div className="max-w-[1600px] mx-auto px-6 py-3">
|
|
148
|
+
<div className="flex items-center gap-4 flex-wrap">
|
|
149
|
+
{/* Static fixture selector */}
|
|
150
|
+
<div className="flex items-center gap-2">
|
|
151
|
+
<span className="text-xs text-[#8b949e] uppercase tracking-wider font-medium">Static:</span>
|
|
152
|
+
<div className="flex gap-1">
|
|
153
|
+
{STATIC_FIXTURES.map((fixture) => (
|
|
154
|
+
<button
|
|
155
|
+
key={fixture.name}
|
|
156
|
+
onClick={() => handleFixtureChange(fixture)}
|
|
157
|
+
className={`px-3 py-1.5 rounded-lg text-xs font-medium transition-all ${
|
|
158
|
+
selectedFixture.name === fixture.name
|
|
159
|
+
? 'bg-accent-cyan/20 text-accent-cyan shadow-[0_0_8px_rgba(0,217,255,0.15)]'
|
|
160
|
+
: 'bg-[#21262d] text-[#8b949e] hover:text-[#c9d1d9] hover:bg-[#30363d]'
|
|
161
|
+
}`}
|
|
162
|
+
>
|
|
163
|
+
{fixture.name}
|
|
164
|
+
</button>
|
|
165
|
+
))}
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
168
|
+
|
|
169
|
+
<div className="w-px h-6 bg-[#30363d]" />
|
|
170
|
+
|
|
171
|
+
{/* Streaming toggle */}
|
|
172
|
+
<label className="flex items-center gap-2 cursor-pointer">
|
|
173
|
+
<input
|
|
174
|
+
type="checkbox"
|
|
175
|
+
checked={streaming}
|
|
176
|
+
onChange={(e) => {
|
|
177
|
+
setStreaming(e.target.checked);
|
|
178
|
+
setReloadKey((k) => k + 1);
|
|
179
|
+
}}
|
|
180
|
+
className="sr-only"
|
|
181
|
+
/>
|
|
182
|
+
<div
|
|
183
|
+
className={`w-8 h-4 rounded-full transition-colors ${
|
|
184
|
+
streaming ? 'bg-accent-cyan' : 'bg-[#30363d]'
|
|
185
|
+
}`}
|
|
186
|
+
>
|
|
187
|
+
<div
|
|
188
|
+
className={`w-3 h-3 rounded-full bg-white mt-0.5 transition-transform ${
|
|
189
|
+
streaming ? 'translate-x-4.5 ml-[18px]' : 'translate-x-0.5 ml-[2px]'
|
|
190
|
+
}`}
|
|
191
|
+
/>
|
|
192
|
+
</div>
|
|
193
|
+
<span className="text-xs text-[#8b949e]">Streaming</span>
|
|
194
|
+
</label>
|
|
195
|
+
|
|
196
|
+
{/* Replay button */}
|
|
197
|
+
<button
|
|
198
|
+
onClick={handleReplay}
|
|
199
|
+
className="px-3 py-1.5 rounded-lg text-xs font-medium bg-[#21262d] text-[#8b949e] hover:text-[#c9d1d9] hover:bg-[#30363d] transition-all flex items-center gap-1.5"
|
|
200
|
+
>
|
|
201
|
+
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
|
202
|
+
<polyline points="1 4 1 10 7 10" />
|
|
203
|
+
<path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10" />
|
|
204
|
+
</svg>
|
|
205
|
+
Replay
|
|
206
|
+
</button>
|
|
207
|
+
</div>
|
|
208
|
+
|
|
209
|
+
{/* Real log agents (loaded dynamically) */}
|
|
210
|
+
{availableAgents.length > 0 && (
|
|
211
|
+
<div className="flex items-center gap-2 mt-3">
|
|
212
|
+
<span className="text-xs text-[#8b949e] uppercase tracking-wider font-medium">Real Logs:</span>
|
|
213
|
+
<div className="flex gap-1 flex-wrap">
|
|
214
|
+
{availableAgents.map((agent) => {
|
|
215
|
+
const isLoaded = fixtures.some((f) => f.name === agent.name);
|
|
216
|
+
const isSelected = selectedFixture.name === agent.name;
|
|
217
|
+
return (
|
|
218
|
+
<button
|
|
219
|
+
key={agent.name}
|
|
220
|
+
onClick={() => loadAgentLog(agent.name)}
|
|
221
|
+
disabled={agent.loading}
|
|
222
|
+
className={`px-3 py-1.5 rounded-lg text-xs font-medium transition-all ${
|
|
223
|
+
isSelected
|
|
224
|
+
? 'bg-[#3fb950]/20 text-[#3fb950] shadow-[0_0_8px_rgba(63,185,80,0.15)]'
|
|
225
|
+
: isLoaded
|
|
226
|
+
? 'bg-[#238636]/10 text-[#3fb950] hover:bg-[#238636]/20'
|
|
227
|
+
: 'bg-[#21262d] text-[#8b949e] hover:text-[#c9d1d9] hover:bg-[#30363d]'
|
|
228
|
+
} ${agent.loading ? 'opacity-50 cursor-wait' : ''}`}
|
|
229
|
+
>
|
|
230
|
+
{agent.loading ? '...' : agent.name}
|
|
231
|
+
</button>
|
|
232
|
+
);
|
|
233
|
+
})}
|
|
234
|
+
</div>
|
|
235
|
+
{loadingAgents && (
|
|
236
|
+
<span className="text-[10px] text-[#6e7681] animate-pulse">Loading agents...</span>
|
|
237
|
+
)}
|
|
238
|
+
</div>
|
|
239
|
+
)}
|
|
240
|
+
{!loadingAgents && availableAgents.length === 0 && (
|
|
241
|
+
<div className="mt-2 text-[10px] text-[#484f58]">
|
|
242
|
+
No real log agents found — start the dashboard server to load worker logs
|
|
243
|
+
</div>
|
|
244
|
+
)}
|
|
245
|
+
|
|
246
|
+
{/* Fixture description */}
|
|
247
|
+
<p className="text-xs text-[#6e7681] mt-2">{selectedFixture.description}</p>
|
|
248
|
+
</div>
|
|
249
|
+
</div>
|
|
250
|
+
|
|
251
|
+
{/* Side-by-side viewers */}
|
|
252
|
+
<div className="max-w-[1600px] mx-auto px-6 py-6">
|
|
253
|
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
254
|
+
{/* Inline mode */}
|
|
255
|
+
<div>
|
|
256
|
+
<h2 className="text-sm font-medium text-[#8b949e] mb-3 flex items-center gap-2">
|
|
257
|
+
<span className="w-2 h-2 rounded-full bg-[#58a6ff]" />
|
|
258
|
+
Inline Mode
|
|
259
|
+
<span className="text-[10px] text-[#6e7681]">(sanitized text, no ANSI)</span>
|
|
260
|
+
</h2>
|
|
261
|
+
<InlineMockViewer
|
|
262
|
+
key={`inline-${reloadKey}`}
|
|
263
|
+
fixture={selectedFixture}
|
|
264
|
+
streaming={streaming}
|
|
265
|
+
/>
|
|
266
|
+
</div>
|
|
267
|
+
|
|
268
|
+
{/* XTerm panel mode — uses real production component in mock mode */}
|
|
269
|
+
<div>
|
|
270
|
+
<h2 className="text-sm font-medium text-[#8b949e] mb-3 flex items-center gap-2">
|
|
271
|
+
<span className="w-2 h-2 rounded-full bg-[#3fb950]" />
|
|
272
|
+
XTerm Panel Mode
|
|
273
|
+
<span className="text-[10px] text-[#6e7681]">(production component, mock data)</span>
|
|
274
|
+
</h2>
|
|
275
|
+
<XTermLogViewer
|
|
276
|
+
key={`xterm-${reloadKey}`}
|
|
277
|
+
agentName={selectedFixture.name}
|
|
278
|
+
mockData={mockData}
|
|
279
|
+
mockStreaming={streaming}
|
|
280
|
+
maxHeight="400px"
|
|
281
|
+
suppressNoisyOutput={true}
|
|
282
|
+
/>
|
|
283
|
+
</div>
|
|
284
|
+
</div>
|
|
285
|
+
</div>
|
|
286
|
+
</div>
|
|
287
|
+
);
|
|
288
|
+
}
|
package/src/app/history/page.tsx
CHANGED
|
@@ -21,12 +21,12 @@ import { getAgentColor, getAgentInitials } from '../../lib/colors';
|
|
|
21
21
|
type ViewMode = 'conversations' | 'sessions' | 'messages';
|
|
22
22
|
|
|
23
23
|
export default function HistoryPage() {
|
|
24
|
-
const [viewMode, setViewMode] = useState<ViewMode>(
|
|
24
|
+
const [viewMode, setViewMode] = useState<ViewMode | null>(null);
|
|
25
25
|
const [conversations, setConversations] = useState<Conversation[]>([]);
|
|
26
26
|
const [sessions, setSessions] = useState<HistorySession[]>([]);
|
|
27
27
|
const [messages, setMessages] = useState<HistoryMessage[]>([]);
|
|
28
28
|
const [stats, setStats] = useState<HistoryStats | null>(null);
|
|
29
|
-
const [isLoading, setIsLoading] = useState(
|
|
29
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
30
30
|
const [error, setError] = useState<string | null>(null);
|
|
31
31
|
|
|
32
32
|
// Filters
|
|
@@ -34,8 +34,12 @@ export default function HistoryPage() {
|
|
|
34
34
|
const [agentFilter, setAgentFilter] = useState('');
|
|
35
35
|
const [selectedConversation, setSelectedConversation] = useState<Conversation | null>(null);
|
|
36
36
|
|
|
37
|
-
// Fetch stats
|
|
37
|
+
// Fetch stats once when the user first selects a tab
|
|
38
|
+
const [statsLoaded, setStatsLoaded] = useState(false);
|
|
38
39
|
useEffect(() => {
|
|
40
|
+
if (!viewMode || statsLoaded) return;
|
|
41
|
+
|
|
42
|
+
setStatsLoaded(true);
|
|
39
43
|
const fetchStats = async () => {
|
|
40
44
|
const result = await api.getHistoryStats();
|
|
41
45
|
if (result.success && result.data) {
|
|
@@ -43,10 +47,12 @@ export default function HistoryPage() {
|
|
|
43
47
|
}
|
|
44
48
|
};
|
|
45
49
|
fetchStats();
|
|
46
|
-
}, []);
|
|
50
|
+
}, [viewMode, statsLoaded]);
|
|
47
51
|
|
|
48
|
-
// Fetch data based on view mode
|
|
52
|
+
// Fetch data based on view mode — only when user has selected a tab
|
|
49
53
|
useEffect(() => {
|
|
54
|
+
if (!viewMode) return;
|
|
55
|
+
|
|
50
56
|
const fetchData = async () => {
|
|
51
57
|
setIsLoading(true);
|
|
52
58
|
setError(null);
|
|
@@ -120,6 +126,13 @@ export default function HistoryPage() {
|
|
|
120
126
|
setViewMode('conversations');
|
|
121
127
|
}, []);
|
|
122
128
|
|
|
129
|
+
const handleTabClick = useCallback((mode: ViewMode) => {
|
|
130
|
+
if (mode === 'conversations') {
|
|
131
|
+
setSelectedConversation(null);
|
|
132
|
+
}
|
|
133
|
+
setViewMode(mode);
|
|
134
|
+
}, []);
|
|
135
|
+
|
|
123
136
|
return (
|
|
124
137
|
<div className="min-h-screen bg-bg-primary text-text-primary font-sans">
|
|
125
138
|
{/* Header */}
|
|
@@ -162,24 +175,21 @@ export default function HistoryPage() {
|
|
|
162
175
|
<div className="flex gap-1 bg-bg-secondary rounded-lg p-1 border border-border">
|
|
163
176
|
<TabButton
|
|
164
177
|
active={viewMode === 'conversations'}
|
|
165
|
-
onClick={() =>
|
|
166
|
-
setSelectedConversation(null);
|
|
167
|
-
setViewMode('conversations');
|
|
168
|
-
}}
|
|
178
|
+
onClick={() => handleTabClick('conversations')}
|
|
169
179
|
>
|
|
170
180
|
<ConversationIcon />
|
|
171
181
|
Conversations
|
|
172
182
|
</TabButton>
|
|
173
183
|
<TabButton
|
|
174
184
|
active={viewMode === 'sessions'}
|
|
175
|
-
onClick={() =>
|
|
185
|
+
onClick={() => handleTabClick('sessions')}
|
|
176
186
|
>
|
|
177
187
|
<SessionIcon />
|
|
178
188
|
Sessions
|
|
179
189
|
</TabButton>
|
|
180
190
|
<TabButton
|
|
181
191
|
active={viewMode === 'messages'}
|
|
182
|
-
onClick={() =>
|
|
192
|
+
onClick={() => handleTabClick('messages')}
|
|
183
193
|
>
|
|
184
194
|
<MessageIcon />
|
|
185
195
|
Messages
|
|
@@ -231,7 +241,13 @@ export default function HistoryPage() {
|
|
|
231
241
|
</div>
|
|
232
242
|
|
|
233
243
|
{/* Content */}
|
|
234
|
-
{
|
|
244
|
+
{!viewMode ? (
|
|
245
|
+
<EmptyState
|
|
246
|
+
icon={<ConversationIcon className="w-12 h-12" />}
|
|
247
|
+
title="Conversation History"
|
|
248
|
+
description="Select a tab above to browse conversations, sessions, or messages."
|
|
249
|
+
/>
|
|
250
|
+
) : isLoading ? (
|
|
235
251
|
<div className="flex items-center justify-center h-[60vh]">
|
|
236
252
|
<div className="flex flex-col items-center gap-4">
|
|
237
253
|
<div className="w-10 h-10 border-2 border-border border-t-accent rounded-full animate-spin" />
|
package/src/app/page.tsx
CHANGED