Skip to content

Commit a8de148

Browse files
committed
Vibes
1 parent 7dcd345 commit a8de148

File tree

6 files changed

+242
-25
lines changed

6 files changed

+242
-25
lines changed

internal/dev_server/ui/dist/index.html

Lines changed: 22 additions & 22 deletions
Large diffs are not rendered by default.

internal/dev_server/ui/src/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Box } from '@launchpad-ui/core';
44
import RouteSelector from './RouteSelector.tsx';
55
import FlagsPage from './FlagsPage.tsx';
66
import EventsPage from './EventsPage.tsx';
7+
import DebugSessionsPage from './DebugSessionsPage.tsx';
78

89
function App() {
910
return (
@@ -33,6 +34,7 @@ function App() {
3334
<Route path="/ui" element={<Navigate to="/ui/flags" replace />} />
3435
<Route path="/ui/flags" element={<FlagsPage />} />
3536
<Route path="/ui/events" element={<EventsPage />} />
37+
<Route path="/ui/debug-sessions" element={<DebugSessionsPage />} />
3638
</Routes>
3739
</Box>
3840
</Box>
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
import { useEffect, useState } from "react";
2+
import { apiRoute } from "./util";
3+
import { DebugSession, DebugSessionsPage as DebugSessionsPageType } from "./types";
4+
import { Box, CopyToClipboard, Alert } from "@launchpad-ui/core";
5+
import { Heading, Text, ProgressBar, Button } from "@launchpad-ui/components";
6+
import { Icon } from "@launchpad-ui/icons";
7+
8+
const DebugSessionsPage = () => {
9+
const [debugSessions, setDebugSessions] = useState<DebugSession[]>([]);
10+
const [loading, setLoading] = useState<boolean>(true);
11+
const [error, setError] = useState<string | null>(null);
12+
const [totalCount, setTotalCount] = useState<number>(0);
13+
14+
const fetchDebugSessions = async () => {
15+
try {
16+
setLoading(true);
17+
setError(null);
18+
19+
const response = await fetch(apiRoute("/dev/debug-sessions?limit=100"));
20+
21+
if (!response.ok) {
22+
throw new Error(`Failed to fetch debug sessions: ${response.status} ${response.statusText}`);
23+
}
24+
25+
const data: DebugSessionsPageType = await response.json();
26+
setDebugSessions(data.sessions);
27+
setTotalCount(data.total_count);
28+
} catch (err) {
29+
setError(err instanceof Error ? err.message : "An unknown error occurred");
30+
} finally {
31+
setLoading(false);
32+
}
33+
};
34+
35+
useEffect(() => {
36+
fetchDebugSessions();
37+
}, []);
38+
39+
const formatDate = (dateString: string) => {
40+
try {
41+
const date = new Date(dateString);
42+
return date.toLocaleString();
43+
} catch {
44+
return dateString;
45+
}
46+
};
47+
48+
if (loading) {
49+
return (
50+
<Box padding="2rem">
51+
<Heading>Debug Sessions</Heading>
52+
<Box marginTop="1rem">
53+
<ProgressBar isIndeterminate />
54+
</Box>
55+
<Box marginTop="1rem">
56+
<Text>Loading debug sessions...</Text>
57+
</Box>
58+
</Box>
59+
);
60+
}
61+
62+
if (error) {
63+
return (
64+
<Box padding="2rem">
65+
<Heading>Debug Sessions</Heading>
66+
<Box marginTop="1rem">
67+
<Alert kind="error">
68+
<Text>Error: {error}</Text>
69+
</Alert>
70+
</Box>
71+
<Box marginTop="1rem">
72+
<Button onPress={fetchDebugSessions}>Retry</Button>
73+
</Box>
74+
</Box>
75+
);
76+
}
77+
78+
return (
79+
<Box padding="2rem">
80+
<Box display="flex" justifyContent="space-between" alignItems="center" marginBottom="1rem">
81+
<Heading>Debug Sessions</Heading>
82+
<Text color="var(--lp-color-text-ui-secondary)">
83+
{totalCount} total session{totalCount !== 1 ? 's' : ''}
84+
</Text>
85+
</Box>
86+
87+
{debugSessions.length === 0 ? (
88+
<Box
89+
padding="2rem"
90+
textAlign="center"
91+
backgroundColor="var(--lp-color-bg-ui-secondary)"
92+
borderRadius="4px"
93+
>
94+
<Icon name="data" size="large" />
95+
<Box marginTop="1rem">
96+
<Text>No debug sessions found</Text>
97+
</Box>
98+
<Box marginTop="0.5rem">
99+
<Text color="var(--lp-color-text-ui-secondary)">
100+
Debug sessions will appear here when events are captured
101+
</Text>
102+
</Box>
103+
</Box>
104+
) : (
105+
<div
106+
style={{
107+
border: "1px solid var(--lp-color-border-ui-primary)",
108+
borderRadius: "4px",
109+
overflow: "hidden"
110+
}}
111+
>
112+
<table style={{ width: "100%", borderCollapse: "collapse" }}>
113+
<thead>
114+
<tr style={{ backgroundColor: "var(--lp-color-bg-ui-secondary)" }}>
115+
<th style={{
116+
padding: "0.75rem",
117+
textAlign: "left",
118+
borderBottom: "1px solid var(--lp-color-border-ui-primary)",
119+
fontWeight: 600
120+
}}>
121+
Session Key
122+
</th>
123+
<th style={{
124+
padding: "0.75rem",
125+
textAlign: "left",
126+
borderBottom: "1px solid var(--lp-color-border-ui-primary)",
127+
fontWeight: 600
128+
}}>
129+
Created At
130+
</th>
131+
<th style={{
132+
padding: "0.75rem",
133+
textAlign: "right",
134+
borderBottom: "1px solid var(--lp-color-border-ui-primary)",
135+
fontWeight: 600
136+
}}>
137+
Event Count
138+
</th>
139+
<th style={{
140+
padding: "0.75rem",
141+
textAlign: "center",
142+
borderBottom: "1px solid var(--lp-color-border-ui-primary)",
143+
fontWeight: 600,
144+
width: "100px"
145+
}}>
146+
Actions
147+
</th>
148+
</tr>
149+
</thead>
150+
<tbody>
151+
{debugSessions.map((session, index) => (
152+
<tr
153+
key={session.key}
154+
style={{
155+
borderBottom: index < debugSessions.length - 1 ? "1px solid var(--lp-color-border-ui-primary)" : "none"
156+
}}
157+
>
158+
<td style={{ padding: "0.75rem" }}>
159+
<Text style={{ fontFamily: "monospace" }}>
160+
{session.key}
161+
</Text>
162+
</td>
163+
<td style={{ padding: "0.75rem" }}>
164+
<Text>
165+
{formatDate(session.written_at)}
166+
</Text>
167+
</td>
168+
<td style={{ padding: "0.75rem", textAlign: "right" }}>
169+
<Text>
170+
{session.event_count.toLocaleString()}
171+
</Text>
172+
</td>
173+
<td style={{ padding: "0.75rem", textAlign: "center" }}>
174+
<CopyToClipboard text={session.key}>
175+
<button
176+
style={{
177+
background: "none",
178+
border: "1px solid var(--lp-color-border-ui-primary)",
179+
borderRadius: "4px",
180+
padding: "0.25rem 0.5rem",
181+
cursor: "pointer",
182+
display: "flex",
183+
alignItems: "center",
184+
gap: "0.25rem"
185+
}}
186+
title="Copy session key"
187+
>
188+
<Icon name="link" size="small" />
189+
</button>
190+
</CopyToClipboard>
191+
</td>
192+
</tr>
193+
))}
194+
</tbody>
195+
</table>
196+
</div>
197+
)}
198+
</Box>
199+
);
200+
};
201+
202+
export default DebugSessionsPage;

internal/dev_server/ui/src/EventsTable.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ const indexRows = (indexEvent: EventData, showNotification: (message: string) =>
5151
let eventText;
5252
if (indexEvent.data.context) {
5353
eventText = (indexEvent.data.context?.kind || 'unknown') + ' context';
54-
} else if (indexEvent.data.user) {
55-
eventText = (indexEvent.data.user.key || 'unknown') + ' user';
54+
} else if ((indexEvent.data as any).user) {
55+
eventText = ((indexEvent.data as any).user.key || 'unknown') + ' user';
5656
}
5757
else {
5858
eventText = 'unknown context';

internal/dev_server/ui/src/RouteSelector.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ const RouteSelector = () => {
99

1010
const options = [
1111
{ key: '/ui/flags', label: 'Flags' },
12-
{ key: '/ui/events', label: 'Events' }
12+
{ key: '/ui/events', label: 'Events' },
13+
{ key: '/ui/debug-sessions', label: 'Debug Sessions' }
1314
];
1415

1516
const currentPath = location.pathname === '/' ? '/ui' : location.pathname;

internal/dev_server/ui/src/types.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,15 @@ export interface EventData {
4646
timestamp: number;
4747
data: SummaryEventPayload | FeatureEventPayload | IndexEventPayload | GenericEventPayload;
4848
}
49+
50+
export interface DebugSession {
51+
key: string;
52+
written_at: string;
53+
event_count: number;
54+
}
55+
56+
export interface DebugSessionsPage {
57+
sessions: DebugSession[];
58+
total_count: number;
59+
has_more: boolean;
60+
}

0 commit comments

Comments
 (0)