101 lines
4.7 KiB
TypeScript
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;
|
|
}
|