BMS/frontend/lib/threshold-context.tsx
2026-03-19 11:32:17 +00:00

101 lines
4.7 KiB
TypeScript

"use client";
import { createContext, useContext, useState, useEffect, useMemo } from "react";
import { THRESHOLDS } from "@/lib/thresholds";
const LS_KEY = "bms_thresholds";
/** Subset of THRESHOLDS that the Settings page allows overriding */
export interface ThresholdOverrides {
temp?: { warn?: number; critical?: number };
humidity?: { low?: number; warn?: number; critical?: number };
power?: { warn?: number; critical?: number };
}
/** Mutable version of THRESHOLDS for runtime use */
export interface MergedThresholds {
temp: { warn: number; critical: number };
humidity: { low: number; warn: number; critical: number };
dewPoint: { warn: number };
power: { warn: number; critical: number };
rackPower: { warn: number; critical: number; rated: number };
filter: { warn: number; critical: number; ratePerDay: number; replaceAt: number };
cop: { warn: number };
compressor: { warn: number; critical: number };
battery: { warn: number; critical: number };
fuel: { warn: number; critical: number };
ups: { loadWarn: number; loadCritical: number };
pue: { target: number; warn: number; critical: number };
phaseImbalance: { warn: number; critical: number };
network: { cpuWarn: number; cpuCritical: number; memWarn: number; memCritical: number; tempWarn: number; tempCritical: number };
ashrae: { tempMin: number; tempMax: number; rhMin: number; rhMax: number };
}
interface ThresholdContextValue {
thresholds: MergedThresholds;
setThresholds: (patch: ThresholdOverrides) => void;
}
const ThresholdContext = createContext<ThresholdContextValue | null>(null);
function loadOverrides(): ThresholdOverrides {
if (typeof window === "undefined") return {};
try {
const raw = localStorage.getItem(LS_KEY);
return raw ? JSON.parse(raw) : {};
} catch {
return {};
}
}
function merge(overrides: ThresholdOverrides): MergedThresholds {
return {
temp: { warn: THRESHOLDS.temp.warn, critical: THRESHOLDS.temp.critical, ...overrides.temp },
humidity: { low: THRESHOLDS.humidity.low, warn: THRESHOLDS.humidity.warn, critical: THRESHOLDS.humidity.critical, ...overrides.humidity },
dewPoint: { warn: THRESHOLDS.dewPoint.warn },
power: { warn: THRESHOLDS.power.warn, critical: THRESHOLDS.power.critical, ...overrides.power },
rackPower: { warn: THRESHOLDS.rackPower.warn, critical: THRESHOLDS.rackPower.critical, rated: THRESHOLDS.rackPower.rated },
filter: { warn: THRESHOLDS.filter.warn, critical: THRESHOLDS.filter.critical, ratePerDay: THRESHOLDS.filter.ratePerDay, replaceAt: THRESHOLDS.filter.replaceAt },
cop: { warn: THRESHOLDS.cop.warn },
compressor: { warn: THRESHOLDS.compressor.warn, critical: THRESHOLDS.compressor.critical },
battery: { warn: THRESHOLDS.battery.warn, critical: THRESHOLDS.battery.critical },
fuel: { warn: THRESHOLDS.fuel.warn, critical: THRESHOLDS.fuel.critical },
ups: { loadWarn: THRESHOLDS.ups.loadWarn, loadCritical: THRESHOLDS.ups.loadCritical },
pue: { target: THRESHOLDS.pue.target, warn: THRESHOLDS.pue.warn, critical: THRESHOLDS.pue.critical },
phaseImbalance: { warn: THRESHOLDS.phaseImbalance.warn, critical: THRESHOLDS.phaseImbalance.critical },
network: { cpuWarn: THRESHOLDS.network.cpuWarn, cpuCritical: THRESHOLDS.network.cpuCritical, memWarn: THRESHOLDS.network.memWarn, memCritical: THRESHOLDS.network.memCritical, tempWarn: THRESHOLDS.network.tempWarn, tempCritical: THRESHOLDS.network.tempCritical },
ashrae: { tempMin: THRESHOLDS.ashrae.tempMin, tempMax: THRESHOLDS.ashrae.tempMax, rhMin: THRESHOLDS.ashrae.rhMin, rhMax: THRESHOLDS.ashrae.rhMax },
};
}
export function ThresholdProvider({ children }: { children: React.ReactNode }) {
const [overrides, setOverrides] = useState<ThresholdOverrides>({});
useEffect(() => {
setOverrides(loadOverrides());
}, []);
const thresholds = useMemo(() => merge(overrides), [overrides]);
function setThresholds(patch: ThresholdOverrides) {
const next: ThresholdOverrides = {
temp: { ...overrides.temp, ...patch.temp },
humidity: { ...overrides.humidity, ...patch.humidity },
power: { ...overrides.power, ...patch.power },
};
setOverrides(next);
localStorage.setItem(LS_KEY, JSON.stringify(next));
}
return (
<ThresholdContext.Provider value={{ thresholds, setThresholds }}>
{children}
</ThresholdContext.Provider>
);
}
export function useThresholds(): ThresholdContextValue {
const ctx = useContext(ThresholdContext);
if (!ctx) throw new Error("useThresholds must be used inside ThresholdProvider");
return ctx;
}