'use client';
import { useState, useEffect } from 'react';
import { Button } from '@/components/ui/button';
import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs';
import {
Shield, Monitor, Network, Apple,
CheckCircle2, XCircle, AlertTriangle, RefreshCw, Loader2,
Server, HardDrive, Cpu, Clock,
} from 'lucide-react';
import { useUserTimezone } from '@/lib/hooks/use-user-timezone';
function StatusDot({ ok, warn }: { ok: boolean; warn?: boolean }) {
if (!ok) return ;
if (warn) return ;
return ;
}
function StatCard({ label, value, sub, icon: Icon, cls }: {
label: string; value: string | number; sub?: string;
icon?: React.ElementType; cls?: string;
}) {
return (
{Icon && }
{label}
{value}
{sub &&
{sub}
}
);
}
function fmtDate(d: string | null, tz: string) {
if (!d) return 'Never';
return new Date(d).toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', timeZone: tz });
}
function VeeamTab({ data, onSync, syncing, tz }: { data: any; onSync: () => void; syncing: boolean; tz: string }) {
if (!data) return
;
const aj = data.agentJobs ?? {};
const bj = data.backupJobs ?? {};
const totalFailed = (aj.failed ?? 0) + (bj.failed ?? 0);
const totalWarning = (aj.warning ?? 0) + (bj.warning ?? 0);
const totalRunning = aj.running ?? 0;
return (
0 || totalWarning > 0} />
{data.configured ? 'Connected to VSPC' : 'Not configured'}
Last sync: {fmtDate(data.lastSync, tz)}
{syncing ? : }
Sync Now
0 ? 'border-blue-500/30 bg-blue-500/5' : ''} />
0 ? 'border-red-500/30 bg-red-500/5' : ''} />
0 ? 'border-yellow-500/30 bg-yellow-500/5' : ''} />
{(totalFailed > 0 || totalWarning > 0 || totalRunning > 0) && (
Attention Required
{totalFailed > 0 && (
{totalFailed} job{totalFailed !== 1 ? 's' : ''} failed
)}
{totalWarning > 0 && (
{totalWarning} job{totalWarning !== 1 ? 's' : ''} completed with warnings
)}
{totalRunning > 0 && (
{totalRunning} job{totalRunning !== 1 ? 's' : ''} running (stalled jobs appear here)
)}
)}
);
}
function DattoRmmTab({ data, onSync, syncing }: { data: any; onSync: () => void; syncing: boolean }) {
if (!data) return
;
const unlinked = Math.max(0, (data.totalConfigItems ?? 0) - (data.rmmLinkedDevices ?? 0));
return (
{data.configured ? 'Connected' : 'Not configured'}
{data.apiUrl}
0 ? 'border-yellow-500/30 bg-yellow-500/5' : ''} />
Datto RMM device data is queried live via the RMM API when investigating alerts.
Device records link to Autotask Configuration Items via rmm_device_uid.
Run an Autotask Configuration Items sync to refresh CI data.
);
}
function AuvikTab({ data }: { data: any }) {
if (!data) return
;
return (
{data.configured ? 'Connected' : 'Not configured'}
{data.apiUrl}
Open Portal
Auvik provides network topology and device data. The API is configured and accessible.
Full sync and dashboard integration is planned — data is currently available via the Auvik API endpoints
at /api/auvik/devices and /api/auvik/tenant-mappings.
);
}
function AddigyTab({ data }: { data: any }) {
if (!data) return
;
return (
{data.configured ? 'Connected' : 'Not configured'}
{data.apiUrl}
Open Portal
Addigy manages Apple (macOS/iOS) devices. The API is configured and accessible via token auth.
Device and policy data is available via /api/addigy-devices and /api/addigy-policies.
Full sync integration is planned.
);
}
export default function IntegrationStatusTabs() {
const tz = useUserTimezone();
const [status, setStatus] = useState(null);
const [loading, setLoading] = useState(true);
const [veeamSyncing, setVeeamSyncing] = useState(false);
const [rmmSyncing, setRmmSyncing] = useState(false);
const fetchStatus = async () => {
try {
const res = await fetch('/api/integrations/status');
if (res.ok) setStatus(await res.json());
} catch (e) {
console.error('Failed to fetch integration status:', e);
} finally {
setLoading(false);
}
};
useEffect(() => { fetchStatus(); }, []);
const handleVeeamSync = async () => {
setVeeamSyncing(true);
try {
await fetch('/api/veeam/sync', { method: 'POST', body: JSON.stringify({ syncType: 'full' }), headers: { 'Content-Type': 'application/json' } });
// Poll until done
const poll = setInterval(async () => {
const r = await fetch('/api/veeam/sync');
if (r.ok) {
const d = await r.json();
if (!d.isSyncing) {
clearInterval(poll);
setVeeamSyncing(false);
fetchStatus();
}
}
}, 3000);
} catch {
setVeeamSyncing(false);
}
};
const handleRmmSync = async () => {
setRmmSyncing(true);
try {
await fetch('/api/sync/entity', {
method: 'POST',
body: JSON.stringify({ entities: ['configuration_items'] }),
headers: { 'Content-Type': 'application/json' },
});
setTimeout(() => { setRmmSyncing(false); fetchStatus(); }, 5000);
} catch {
setRmmSyncing(false);
}
};
if (loading) {
return (
);
}
return (
Veeam
Datto RMM
Auvik
Addigy
);
}