From 30806a61c47e82404101bb1a354b915cb4e37e23 Mon Sep 17 00:00:00 2001 From: csawatzky Date: Wed, 20 Aug 2025 16:06:40 -0600 Subject: [PATCH 01/11] expanding the json file so the the new scd30 subtype for co2 has the mode/calibration part --- src/component/ComponentMode.json | 39 ++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/component/ComponentMode.json b/src/component/ComponentMode.json index 16cea43..2c66a6e 100644 --- a/src/component/ComponentMode.json +++ b/src/component/ComponentMode.json @@ -38,6 +38,45 @@ ] } }, + { + "type": 12, + "subtype": 1, + "mode": { + "labelA": "Power Mode", + "entryA": "select", + "dictionaryA": [ + { + "key": "High Power", + "value": 1, + "restricted": false + }, + { + "key": "Low Power", + "value": 2, + "restricted": false + }, + { + "key": "Calibration", + "value": 3, + "restricted": true + } + ], + "labelB": "Number of Averages", + "entryB": "number", + "dictionaryB": [ + { + "key": "min", + "value": 1, + "restricted": false + }, + { + "key": "max", + "value": 8, + "restricted": false + } + ] + } + }, { "type": 28, "subtype": 0, From 731cf06e606ac7d1df98f3fed8a58c29bfbb7fb1 Mon Sep 17 00:00:00 2001 From: csawatzky Date: Wed, 20 Aug 2025 16:13:13 -0600 Subject: [PATCH 02/11] change to the form so that if a device has individual calibrations it can still use the mode stuff --- src/component/ComponentForm.tsx | 168 +++++++++++++++++--------------- 1 file changed, 89 insertions(+), 79 deletions(-) diff --git a/src/component/ComponentForm.tsx b/src/component/ComponentForm.tsx index 08d6117..99568da 100644 --- a/src/component/ComponentForm.tsx +++ b/src/component/ComponentForm.tsx @@ -699,6 +699,86 @@ export default function ComponentForm(props: Props) { ); }; + const componentMode = () => { + const { component, coefficient, offset } = form; + return ( + + + + + } + label="Mode" + labelPlacement="top" + className={classes.switchControl} + disabled={!canEdit} + /> + + + + {compMode.mode.entryA && ( + + {compMode.mode.entryA === "select" && + compMode.mode.dictionaryA.map((elem: any) => { + if (!elem.restricted || (elem.restricted && user.hasAdmin())) { + return ( + + {elem.key} + + ); + } + return undefined; //TODO-CS: Time permitting re-think the structure of this function so that I don't have to return undefined + })} + + )} + + + {compMode.mode.entryB && ( + + {compMode.mode.entryB === "select" && + compMode.mode.dictionaryB.map((elem: any) => ( + + {elem.key} + + ))} + + )} + + + ) + } + const describeSource = (measurementType: quack.MeasurementType): MeasurementDescriber => { const { component } = form; return describeMeasurement(measurementType, component.type(), component.subType()); @@ -1046,87 +1126,17 @@ export default function ComponentForm(props: Props) { } - {!compMode ? ( - device.featureSupported("individualCalibrations") ? ( - individualCalibration() - ) : ( - blanketCalibration() - ) - ) : ( + {device.featureSupported("individualCalibrations") ? ( - - - - } - label="Mode" - labelPlacement="top" - className={classes.switchControl} - disabled={!canEdit} - /> - - - - {compMode.mode.entryA && ( - - {compMode.mode.entryA === "select" && - compMode.mode.dictionaryA.map((elem: any) => { - if (!elem.restricted || (elem.restricted && user.hasAdmin())) { - return ( - - {elem.key} - - ); - } - return undefined; //TODO-CS: Time permitting re-think the structure of this function so that I don't have to return undefined - })} - - )} - - - {compMode.mode.entryB && ( - - {compMode.mode.entryB === "select" && - compMode.mode.dictionaryB.map((elem: any) => ( - - {elem.key} - - ))} - - )} - + {compMode && componentMode()} + {individualCalibration()} + ) : ( + !compMode ? ( + blanketCalibration() + ):( + componentMode() + ) )} Date: Thu, 21 Aug 2025 14:33:22 -0600 Subject: [PATCH 03/11] added cache-busting service-worker and removed caching for service-worker.js (vite uses sw.js) --- nginx.conf | 6 ++++++ public/service-worker.js | 24 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 public/service-worker.js diff --git a/nginx.conf b/nginx.conf index b390bff..1537b32 100644 --- a/nginx.conf +++ b/nginx.conf @@ -71,6 +71,12 @@ http { add_header Cache-Control "no-store, no-cache, must-revalidate"; } + # Force re-cache of old service-worker + location = /service-worker.js { + root /usr/share/nginx/html; # adjust if your build folder is elsewhere + add_header Cache-Control "no-store, no-cache, must-revalidate"; + } + # Redirect old /index.html requests to new file location = /index.html { return 301 /indexV2.html; diff --git a/public/service-worker.js b/public/service-worker.js new file mode 100644 index 0000000..6b6a19c --- /dev/null +++ b/public/service-worker.js @@ -0,0 +1,24 @@ +// public/service-worker.js +self.addEventListener('install', () => self.skipWaiting()); + +self.addEventListener('activate', async () => { + // Unregister old CRA SW + const regs = await self.registration.scope ? [self.registration] : await self.clients.getRegistrations(); + for (const reg of regs) { + if (reg && reg.scriptURL.endsWith('service-worker.js')) { + await reg.unregister(); + } + } + + // Clear all caches + if ('caches' in self) { + const keys = await caches.keys(); + for (const key of keys) { + await caches.delete(key); + } + } + + // Reload all clients + const clients = await self.clients.matchAll({ type: 'window' }); + clients.forEach(client => client.navigate(client.url)); +}); From 27c69c3e553fc1acd8dc19fa680bc9affc16481a Mon Sep 17 00:00:00 2001 From: csawatzky Date: Fri, 22 Aug 2025 13:35:27 -0600 Subject: [PATCH 04/11] hotfix for the bin duplication in the bin actions of the bin page --- src/bin/BinActions.tsx | 6 ++-- src/bin/BinDuplication.tsx | 72 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 src/bin/BinDuplication.tsx diff --git a/src/bin/BinActions.tsx b/src/bin/BinActions.tsx index 5f4d93a..a425ea6 100644 --- a/src/bin/BinActions.tsx +++ b/src/bin/BinActions.tsx @@ -24,7 +24,7 @@ import RemoveSelfFromObject from "user/RemoveSelfFromObject"; import ShareObject from "user/ShareObject"; import { isOffline } from "utils/environment"; import ObjectTeams from "teams/ObjectTeams"; -// import BinDuplication from "./BinDuplication"; +import BinDuplication from "./BinDuplication"; import BinsIcon from "products/Bindapt/BinsIcon"; import HelpIcon from "@mui/icons-material/Help"; import BinSensors from "./BinSensors"; @@ -269,14 +269,14 @@ export default function BinActions(props: Props) { closeDialogCallback={() => setOpenState({ ...openState, users: false })} refreshCallback={refreshCallback} /> - {/* { setOpenState({ ...openState, duplication: false }); }} bin={bin} refreshCallback={refreshCallback} - /> */} + /> void; + refreshCallback: () => void; +} + +export default function BinDuplication(props: Props) { + const { open, bin, closeDialog, refreshCallback } = props; + const [binDupName, setBinDupName] = useState("(copy of) " + bin.name()); + const binAPI = useBinAPI(); + const { openSnack } = useSnackbar(); + + useEffect(() => { + setBinDupName("(copy of) " + bin.name()); + }, [bin]); + + const duplicate = () => { + let settings = bin.settings; + settings.name = binDupName; + binAPI + .addBin(settings) + .then(resp => { + openSnack("Successfully duplicated bin"); + }) + .catch(err => { + openSnack("Failed to duplicate bin"); + }); + refreshCallback(); + closeDialog(); + }; + + return ( + + Create Duplicate Bin + + + This will create a new bin with the same settings as {bin.name()}. + + setBinDupName(e.target.value)} + /> + + + + + + + ); +} From b2f3fac57e6a028e9f79c47a5b4ea9c925795007 Mon Sep 17 00:00:00 2001 From: csawatzky Date: Fri, 22 Aug 2025 14:50:29 -0600 Subject: [PATCH 05/11] fixing the drying calculator by making sure to update the initial time when the mode is changed --- src/bin/BinVisualizerV2.tsx | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/bin/BinVisualizerV2.tsx b/src/bin/BinVisualizerV2.tsx index 0db4690..3e5e131 100644 --- a/src/bin/BinVisualizerV2.tsx +++ b/src/bin/BinVisualizerV2.tsx @@ -250,6 +250,7 @@ export default function BinVisualizer(props: Props) { const [cfmHighOpen, setCFMHighOpen] = useState(false); const [{ user }] = useGlobalState(); const [newPreset, setNewPreset] = useState(pond.BinMode.BIN_MODE_NONE); + const [newBinMode, setNewBinMode] = useState(pond.BinMode.BIN_MODE_NONE); const [selectedCable, setSelectedCable] = useState(); const [openNodeDialog, setOpenNodeDialog] = useState(false); const [cableDevice, setCableDevice] = useState(); @@ -345,6 +346,7 @@ export default function BinVisualizer(props: Props) { setGrainOption(ToGrainOption(bin.settings.inventory.grainType)); setBushPerTonne(bin.settings.inventory.bushelsPerTonne.toFixed(2)); setGrainSubtype(bin.subtype()); + setNewBinMode(bin.settings.mode); } if (bin.settings) { let t = bin.settings.outdoorTemp; @@ -1967,6 +1969,7 @@ export default function BinVisualizer(props: Props) { const setModeStorage = () => { setNewPreset(pond.BinMode.BIN_MODE_STORAGE); + setNewBinMode(pond.BinMode.BIN_MODE_STORAGE); }; const setModeCooldown = () => { @@ -1974,6 +1977,7 @@ export default function BinVisualizer(props: Props) { return; } setNewPreset(pond.BinMode.BIN_MODE_COOLDOWN); + setNewBinMode(pond.BinMode.BIN_MODE_COOLDOWN); }; const setModeDrying = () => { @@ -1982,13 +1986,16 @@ export default function BinVisualizer(props: Props) { bin.settings.inventory?.initialMoisture < bin.settings.inventory?.targetMoisture ) { setNewPreset(pond.BinMode.BIN_MODE_HYDRATING); + setNewBinMode(pond.BinMode.BIN_MODE_HYDRATING); } else { setNewPreset(pond.BinMode.BIN_MODE_DRYING); + setNewBinMode(pond.BinMode.BIN_MODE_DRYING); } }; const closeMoistureDialog = () => { setNewPreset(0); + setNewBinMode(bin.settings.mode); setShowInputMoisture(false); }; @@ -2049,6 +2056,7 @@ export default function BinVisualizer(props: Props) {