'use client'; import { useEffect, useState } from 'react'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Skeleton } from '@/components/ui/skeleton'; import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import { Loader2, RefreshCw, Terminal } from 'lucide-react'; import { toast } from 'sonner'; import { PageHeader } from '@/components/navigation/page-header'; interface Settings { overshellComponentUid: string | null; overshellComponentName: string | null; overshellVariableName: string; discoveredAt: string | null; logliftComponentUid: string | null; logliftComponentName: string | null; logliftDiscoveredAt: string | null; updatedAt: string; } interface ExecRow { id: string; scriptId: string; jobName: string; targetHostname: string | null; status: 'queued' | 'running' | 'complete' | 'failed' | 'timeout'; exitCode: number | null; errorMessage: string | null; performedByUserId: string | null; queuedAt: string; completedAt: string | null; } export default function RmmOvershellAdminPage() { const [settings, setSettings] = useState(null); const [counts, setCounts] = useState<{ total: string; running: string; failed_24h: string } | null>(null); const [executions, setExecutions] = useState(null); const [error, setError] = useState(null); const [discovering, setDiscovering] = useState(false); const [discoveringLoglift, setDiscoveringLoglift] = useState(false); async function loadAll() { try { const [s, e] = await Promise.all([ fetch('/api/admin/rmm/settings').then((r) => r.json()), fetch('/api/rmm/executions?limit=50').then((r) => r.json()), ]); if (s.error) throw new Error(s.error); setSettings(s.settings); setCounts(s.counts); setExecutions(e.executions ?? []); setError(null); } catch (err) { setError(err instanceof Error ? err.message : 'Unknown error'); } } useEffect(() => { void loadAll(); }, []); async function discover() { setDiscovering(true); try { const res = await fetch('/api/admin/rmm/settings/discover', { method: 'POST' }); const data = await res.json(); if (!res.ok) throw new Error(data.message ?? data.error ?? 'Discovery failed'); toast.success(`Found component: ${data.discovered?.name ?? 'unknown'}`); void loadAll(); } catch (err) { toast.error(err instanceof Error ? err.message : 'Discovery failed'); } finally { setDiscovering(false); } } async function discoverLoglift() { setDiscoveringLoglift(true); try { const res = await fetch('/api/admin/rmm/settings/discover-loglift', { method: 'POST', }); const data = await res.json(); if (!res.ok) throw new Error(data.message ?? data.error ?? 'Discovery failed'); toast.success(`Found LogLift component: ${data.discovered?.name ?? 'unknown'}`); void loadAll(); } catch (err) { toast.error(err instanceof Error ? err.message : 'Discovery failed'); } finally { setDiscoveringLoglift(false); } } return ( <>
RMM Overshell

Datto RMM PowerShell evidence pipeline. Pulse dispatches scripts via the configured Overshell component; the worker polls for results and the audit pipeline pulls them in as live evidence.

{error && ( Couldn’t load settings {error} )} {settings === null && !error ? ( ) : settings ? (

Overshell component

{settings.overshellComponentUid ? ( <>

{settings.overshellComponentName}

{settings.overshellComponentUid}

{settings.discoveredAt && (

discovered {new Date(settings.discoveredAt).toLocaleString()}

)} ) : (

No component cached. Click Discover to scan Datto RMM.

)}

Variable name

{settings.overshellVariableName}

Adjust if your component uses a different variable.

Activity (24h)

{counts?.total ?? '0'} total · {counts?.running ?? '0'} running · {' '} {counts?.failed_24h ?? '0'} failed

LogLift component

{settings.logliftComponentUid ? ( <>

{settings.logliftComponentName}

{settings.logliftComponentUid}

{settings.logliftDiscoveredAt && (

discovered{' '} {new Date(settings.logliftDiscoveredAt).toLocaleString()}

)} ) : (

No LogLift component cached. Click below to scan Datto RMM for one named “loglift” or “eventlog”.

)}
) : null}
Recent executions {executions === null ? ( ) : executions.length === 0 ? (

No executions yet.

) : (
    {executions.map((e) => (
  • {e.scriptId} {e.targetHostname ?? '—'} {e.status} {e.exitCode !== null ? ` · exit ${e.exitCode}` : ''} {new Date(e.queuedAt).toLocaleString()} {e.errorMessage && ( ! )}
  • ))}
)}
); }