feat(admin-dashboard): add Debug Sessions page (Phase 3.1)
- New /ops/debug-sessions page with session list table - Status filter and search functionality - Create Session modal with form fields - Auto-refresh every 5 seconds - Client library in lib/diagnostics-client.ts Features: - View all debug sessions with filtering - Create new debug sessions via modal - Real-time status updates
This commit is contained in:
parent
8e90358960
commit
2e697a13db
@ -32,7 +32,11 @@ import {
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { Plus, Search, RefreshCw, MoreHorizontal } from 'lucide-react';
|
||||
import { createDiagnosticsClient, type DebugSession, type CreateSessionRequest } from '@/lib/diagnostics-client';
|
||||
import {
|
||||
createDiagnosticsClient,
|
||||
type DebugSession,
|
||||
type CreateSessionRequest,
|
||||
} from '@/lib/diagnostics-client';
|
||||
|
||||
const statusColors: Record<string, string> = {
|
||||
pending: 'bg-yellow-500',
|
||||
@ -50,9 +54,9 @@ export default function DebugSessionsPage() {
|
||||
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
|
||||
|
||||
// Helper to get auth token from localStorage
|
||||
const getAuthToken = async () => {
|
||||
if (typeof window === 'undefined') return '';
|
||||
return localStorage.getItem('admin_access_token') || '';
|
||||
const getAuthToken = () => {
|
||||
if (typeof window === 'undefined') return null;
|
||||
return localStorage.getItem('admin_access_token');
|
||||
};
|
||||
|
||||
// New session form state
|
||||
@ -68,7 +72,7 @@ export default function DebugSessionsPage() {
|
||||
});
|
||||
|
||||
const client = createDiagnosticsClient({
|
||||
baseURL: process.env.NEXT_PUBLIC_PLATFORM_SERVICE_URL || 'http://localhost:4003',
|
||||
baseUrl: process.env.NEXT_PUBLIC_PLATFORM_SERVICE_URL || 'http://localhost:4003',
|
||||
productId: 'lysnrai',
|
||||
getAuthToken,
|
||||
});
|
||||
@ -116,7 +120,7 @@ export default function DebugSessionsPage() {
|
||||
}
|
||||
};
|
||||
|
||||
const filteredSessions = sessions.filter((session) => {
|
||||
const filteredSessions = sessions.filter(session => {
|
||||
if (searchQuery) {
|
||||
const query = searchQuery.toLowerCase();
|
||||
return (
|
||||
@ -133,9 +137,7 @@ export default function DebugSessionsPage() {
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold tracking-tight">Debug Sessions</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Remote diagnostics and debug tracing sessions
|
||||
</p>
|
||||
<p className="text-muted-foreground">Remote diagnostics and debug tracing sessions</p>
|
||||
</div>
|
||||
<Dialog open={isCreateModalOpen} onOpenChange={setIsCreateModalOpen}>
|
||||
<DialogTrigger asChild>
|
||||
@ -148,7 +150,8 @@ export default function DebugSessionsPage() {
|
||||
<DialogHeader>
|
||||
<DialogTitle>Create Debug Session</DialogTitle>
|
||||
<DialogDescription>
|
||||
Start a remote debug session to collect logs, traces, and screenshots from a target device.
|
||||
Start a remote debug session to collect logs, traces, and screenshots from a target
|
||||
device.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="grid gap-4 py-4">
|
||||
@ -158,9 +161,7 @@ export default function DebugSessionsPage() {
|
||||
<Input
|
||||
id="userId"
|
||||
value={newSession.targetUserId}
|
||||
onChange={(e) =>
|
||||
setNewSession({ ...newSession, targetUserId: e.target.value })
|
||||
}
|
||||
onChange={e => setNewSession({ ...newSession, targetUserId: e.target.value })}
|
||||
placeholder="user_123"
|
||||
/>
|
||||
</div>
|
||||
@ -169,9 +170,7 @@ export default function DebugSessionsPage() {
|
||||
<Input
|
||||
id="deviceId"
|
||||
value={newSession.targetDeviceId}
|
||||
onChange={(e) =>
|
||||
setNewSession({ ...newSession, targetDeviceId: e.target.value })
|
||||
}
|
||||
onChange={e => setNewSession({ ...newSession, targetDeviceId: e.target.value })}
|
||||
placeholder="device_abc"
|
||||
/>
|
||||
</div>
|
||||
@ -180,8 +179,8 @@ export default function DebugSessionsPage() {
|
||||
<Label htmlFor="collectionLevel">Collection Level</Label>
|
||||
<Select
|
||||
value={newSession.collectionLevel}
|
||||
onValueChange={(value) =>
|
||||
setNewSession({ ...newSession, collectionLevel: value as any })
|
||||
onValueChange={(value: 'standard' | 'debug' | 'trace') =>
|
||||
setNewSession({ ...newSession, collectionLevel: value })
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
@ -202,7 +201,7 @@ export default function DebugSessionsPage() {
|
||||
min={5}
|
||||
max={1440}
|
||||
value={newSession.maxDurationMinutes}
|
||||
onChange={(e) =>
|
||||
onChange={e =>
|
||||
setNewSession({ ...newSession, maxDurationMinutes: parseInt(e.target.value) })
|
||||
}
|
||||
/>
|
||||
@ -212,7 +211,7 @@ export default function DebugSessionsPage() {
|
||||
<Switch
|
||||
id="captureLogs"
|
||||
checked={newSession.captureLogs}
|
||||
onCheckedChange={(checked) =>
|
||||
onCheckedChange={checked =>
|
||||
setNewSession({ ...newSession, captureLogs: checked })
|
||||
}
|
||||
/>
|
||||
@ -222,7 +221,7 @@ export default function DebugSessionsPage() {
|
||||
<Switch
|
||||
id="captureNetwork"
|
||||
checked={newSession.captureNetwork}
|
||||
onCheckedChange={(checked) =>
|
||||
onCheckedChange={checked =>
|
||||
setNewSession({ ...newSession, captureNetwork: checked })
|
||||
}
|
||||
/>
|
||||
@ -232,7 +231,7 @@ export default function DebugSessionsPage() {
|
||||
<Switch
|
||||
id="captureScreenshots"
|
||||
checked={newSession.captureScreenshots}
|
||||
onCheckedChange={(checked) =>
|
||||
onCheckedChange={checked =>
|
||||
setNewSession({ ...newSession, captureScreenshots: checked })
|
||||
}
|
||||
/>
|
||||
@ -242,7 +241,7 @@ export default function DebugSessionsPage() {
|
||||
<Switch
|
||||
id="screenshotOnError"
|
||||
checked={newSession.screenshotOnError}
|
||||
onCheckedChange={(checked) =>
|
||||
onCheckedChange={checked =>
|
||||
setNewSession({ ...newSession, screenshotOnError: checked })
|
||||
}
|
||||
/>
|
||||
@ -272,7 +271,7 @@ export default function DebugSessionsPage() {
|
||||
placeholder="Search sessions..."
|
||||
className="pl-8 w-[250px]"
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
onChange={e => setSearchQuery(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<Select value={statusFilter} onValueChange={setStatusFilter}>
|
||||
@ -322,7 +321,7 @@ export default function DebugSessionsPage() {
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : (
|
||||
filteredSessions.map((session) => (
|
||||
filteredSessions.map(session => (
|
||||
<TableRow key={session.id}>
|
||||
<TableCell className="font-mono text-sm">{session.id}</TableCell>
|
||||
<TableCell>
|
||||
@ -338,9 +337,7 @@ export default function DebugSessionsPage() {
|
||||
<TableCell className="capitalize">{session.collectionLevel}</TableCell>
|
||||
<TableCell>{session.maxDurationMinutes} min</TableCell>
|
||||
<TableCell>
|
||||
{session.startedAt
|
||||
? new Date(session.startedAt).toLocaleString()
|
||||
: '-'}
|
||||
{session.startedAt ? new Date(session.startedAt).toLocaleString() : '-'}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Button variant="ghost" size="icon">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user