85 lines
2.5 KiB
TypeScript
85 lines
2.5 KiB
TypeScript
/**
|
|
* JobsTab — operational content for the backups service page.
|
|
*
|
|
* Instance-scoped: hooks filter by instance.id so multi-instance setups
|
|
* show only the selected backups service's jobs, runs, and alerts.
|
|
*/
|
|
import { useState } from "react";
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
|
import {
|
|
useAcknowledgeAlert,
|
|
useBackupAlerts,
|
|
useBackupJobs,
|
|
useBackupRuns,
|
|
} from "../../hooks/useBackups";
|
|
import BackupAlertsTable from "../../components/BackupAlertsTable";
|
|
import BackupJobsTable from "../../components/BackupJobsTable";
|
|
import BackupRunsTable from "../../components/BackupRunsTable";
|
|
import type { ServiceInstance } from "../../types";
|
|
|
|
export function JobsTab({ instance }: { instance: ServiceInstance }) {
|
|
const [tab, setTab] = useState("jobs");
|
|
const { data: jobsData, isLoading: jobsLoading } = useBackupJobs(instance.id);
|
|
const { data: runsData, isLoading: runsLoading } = useBackupRuns(
|
|
undefined,
|
|
undefined,
|
|
instance.id,
|
|
);
|
|
const { data: alertsData, isLoading: alertsLoading } = useBackupAlerts(
|
|
undefined,
|
|
false,
|
|
undefined,
|
|
instance.id,
|
|
);
|
|
const acknowledgeMutation = useAcknowledgeAlert();
|
|
|
|
// Build a map of latest runs per job
|
|
const latestRuns = new Map();
|
|
if (runsData) {
|
|
for (const run of runsData) {
|
|
const existing = latestRuns.get(run.job_id);
|
|
if (!existing || run.started_at > existing.started_at) {
|
|
latestRuns.set(run.job_id, run);
|
|
}
|
|
}
|
|
}
|
|
|
|
const alertsLabel = alertsData ? `Alerts (${alertsData.length})` : "Alerts";
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
<Tabs value={tab} onValueChange={setTab}>
|
|
<TabsList>
|
|
<TabsTrigger value="jobs">Jobs</TabsTrigger>
|
|
<TabsTrigger value="runs">Runs</TabsTrigger>
|
|
<TabsTrigger value="alerts">{alertsLabel}</TabsTrigger>
|
|
</TabsList>
|
|
<TabsContent value="jobs">
|
|
{jobsLoading ? (
|
|
<p className="text-sm text-muted-foreground">Loading jobs…</p>
|
|
) : (
|
|
<BackupJobsTable jobs={jobsData ?? []} latestRuns={latestRuns} />
|
|
)}
|
|
</TabsContent>
|
|
<TabsContent value="runs">
|
|
{runsLoading ? (
|
|
<p className="text-sm text-muted-foreground">Loading runs…</p>
|
|
) : (
|
|
<BackupRunsTable runs={runsData ?? []} />
|
|
)}
|
|
</TabsContent>
|
|
<TabsContent value="alerts">
|
|
{alertsLoading ? (
|
|
<p className="text-sm text-muted-foreground">Loading alerts…</p>
|
|
) : (
|
|
<BackupAlertsTable
|
|
alerts={alertsData ?? []}
|
|
onAcknowledge={(id) => acknowledgeMutation.mutate(id)}
|
|
/>
|
|
)}
|
|
</TabsContent>
|
|
</Tabs>
|
|
</div>
|
|
);
|
|
}
|