import { pb } from "@/lib/stores" import { alertInfo, cn } from "@/lib/utils" import { Switch } from "@/components/ui/switch" import { AlertInfo, AlertRecord, SystemRecord } from "@/types" import { lazy, Suspense, useRef, useState } from "react" import { toast } from "../ui/use-toast" import { RecordOptions } from "pocketbase" import { Trans, t, Plural } from "@lingui/macro" interface AlertData { checked?: boolean val?: number min?: number updateAlert?: (checked: boolean, value: number, min: number) => void key: keyof typeof alertInfo alert: AlertInfo system: SystemRecord } const Slider = lazy(() => import("@/components/ui/slider")) const failedUpdateToast = () => toast({ title: t`Failed to update alert`, description: t`Please check logs for more details.`, variant: "destructive", }) export function SystemAlert({ system, systemAlerts, data, }: { system: SystemRecord systemAlerts: AlertRecord[] data: AlertData }) { const alert = systemAlerts.find((alert) => alert.name === data.key) data.updateAlert = async (checked: boolean, value: number, min: number) => { try { if (alert && !checked) { await pb.collection("alerts").delete(alert.id) } else if (alert && checked) { await pb.collection("alerts").update(alert.id, { value, min, triggered: false }) } else if (checked) { pb.collection("alerts").create({ system: system.id, user: pb.authStore.record!.id, name: data.key, value: value, min: min, }) } } catch (e) { failedUpdateToast() } } if (alert) { data.checked = true data.val = alert.value data.min = alert.min || 1 } return } export function SystemAlertGlobal({ data, overwrite, alerts, systems, }: { data: AlertData overwrite: boolean | "indeterminate" alerts: AlertRecord[] systems: SystemRecord[] }) { const systemsWithExistingAlerts = useRef<{ set: Set; populatedSet: boolean }>({ set: new Set(), populatedSet: false, }) data.checked = false data.val = data.min = 0 data.updateAlert = async (checked: boolean, value: number, min: number) => { const { set, populatedSet } = systemsWithExistingAlerts.current // if overwrite checked, make sure all alerts will be overwritten if (overwrite) { set.clear() } const recordData: Partial = { value, min, triggered: false, } // we can only send 50 in one batch let done = 0 while (done < systems.length) { const batch = pb.createBatch() let batchSize = 0 for (let i = done; i < Math.min(done + 50, systems.length); i++) { const system = systems[i] // if overwrite is false and system is in set (alert existed), skip if (!overwrite && set.has(system.id)) { continue } // find matching existing alert const existingAlert = alerts.find((alert) => alert.system === system.id && data.key === alert.name) // if first run, add system to set (alert already existed when global panel was opened) if (existingAlert && !populatedSet && !overwrite) { set.add(system.id) continue } batchSize++ const requestOptions: RecordOptions = { requestKey: system.id, } // checked - make sure alert is created or updated if (checked) { if (existingAlert) { batch.collection("alerts").update(existingAlert.id, recordData, requestOptions) } else { batch.collection("alerts").create( { system: system.id, user: pb.authStore.record!.id, name: data.key, ...recordData, }, requestOptions ) } } else if (existingAlert) { batch.collection("alerts").delete(existingAlert.id) } } try { batchSize && batch.send() } catch (e) { failedUpdateToast() } finally { done += 50 } } systemsWithExistingAlerts.current.populatedSet = true } return } function AlertContent({ data }: { data: AlertData }) { const { key } = data const singleDescription = data.alert.singleDesc?.() const [checked, setChecked] = useState(data.checked || false) const [min, setMin] = useState(data.min || 10) const [value, setValue] = useState(data.val || (singleDescription ? 0 : 80)) const newMin = useRef(min) const newValue = useRef(value) const Icon = alertInfo[key].icon const updateAlert = (c?: boolean) => data.updateAlert?.(c ?? checked, newValue.current, newMin.current) return (
{checked && (
}> {!singleDescription && (

Average exceeds{" "} {value} {data.alert.unit}

(newValue.current = val[0]) && updateAlert()} onValueChange={(val) => setValue(val[0])} min={1} max={alertInfo[key].max ?? 99} />
)}

{singleDescription && ( <>{singleDescription}{` `} )} For {min}{" "}

(newMin.current = val[0]) && updateAlert()} onValueChange={(val) => setMin(val[0])} min={1} max={60} />
)}
) }