first commit
This commit is contained in:
commit
4b98219bf7
144 changed files with 31561 additions and 0 deletions
101
frontend/lib/threshold-context.tsx
Normal file
101
frontend/lib/threshold-context.tsx
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
"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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue