feat: RMM Overshell, IT Glue audit/write-back, LogLift, link-aware bundles, dashboard overhaul

- RMM Overshell (migration 077): admin page, dispatch UI, executor/worker, target
  resolver, script registry (AD/DHCP/DNS/event-log/services/software/network/loglift)
- LogLift evidence pipeline (migration 078): upload webhook, B2 storage client,
  receiver/matcher, EventLogCollector PowerShell script
- IT Glue audit + write-back (migrations 075, 076): asset-audit runner, ticket
  xrefs, applications/configurations browse pages + apply/revert/audit endpoints
- Link-aware analyzer bundles (migration 073) + provider toggle (migration 074):
  link-discovery service, OpenRouter LLM provider, related-tickets/itglue-suggestion
  panels, analyze-bundle endpoint
- Endpoint data model + device-link reconciliation (migrations 079, 080): conflicts
  admin page, reconciler service, resolve endpoints
- Dashboard overhaul: integration-health service + alerts, overview/health endpoints
- Permissions: add itglue + rmm scopes; middleware: public /api/rmm/loglift route

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
lorentz 2026-05-03 07:13:18 -04:00
parent 378e68ad8a
commit 1112a06afe
132 changed files with 21352 additions and 743 deletions

View file

@ -10,7 +10,7 @@ import { Switch } from '@/components/ui/switch';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
import { Alert, AlertDescription } from '@/components/ui/alert';
import { Clock, Play, Pause, Trash2, Plus, Calendar, AlertCircle, CheckCircle2, XCircle } from 'lucide-react';
import { Clock, Play, Pause, Trash2, Plus, Calendar, AlertCircle, CheckCircle2, XCircle, RefreshCw } from 'lucide-react';
interface ScheduleConfig {
id: string;
@ -37,6 +37,7 @@ interface ScheduleStatus {
export default function SyncScheduler() {
const [schedules, setSchedules] = useState<ScheduleStatus[]>([]);
const [reloading, setReloading] = useState(false);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [editingSchedule, setEditingSchedule] = useState<ScheduleConfig | null>(null);
@ -90,6 +91,20 @@ export default function SyncScheduler() {
}
};
const reloadSchedules = async () => {
setReloading(true);
try {
const res = await fetch('/api/sync/schedules/reload', { method: 'POST' });
const data = await res.json();
if (!res.ok) throw new Error(data.error ?? `HTTP ${res.status}`);
await fetchSchedules();
} catch (err) {
alert(`Reload failed: ${err instanceof Error ? err.message : err}`);
} finally {
setReloading(false);
}
};
const toggleSchedule = async (scheduleId: string, currentState: boolean) => {
try {
const response = await fetch(`/api/sync/schedules/${scheduleId}`, {
@ -259,10 +274,16 @@ export default function SyncScheduler() {
Manage automatic sync schedules
</CardDescription>
</div>
<Button onClick={openCreateDialog}>
<Plus className="h-4 w-4 mr-2" />
New Schedule
</Button>
<div className="flex items-center gap-2">
<Button variant="outline" onClick={reloadSchedules} disabled={reloading}>
<RefreshCw className={`h-4 w-4 mr-2 ${reloading ? 'animate-spin' : ''}`} />
{reloading ? 'Reloading…' : 'Reload from DB'}
</Button>
<Button onClick={openCreateDialog}>
<Plus className="h-4 w-4 mr-2" />
New Schedule
</Button>
</div>
</div>
</CardHeader>
<CardContent>