'use client'; import { useState, useEffect } from 'react'; import Link from 'next/link'; import { Button } from '@/components/ui/button'; import { RefreshCw, CheckCircle2, XCircle, AlertTriangle, Clock, Loader2, ChevronRight } from 'lucide-react'; import { PageHeader } from '@/components/navigation/page-header'; interface IntegrationCard { id: string; category: string; product: string; description: string; href: string; logo: string; color: string; } const INTEGRATIONS: IntegrationCard[] = [ { id: 'autotask', category: 'PSA', product: 'Autotask', description: 'Tickets, companies, contacts, time entries, configuration items', href: '/admin/sync/autotask', logo: '/logos/autotask.ico', color: 'red' }, { id: 'itglue', category: 'Documentation', product: 'IT Glue', description: 'Organizations, configurations, contacts, passwords, flexible assets, documents, domains', href: '/admin/sync/itglue', logo: '/logos/itglue.ico', color: 'blue' }, { id: 'veeam', category: 'Backup', product: 'Veeam VSPC', description: 'Agent jobs, backup jobs, protected workloads, compliance', href: '/admin/sync/veeam', logo: '/logos/veeam.ico', color: 'green' }, { id: 'datto-rmm', category: 'RMM', product: 'Datto RMM', description: 'Device monitoring, alerts, patch management, remote access', href: '/admin/sync/datto-rmm', logo: '/logos/datto-rmm.ico', color: 'orange' }, { id: 'auvik', category: 'NMS', product: 'Auvik', description: 'Network devices, topology, tenant mappings', href: '/admin/sync/auvik', logo: '/logos/auvik.ico', color: 'purple' }, { id: 'addigy', category: 'Apple RMM', product: 'Addigy', description: 'macOS/iOS device management, policies, compliance', href: '/admin/sync/addigy', logo: '/logos/addigy.ico', color: 'gray' }, { id: 'sentinelone', category: 'EDR/AV', product: 'SentinelOne', description: 'Endpoint agents, threat detections, site coverage, AV health', href: '/admin/sync/sentinelone', logo: '/logos/sentinelone.ico', color: 'purple' }, { id: 'mimecast', category: 'Email Security', product: 'Mimecast', description: 'Message tracking logs, threat events, SIEM data, 120-day retention', href: '/admin/sync/mimecast', logo: '/logos/mimecast.ico', color: 'blue' }, { id: 'duo', category: '2FA / MFA', product: 'Duo Security', description: 'Users, phones, auth logs, groups, integrations across all child accounts', href: '/admin/sync/duo', logo: '/logos/duo.ico', color: 'green' }, ]; const COLOR_MAP: Record = { red: { bg: 'bg-red-500/5', border: 'border-red-500/20' }, green: { bg: 'bg-green-500/5', border: 'border-green-500/20' }, blue: { bg: 'bg-blue-500/5', border: 'border-blue-500/20' }, orange: { bg: 'bg-orange-500/5', border: 'border-orange-500/20' }, purple: { bg: 'bg-purple-500/5', border: 'border-purple-500/20' }, gray: { bg: 'bg-muted/20', border: 'border-border' }, }; function fmtDate(d: string | null) { if (!d) return 'Never'; const date = new Date(d); const diff = Date.now() - date.getTime(); const mins = Math.floor(diff / 60000); if (mins < 1) return 'Just now'; if (mins < 60) return `${mins}m ago`; const hrs = Math.floor(mins / 60); if (hrs < 24) return `${hrs}h ago`; return `${Math.floor(hrs / 24)}d ago`; } export default function SyncOverviewPage() { const [status, setStatus] = useState(null); const [autotaskSync, setAutotaskSync] = useState(null); const [loading, setLoading] = useState(true); const [itglueSyncData, setItglueSyncData] = useState(null); const [s1SyncData, setS1SyncData] = useState(null); const [mimecastData, setMimecastData] = useState(null); const [duoData, setDuoData] = useState(null); const fetchAll = async () => { try { const [intRes, atRes, itgRes, s1Res, mcRes, duoRes] = await Promise.all([ fetch('/api/integrations/status'), fetch('/api/sync/last-sync'), fetch('/api/itglue/sync'), fetch('/api/sentinelone/sync'), fetch('/api/mimecast/status'), fetch('/api/duo/status'), ]); if (intRes.ok) setStatus(await intRes.json()); if (atRes.ok) { const d = await atRes.json(); setAutotaskSync(d.lastSync || {}); } if (itgRes.ok) setItglueSyncData(await itgRes.json()); if (s1Res.ok) setS1SyncData(await s1Res.json()); if (mcRes.ok) setMimecastData(await mcRes.json()); if (duoRes.ok) setDuoData(await duoRes.json()); } catch (e) { console.error(e); } finally { setLoading(false); } }; useEffect(() => { fetchAll(); }, []); const getAutotaskSummary = () => { if (!autotaskSync) return null; const entries = Object.values(autotaskSync) as any[]; if (!entries.length) return null; const latest = entries.reduce((a: any, b: any) => new Date(a.completed_at) > new Date(b.completed_at) ? a : b ); const failed = entries.filter((e: any) => e.status === 'failed').length; return { lastSync: latest.completed_at, failed, total: entries.length }; }; const atSummary = getAutotaskSummary(); const getSummary = (id: string) => { if (!status) return null; if (id === 'autotask') return atSummary; if (id === 'veeam') { const v = status.veeam; if (!v) return null; const aj = v.agentJobs ?? {}; const bj = v.backupJobs ?? {}; return { lastSync: v.lastSync, failed: (aj.failed ?? 0) + (bj.failed ?? 0), warning: (aj.warning ?? 0) + (bj.warning ?? 0), running: aj.running ?? 0, total: (aj.total ?? 0) + (bj.total ?? 0), }; } if (id === 'datto-rmm') { const d = status.dattoRmm; if (!d) return null; return { lastSync: d.lastSync, sites: d.sites ?? 0, devices: d.devices?.total ?? 0, online: d.devices?.online ?? 0, offline: d.devices?.offline ?? 0, openAlerts: d.openAlerts?.total ?? 0, critical: d.openAlerts?.critical ?? 0, }; } if (id === 'itglue') { if (!itglueSyncData) return null; const h = itglueSyncData.history?.[0]; const c = itglueSyncData.counts ?? {}; return { lastSync: h?.completed_at ?? null, organizations: Number(c.organizations ?? 0), configurations: Number(c.configurations ?? 0), totalUpserted: h?.total_upserted ?? 0, status: h?.status ?? null, }; } if (id === 'sentinelone') { if (!s1SyncData) return null; const h = s1SyncData.history?.[0]; const c = s1SyncData.counts ?? {}; return { lastSync: h?.completed_at ?? null, status: h?.status ?? null, sites: Number(c.sites ?? 0), agents: Number(c.agents ?? 0), infected: Number(c.infected ?? 0), threats: Number(c.threats ?? 0), }; } if (id === 'auvik') return { lastSync: status.auvik?.lastSync, configured: status.auvik?.configured }; if (id === 'addigy') return { lastSync: status.addigy?.lastSync, configured: status.addigy?.configured }; if (id === 'mimecast') { if (!mimecastData) return null; const s = mimecastData.stats ?? {}; return { lastSync: s.lastSync ?? null, connected: mimecastData.connected ?? false, messages: s.messages ?? 0, threats: s.threats ?? 0, }; } if (id === 'duo') { if (!duoData) return null; const c = duoData.counts ?? {}; return { lastSync: duoData.lastSync ?? null, connected: duoData.connected ?? false, accounts: c.accounts ?? 0, users: c.users ?? 0, phones: c.phones ?? 0, authLogs: c.authLogs ?? 0, bypass: c.bypass ?? 0, }; } return null; }; const getStatusIcon = (id: string, summary: any) => { if (!summary) return ; if (id === 'veeam') { if (summary.failed > 0) return ; if (summary.warning > 0 || summary.running > 0) return ; return ; } if (id === 'autotask') { if (summary.failed > 0) return ; return ; } if (id === 'datto-rmm') { if (summary.critical > 0) return ; if (summary.openAlerts > 0) return ; return ; } if (id === 'itglue') { if (!summary.lastSync) return ; if (summary.status === 'failed') return ; return ; } if (id === 'sentinelone') { if (!summary.lastSync) return ; if (summary.infected > 0) return ; return ; } if (id === 'mimecast') { if (!summary.connected) return ; if ((summary as any).threats > 0) return ; return ; } if (id === 'duo') { if (!summary.connected) return ; if ((summary as any).bypass > 0) return ; return ; } return ; }; return ( <> Refresh } />
{loading ? (
) : (
{INTEGRATIONS.map((intg) => { const colors = COLOR_MAP[intg.color]; const summary = getSummary(intg.id); return (
{/* Header: logo + names + chevron */}
{intg.product}

{intg.category}

{intg.product} {summary && getStatusIcon(intg.id, summary)}
{/* Description */}

{intg.description}

{/* Stats — pushed to bottom */}
{intg.id === 'autotask' && summary && ( <>
Last sync {fmtDate(summary.lastSync)}
Entities tracked {summary.total}
)} {intg.id === 'veeam' && summary && ( <>
Last sync {fmtDate(summary.lastSync)}
Total jobs {summary.total}
{(summary as any).failed > 0 && (
Failed{(summary as any).failed}
)} {(summary as any).running > 0 && (
Running (stalled?){(summary as any).running}
)} {(summary as any).warning > 0 && (
Warning{(summary as any).warning}
)} )} {intg.id === 'datto-rmm' && summary && ( <>
Last sync {fmtDate(summary.lastSync)}
Sites / Devices {(summary as any).sites} / {(summary as any).devices}
Online / Offline {(summary as any).online} / {(summary as any).offline}
{(summary as any).openAlerts > 0 && (
0 ? 'text-red-600' : 'text-yellow-700'}`}> Open alerts {(summary as any).openAlerts}
)} )} {intg.id === 'itglue' && summary && ( <>
Last sync {fmtDate(summary.lastSync)}
Organizations {(summary as any).organizations?.toLocaleString()}
Configurations {(summary as any).configurations?.toLocaleString()}
)} {intg.id === 'sentinelone' && summary && ( <>
Last sync {fmtDate(summary.lastSync)}
Sites / Agents {(summary as any).sites} / {(summary as any).agents?.toLocaleString()}
{(summary as any).infected > 0 && (
Infected {(summary as any).infected}
)} )} {intg.id === 'mimecast' && summary && ( <>
Last sync {fmtDate((summary as any).lastSync)}
Messages {((summary as any).messages ?? 0).toLocaleString()}
{(summary as any).threats > 0 && (
Threat events {(summary as any).threats}
)} )} {intg.id === 'duo' && summary && ( <>
Last sync {fmtDate((summary as any).lastSync)}
Accounts / Users {(summary as any).accounts} / {(summary as any).users?.toLocaleString()}
Phones {(summary as any).phones?.toLocaleString()}
Auth logs {(summary as any).authLogs?.toLocaleString()}
{(summary as any).bypass > 0 && (
Bypass (MFA skipped) {(summary as any).bypass}
)} )} {(intg.id === 'auvik' || intg.id === 'addigy') && (
Status {(summary as any)?.configured ? 'Connected' : 'Not configured'}
)}
); })}
)}
); }