From 69a848daf5a70153884c767e74dbc297df3340d5 Mon Sep 17 00:00:00 2001 From: Carter Date: Mon, 11 Aug 2025 11:22:01 -0600 Subject: [PATCH 01/44] merged staging and switched to master proto --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fc7a1ac..ee0e9b7 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "mui-tel-input": "^7.0.0", "notistack": "^3.0.1", "openweathermap-ts": "^1.2.10", - "protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#staging", + "protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#master", "query-string": "^9.2.1", "react": "^18.3.1", "react-beautiful-dnd": "^13.1.1", From 7029a18d9cdad06a8fbbdeb7930bebd04b32fdba Mon Sep 17 00:00:00 2001 From: csawatzky Date: Wed, 13 Aug 2025 10:23:02 -0600 Subject: [PATCH 02/44] making sure so use stagings protobuf --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index b89d4cd..81f47c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,7 +42,7 @@ "mui-tel-input": "^7.0.0", "notistack": "^3.0.1", "openweathermap-ts": "^1.2.10", - "protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#libracart", + "protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#staging", "query-string": "^9.2.1", "react": "^18.3.1", "react-beautiful-dnd": "^13.1.1", @@ -10911,7 +10911,7 @@ }, "node_modules/protobuf-ts": { "version": "1.0.0", - "resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#c68c727be5b1076bbb534996a13d5e3285c6ca68", + "resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#0e34386a27695f7cd98099015870a19c38f62bc6", "dependencies": { "protobufjs": "^6.8.8" } diff --git a/package.json b/package.json index 89efa4d..fc7a1ac 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "mui-tel-input": "^7.0.0", "notistack": "^3.0.1", "openweathermap-ts": "^1.2.10", - "protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#libracart", + "protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#staging", "query-string": "^9.2.1", "react": "^18.3.1", "react-beautiful-dnd": "^13.1.1", From 31af3ffa65dc7607ae66bedc72b084c5d53d5d6e Mon Sep 17 00:00:00 2001 From: csawatzky Date: Wed, 13 Aug 2025 14:28:24 -0600 Subject: [PATCH 03/44] hard coding in the url for the libracart button --- src/integrations/LibraCart/LibraCartAccess.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/integrations/LibraCart/LibraCartAccess.tsx b/src/integrations/LibraCart/LibraCartAccess.tsx index fae3362..d075b8e 100644 --- a/src/integrations/LibraCart/LibraCartAccess.tsx +++ b/src/integrations/LibraCart/LibraCartAccess.tsx @@ -34,8 +34,6 @@ export default function LibraCartAccess() { //const [dataOps, setDataOps] = useState([]); const { openSnack } = useSnackbar(); //const [{ as }] = useGlobalState(); - // const integration_url = process.env.REACT_APP_LIBRACART_INTEGRATION_URL; - const integration_url = import.meta.env.VITE_LIBRACART_INTEGRATION_URL; const submitNewOrganization = () => { @@ -183,7 +181,7 @@ export default function LibraCartAccess() { color="primary" onClick={e => { e.preventDefault(); - window.open(`${integration_url}`, "_blank"); + window.open(`https://staging.cloud.agrimatics.com/grain/integrations`, "_blank"); }}> Link Libra Cart Account From 85ccecdcdc1906644f7dd80f31cf058dce2ca274 Mon Sep 17 00:00:00 2001 From: Carter Date: Wed, 13 Aug 2025 14:37:38 -0600 Subject: [PATCH 04/44] hotfix: if getting user with team fails, just get the user --- package-lock.json | 2 +- src/app/UserWrapper.tsx | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index eb7d904..0e4f8f9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,7 +42,7 @@ "mui-tel-input": "^7.0.0", "notistack": "^3.0.1", "openweathermap-ts": "^1.2.10", - "protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#staging", + "protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#master", "query-string": "^9.2.1", "react": "^18.3.1", "react-beautiful-dnd": "^13.1.1", diff --git a/src/app/UserWrapper.tsx b/src/app/UserWrapper.tsx index 722705e..cb4cdf8 100644 --- a/src/app/UserWrapper.tsx +++ b/src/app/UserWrapper.tsx @@ -82,7 +82,20 @@ export default function UserWrapper(props: Props) { firmware: new Map() }) }).catch(() => { - setGlobal(globalDefault) + userAPI.getUser(user_id).then(user => { + setGlobal({ + user: user ? user : User.create(), + team: globalDefault.team, + as: "", + showErrors: false, + userTeamPermissions: [], + backgroundTasksComplete: false, + firmware: new Map() + }) + }).catch(() => { + setGlobal(globalDefault) + }) + }) .finally(() => { setLoading(false) From 2dde79970da30fe24635328cc9b122b628e9c566 Mon Sep 17 00:00:00 2001 From: csawatzky Date: Wed, 13 Aug 2025 15:46:07 -0600 Subject: [PATCH 05/44] hotfix to have the duplicate button available to users with the installer feature flag --- src/bin/BinCardV2.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/BinCardV2.tsx b/src/bin/BinCardV2.tsx index 35fcd12..683e598 100644 --- a/src/bin/BinCardV2.tsx +++ b/src/bin/BinCardV2.tsx @@ -490,7 +490,7 @@ export default function BinCard(props: Props) { return ( - {user.hasFeature("admin") && ( + {user.hasFeature("installer") && ( Date: Thu, 14 Aug 2025 09:16:46 -0600 Subject: [PATCH 06/44] putting the background colour back in for the responsive table sticky header --- src/common/ResponsiveTable.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/ResponsiveTable.tsx b/src/common/ResponsiveTable.tsx index 79238ea..ef99665 100644 --- a/src/common/ResponsiveTable.tsx +++ b/src/common/ResponsiveTable.tsx @@ -59,7 +59,7 @@ const useStyles = makeStyles((theme: Theme) => { }, stickyHeader: { position: "sticky", - // backgroundColor: getThemeType() === "light" ? "rgb(245, 245, 245)" : "rgb(40, 40, 40)", + backgroundColor: getThemeType() === "light" ? "rgb(245, 245, 245)" : "rgb(40, 40, 40)", top: 0, zIndex: 300 //giving a really high z-index to make sure nothing is in front of it } From 2e3192e9af773cc3fde753b90b428cbef0f24cb4 Mon Sep 17 00:00:00 2001 From: csawatzky Date: Thu, 14 Aug 2025 09:18:09 -0600 Subject: [PATCH 07/44] hotfix - putting back the background colour for the resposive table sticky header --- src/common/ResponsiveTable.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/ResponsiveTable.tsx b/src/common/ResponsiveTable.tsx index 79238ea..ef99665 100644 --- a/src/common/ResponsiveTable.tsx +++ b/src/common/ResponsiveTable.tsx @@ -59,7 +59,7 @@ const useStyles = makeStyles((theme: Theme) => { }, stickyHeader: { position: "sticky", - // backgroundColor: getThemeType() === "light" ? "rgb(245, 245, 245)" : "rgb(40, 40, 40)", + backgroundColor: getThemeType() === "light" ? "rgb(245, 245, 245)" : "rgb(40, 40, 40)", top: 0, zIndex: 300 //giving a really high z-index to make sure nothing is in front of it } From e57f75bf5664457f694e3793a3aa159195e93fab Mon Sep 17 00:00:00 2001 From: csawatzky Date: Fri, 15 Aug 2025 11:18:19 -0600 Subject: [PATCH 08/44] set up an areea chart for bin levels over time if there are more than 10 changes since the bars get kinda cluttered --- src/bin/BinSettings.tsx | 2 - src/bin/graphs/BinLevelAreaGraph.tsx | 67 ++++++++++++++++++++++++++++ src/bin/graphs/BinLevelOverTime.tsx | 42 ++++++++++------- 3 files changed, 94 insertions(+), 17 deletions(-) create mode 100644 src/bin/graphs/BinLevelAreaGraph.tsx diff --git a/src/bin/BinSettings.tsx b/src/bin/BinSettings.tsx index 2c97be1..f970b2b 100644 --- a/src/bin/BinSettings.tsx +++ b/src/bin/BinSettings.tsx @@ -374,7 +374,6 @@ export default function BinSettings(props: Props) { let options: Option[] = [] libracartAPI.listDestinations(0,0,undefined, as) .then(resp=>{ - console.log(resp) //set the options for the search select resp.data.destinations.forEach(d => { let newOp: Option = { @@ -486,7 +485,6 @@ export default function BinSettings(props: Props) { form.inventory.inventoryControl = inventoryControl form.inventory.autoThreshold = autoFillThreshold } - console.log(form) binAPI .updateBin(bin.key(), form, as) .then(response => { diff --git a/src/bin/graphs/BinLevelAreaGraph.tsx b/src/bin/graphs/BinLevelAreaGraph.tsx new file mode 100644 index 0000000..fc13182 --- /dev/null +++ b/src/bin/graphs/BinLevelAreaGraph.tsx @@ -0,0 +1,67 @@ +import { useTheme } from "@mui/material"; +import MaterialChartTooltip from "charts/MaterialChartTooltip"; +import moment from "moment"; +import { Area, AreaChart, ResponsiveContainer, Tooltip, TooltipProps, XAxis, YAxis } from "recharts"; + +export interface LevelAreaData { + timestamp: number; + value: number; +} + +interface Props { + data: LevelAreaData[] + fill: string + customHeight?: string | number +} + +export default function BinLevelAreaGraph(props: Props) { + const { data, customHeight, fill } = props + const theme = useTheme(); + const now = moment(); + + + return ( + + + { + let t = moment(timestamp); + return now.isSame(t, "day") ? t.format("LT") : t.format("MMM DD"); + }} + scale="time" + type="number" + tick={{ fill: theme.palette.text.primary }} + stroke={theme.palette.divider} + interval="preserveStartEnd" + /> + + + moment(timestamp).format("lll")} + content={(props: TooltipProps) => { + return ( + { + return value + " Bushels"; + }} + /> + ); + }} + /> + + + ) +} \ No newline at end of file diff --git a/src/bin/graphs/BinLevelOverTime.tsx b/src/bin/graphs/BinLevelOverTime.tsx index 63bb51d..33212f5 100644 --- a/src/bin/graphs/BinLevelOverTime.tsx +++ b/src/bin/graphs/BinLevelOverTime.tsx @@ -9,6 +9,7 @@ import { } from "@mui/material"; import { blue, grey, red, yellow, orange } from "@mui/material/colors"; import BarGraph, { BarData, RefArea } from "charts/BarGraph"; +import MultiLineGraph, { LineData } from "charts/measurementCharts/MultiLineGraph"; import { Bin } from "models"; import moment, { Moment } from "moment"; import { pond, quack } from "protobuf-ts/pond"; @@ -16,6 +17,7 @@ import { useBinAPI, useGlobalState } from "providers"; import { useCallback, useEffect, useState } from "react"; import { Legend } from "recharts"; import { getGrainUnit } from "utils"; +import BinLevelAreaGraph from "./BinLevelAreaGraph"; interface Props { binLoading: boolean; @@ -27,11 +29,16 @@ interface Props { customHeight?: number | string; } +interface InventoryAt { + timestamp: number; + value: number; +} + export default function BinLevelOverTime(props: Props) { const { bin, fertilizerBin, colour, startDate, endDate, customHeight } = props; const binAPI = useBinAPI(); const [{as}] = useGlobalState(); - const [data, setData] = useState([]); + const [inventoryData, setInventoryData] = useState([]); const [modeAreas, setModeAreas] = useState([]); const [dataLoading, setDataLoading] = useState(false); const [capacity, setCapacity] = useState(); @@ -102,7 +109,7 @@ export default function BinLevelOverTime(props: Props) { fill: getFill(settings.mode) }); currentMode = settings.mode; - let newData: BarData = { + let newData: InventoryAt = { timestamp: moment(hist.timestamp).valueOf(), value: fertilizerBin ? Math.round(bushels * 35.239) @@ -135,7 +142,7 @@ export default function BinLevelOverTime(props: Props) { fill: getFill(bin.settings.mode) }); } - setData(data); + setInventoryData(data); setModeAreas(modeAreas); }) .finally(() => { @@ -191,7 +198,7 @@ export default function BinLevelOverTime(props: Props) { timestamp: currentTime }); } - setData(autoBarData); + setInventoryData(autoBarData); }) .catch(err => {}) .finally(() => { @@ -271,23 +278,31 @@ export default function BinLevelOverTime(props: Props) { }; const inventoryChart = () => { - return ( - 10){ + return ( + + ) + }else{ + return ( + 0 ? legend() : undefined} labelColour="white" labels useGradient - /> - ); + /> + ); + } }; - const autoBinModeChart = () => { + const binModeChart = () => { return ( {dataLoading ? : inventoryChart()} - {/* when using auto will need to make a new chart just for the bin modes since the auto inventory comes from another place */} - {(bin.inventoryControl() === pond.BinInventoryControl.BIN_INVENTORY_CONTROL_AUTOMATIC_LIDAR || - bin.inventoryControl() === pond.BinInventoryControl.BIN_INVENTORY_CONTROL_AUTOMATIC || - bin.inventoryControl() === pond.BinInventoryControl.BIN_INVENTORY_CONTROL_LIBRACART) && autoBinModeChart()} + {binModeChart()} ); } From 2bd04acb6887bf17ecd2c84fd6717e76e9d570c6 Mon Sep 17 00:00:00 2001 From: csawatzky Date: Fri, 15 Aug 2025 11:36:54 -0600 Subject: [PATCH 09/44] fixed up the mode graph --- src/bin/graphs/BinLevelOverTime.tsx | 59 ++++++++++------------------- 1 file changed, 19 insertions(+), 40 deletions(-) diff --git a/src/bin/graphs/BinLevelOverTime.tsx b/src/bin/graphs/BinLevelOverTime.tsx index 33212f5..58ce4d6 100644 --- a/src/bin/graphs/BinLevelOverTime.tsx +++ b/src/bin/graphs/BinLevelOverTime.tsx @@ -1,18 +1,13 @@ import { - Box, Card, CircularProgress, - FormControlLabel, - Grid, - Switch, Typography } from "@mui/material"; import { blue, grey, red, yellow, orange } from "@mui/material/colors"; -import BarGraph, { BarData, RefArea } from "charts/BarGraph"; -import MultiLineGraph, { LineData } from "charts/measurementCharts/MultiLineGraph"; +import BarGraph, { BarData } from "charts/BarGraph"; import { Bin } from "models"; import moment, { Moment } from "moment"; -import { pond, quack } from "protobuf-ts/pond"; +import { pond } from "protobuf-ts/pond"; import { useBinAPI, useGlobalState } from "providers"; import { useCallback, useEffect, useState } from "react"; import { Legend } from "recharts"; @@ -39,7 +34,6 @@ export default function BinLevelOverTime(props: Props) { const binAPI = useBinAPI(); const [{as}] = useGlobalState(); const [inventoryData, setInventoryData] = useState([]); - const [modeAreas, setModeAreas] = useState([]); const [dataLoading, setDataLoading] = useState(false); const [capacity, setCapacity] = useState(); @@ -83,32 +77,14 @@ export default function BinLevelOverTime(props: Props) { .listHistoryBetween(bin.key(), 500, startDate.toISOString(), endDate.toISOString()) .then(resp => { let data: BarData[] = []; - let modeAreas: RefArea[] = []; let lastBushels = -1; - - //values for ref areas - let x1 = 0; - let x2 = 0; - let y1 = -50; - let y2 = -200; - - let currentMode: pond.BinMode; - + let currentMode: pond.BinMode | undefined = undefined + let modeData: BarData[] = [] resp.data.history.forEach(hist => { + //build the data for the inventory bar graph if (hist.settings?.inventory) { - let settings = pond.BinSettings.fromObject(hist.settings); let bushels = hist.settings.inventory.grainBushels ?? 0; - if (bushels !== lastBushels || currentMode !== settings.mode) { - x1 = moment(hist.timestamp).valueOf(); - x2 = moment(hist.timestamp).valueOf(); - modeAreas.push({ - x1: x1, - x2: x2, - y1: cap ? cap * -0.1 : y1, - y2: cap ? cap * -0.2 : y2, - fill: getFill(settings.mode) - }); - currentMode = settings.mode; + if (bushels !== lastBushels) { let newData: InventoryAt = { timestamp: moment(hist.timestamp).valueOf(), value: fertilizerBin @@ -121,6 +97,17 @@ export default function BinLevelOverTime(props: Props) { lastBushels = bushels; } } + //build the data for the mode change bar graph + let histBin = Bin.create() + histBin.settings = hist.settings ?? pond.BinSettings.create() + if(hist.settings && currentMode !== hist.settings.mode){ + currentMode = hist.settings.mode + modeData.push({ + timestamp: moment(hist.timestamp).valueOf(), + value: 1, + fill: getFill(currentMode) + }) + } }); if (data.length === 0) { let bushels = bin.settings.inventory?.grainBushels ?? 0; @@ -133,17 +120,9 @@ export default function BinLevelOverTime(props: Props) { : bushels, timestamp: currentTime }); - - modeAreas.push({ - x1: currentTime, - x2: currentTime, - y1: cap ? cap * -0.1 : y1, - y2: cap ? cap * -0.2 : y2, - fill: getFill(bin.settings.mode) - }); } setInventoryData(data); - setModeAreas(modeAreas); + setModeData(modeData) }) .finally(() => { setDataLoading(false); @@ -290,7 +269,6 @@ export default function BinLevelOverTime(props: Props) { { + console.log(modeData) return ( Date: Fri, 15 Aug 2025 15:51:12 -0600 Subject: [PATCH 10/44] correction for when there is no data for the graph to use the correct inventory (settings or status) --- src/bin/graphs/BinLevelOverTime.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/graphs/BinLevelOverTime.tsx b/src/bin/graphs/BinLevelOverTime.tsx index 58ce4d6..1756a60 100644 --- a/src/bin/graphs/BinLevelOverTime.tsx +++ b/src/bin/graphs/BinLevelOverTime.tsx @@ -110,7 +110,7 @@ export default function BinLevelOverTime(props: Props) { } }); if (data.length === 0) { - let bushels = bin.settings.inventory?.grainBushels ?? 0; + let bushels = bin.bushels(); let currentTime = moment().valueOf(); data.push({ value: fertilizerBin @@ -166,7 +166,7 @@ export default function BinLevelOverTime(props: Props) { }); }); if (autoBarData.length === 0) { - let bushels = bin.settings.inventory?.grainBushels ?? 0; + let bushels = bin.bushels(); let currentTime = moment().valueOf(); autoBarData.push({ value: fertilizerBin From 497e81fc4baa9173ed862986e147cb621daed359 Mon Sep 17 00:00:00 2001 From: csawatzky Date: Mon, 18 Aug 2025 14:08:20 -0600 Subject: [PATCH 11/44] fixed bug that was causing the reading in the headers of the bin sensro graphs to be converted evertime the tab changed to "Sensors" --- src/bin/graphs/BinComponentGraph.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/graphs/BinComponentGraph.tsx b/src/bin/graphs/BinComponentGraph.tsx index 6b593a9..3c5a625 100644 --- a/src/bin/graphs/BinComponentGraph.tsx +++ b/src/bin/graphs/BinComponentGraph.tsx @@ -184,7 +184,7 @@ export default function BinComponentGraph(props: Props) { UnitMeasurement.create(m, user)) + lastMeasurement.map(m => UnitMeasurement.create(m, user)) )} /> } From eae0628e8be9e149a64f9cdbe7b757b5c5993677 Mon Sep 17 00:00:00 2001 From: csawatzky Date: Mon, 18 Aug 2025 14:59:32 -0600 Subject: [PATCH 12/44] hotfix for the plenum column on the devices page to be renamed and the bin page sensors graph headers reading going through multiple conversions --- src/bin/graphs/BinComponentGraph.tsx | 2 +- src/pages/Devices.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/graphs/BinComponentGraph.tsx b/src/bin/graphs/BinComponentGraph.tsx index 6b593a9..3c5a625 100644 --- a/src/bin/graphs/BinComponentGraph.tsx +++ b/src/bin/graphs/BinComponentGraph.tsx @@ -184,7 +184,7 @@ export default function BinComponentGraph(props: Props) { UnitMeasurement.create(m, user)) + lastMeasurement.map(m => UnitMeasurement.create(m, user)) )} /> } diff --git a/src/pages/Devices.tsx b/src/pages/Devices.tsx index 7721ec1..673f097 100644 --- a/src/pages/Devices.tsx +++ b/src/pages/Devices.tsx @@ -472,7 +472,7 @@ export default function Devices() { ] if (hasPlenums) { columns.push({ - title: "Plenum", + title: "Temp/Humidity", // sortKey: "hi", // disableSort: true, render: (device: Device) => { From 441e02f65a1657cd734888d6b370d6dc0c5d807f Mon Sep 17 00:00:00 2001 From: csawatzky Date: Mon, 18 Aug 2025 16:11:32 -0600 Subject: [PATCH 13/44] fixed the Duplicate Bin button in the bin actions by importing the BinDuplication react component from the old frontend --- src/bin/BinActions.tsx | 7 ++-- src/bin/BinDuplication.tsx | 72 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 src/bin/BinDuplication.tsx diff --git a/src/bin/BinActions.tsx b/src/bin/BinActions.tsx index 5f4d93a..e467a8b 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"; @@ -166,6 +166,7 @@ export default function BinActions(props: Props) { { + console.log("duplicate") setOpenState({ ...openState, duplication: true }); setAnchorEl(null); }} @@ -269,14 +270,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 44f227c3e9bb4bd86f0236ffe9e1f3d77b8287fa Mon Sep 17 00:00:00 2001 From: csawatzky Date: Mon, 18 Aug 2025 16:50:53 -0600 Subject: [PATCH 14/44] removing some logs --- src/bin/BinActions.tsx | 1 - src/bin/graphs/BinLevelOverTime.tsx | 1 - 2 files changed, 2 deletions(-) diff --git a/src/bin/BinActions.tsx b/src/bin/BinActions.tsx index e467a8b..a425ea6 100644 --- a/src/bin/BinActions.tsx +++ b/src/bin/BinActions.tsx @@ -166,7 +166,6 @@ export default function BinActions(props: Props) { { - console.log("duplicate") setOpenState({ ...openState, duplication: true }); setAnchorEl(null); }} diff --git a/src/bin/graphs/BinLevelOverTime.tsx b/src/bin/graphs/BinLevelOverTime.tsx index 1756a60..59c9bae 100644 --- a/src/bin/graphs/BinLevelOverTime.tsx +++ b/src/bin/graphs/BinLevelOverTime.tsx @@ -281,7 +281,6 @@ export default function BinLevelOverTime(props: Props) { }; const binModeChart = () => { - console.log(modeData) return ( Date: Mon, 18 Aug 2025 16:55:49 -0600 Subject: [PATCH 15/44] fix for when there are no changes to the mode over the set period of time --- src/bin/graphs/BinLevelOverTime.tsx | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/bin/graphs/BinLevelOverTime.tsx b/src/bin/graphs/BinLevelOverTime.tsx index 59c9bae..d9c98cf 100644 --- a/src/bin/graphs/BinLevelOverTime.tsx +++ b/src/bin/graphs/BinLevelOverTime.tsx @@ -109,9 +109,9 @@ export default function BinLevelOverTime(props: Props) { }) } }); + let currentTime = moment().valueOf(); if (data.length === 0) { let bushels = bin.bushels(); - let currentTime = moment().valueOf(); data.push({ value: fertilizerBin ? Math.round(bushels * 35.239) @@ -121,6 +121,13 @@ export default function BinLevelOverTime(props: Props) { timestamp: currentTime }); } + if(modeData.length === 0){ + modeData.push({ + timestamp: currentTime, + value: 1, + fill: getFill(bin.settings.mode) + }) + } setInventoryData(data); setModeData(modeData) }) @@ -206,6 +213,13 @@ export default function BinLevelOverTime(props: Props) { }) } }) + if(modeData.length === 0){ + modeData.push({ + timestamp: moment().valueOf(), + value: 1, + fill: getFill(bin.settings.mode) + }) + } setModeData(modeData) }) .catch(err => { From b3245ad1bc27bb95d162aac48395938afc6e2662 Mon Sep 17 00:00:00 2001 From: csawatzky Date: Tue, 19 Aug 2025 11:00:26 -0600 Subject: [PATCH 16/44] fixed the function definition since it was preventing cloning of components for the support page --- src/models/Component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/Component.ts b/src/models/Component.ts index 9b96599..473d85d 100644 --- a/src/models/Component.ts +++ b/src/models/Component.ts @@ -114,7 +114,7 @@ export class Component { return 0; } - public addressDescription = (deviceProduct?: pond.DeviceProduct) => { + public addressDescription(deviceProduct?: pond.DeviceProduct): string { if ( this.settings.addressType === quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY || (this.settings.addressType >= quack.AddressType.ADDRESS_TYPE_PIN_OFFSET1 && From b3569efc5fa224e0ecbb5b82bf7048bd5be62d7d Mon Sep 17 00:00:00 2001 From: csawatzky Date: Tue, 19 Aug 2025 14:24:55 -0600 Subject: [PATCH 17/44] added a use effect to update the value in the time when the initial value in the component changes --- src/common/time/PeriodSelect.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/common/time/PeriodSelect.tsx b/src/common/time/PeriodSelect.tsx index 66e4f9c..d510ebc 100644 --- a/src/common/time/PeriodSelect.tsx +++ b/src/common/time/PeriodSelect.tsx @@ -28,6 +28,13 @@ export default function PeriodSelect(props: Props) { } }, [unit, prevUnit, onChange, value]); + useEffect(()=>{ + let initialUnit: TimeUnit = bestUnit(initialMs); + let initialValue = milliToX(initialMs, initialUnit).toString(); + setValue(initialValue) + setUnit(initialUnit) + },[initialMs]) + const changeValue = (event: any) => { let value = event.target.value; setValue(value); From 8a9d7af6ae3c1191a9a283d012be1dba43018348 Mon Sep 17 00:00:00 2001 From: csawatzky Date: Tue, 19 Aug 2025 15:34:47 -0600 Subject: [PATCH 18/44] adding temp oats to the grain describer to have a user test which is more accurate --- src/grain/GrainDescriber.ts | 38 +++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/grain/GrainDescriber.ts b/src/grain/GrainDescriber.ts index ce394b3..769826c 100644 --- a/src/grain/GrainDescriber.ts +++ b/src/grain/GrainDescriber.ts @@ -48,7 +48,7 @@ const defaultGrain: GrainExtension = { bushelsPerTonne: 0 }; -export const GrainExtensions: Map = new Map([ +export const GrainExtensions: Map = new Map([ [pond.Grain.GRAIN_INVALID, defaultGrain], [pond.Grain.GRAIN_NONE, defaultGrain], [ @@ -190,7 +190,7 @@ export const GrainExtensions: Map = new Map([ [ pond.Grain.GRAIN_OATS, { - name: "Oats", + name: "Oats a", group: "Oats", equation: Equation.henderson, a: 0.000085511, @@ -203,6 +203,40 @@ export const GrainExtensions: Map = new Map([ weightConversionKg: 15.4222988297197, bushelsPerTonne: 64.842 } + ], + [ + 29, + { + name: "Oats b", + group: "Oats", + equation: Equation.chungPfost, + a: 442.85, + b: 0.21228, + c: 35.803, + setTempC: 32.0, + targetMC: 13.6, + img: OatImg, + colour: "#79955a", + weightConversionKg: 15.4222988297197, + bushelsPerTonne: 64.842 + } + ], + [ + 30, + { + name: "Oats c", + group: "Oats", + equation: Equation.oswin, + a: 12.412, + b: -0.060707, + c: 2.9397, + setTempC: 32.0, + targetMC: 13.6, + img: OatImg, + colour: "#79955a", + weightConversionKg: 15.4222988297197, + bushelsPerTonne: 64.842 + } ], [ pond.Grain.GRAIN_PEANUTS, From e313fd10ae008d16322d8a1a904ccbb69151b6ba Mon Sep 17 00:00:00 2001 From: csawatzky Date: Tue, 19 Aug 2025 15:51:58 -0600 Subject: [PATCH 19/44] proto update for the test oats enum --- package-lock.json | 2 +- src/grain/GrainDescriber.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0e4f8f9..fe947bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10911,7 +10911,7 @@ }, "node_modules/protobuf-ts": { "version": "1.0.0", - "resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#0b7dd45fa720d6c3f20ac7bafac4a3f0bdbc7ab6", + "resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#0cdf4d5e3038ef13318da0841886a7c9f0926f8d", "dependencies": { "protobufjs": "^6.8.8" } diff --git a/src/grain/GrainDescriber.ts b/src/grain/GrainDescriber.ts index 769826c..c140a85 100644 --- a/src/grain/GrainDescriber.ts +++ b/src/grain/GrainDescriber.ts @@ -48,7 +48,7 @@ const defaultGrain: GrainExtension = { bushelsPerTonne: 0 }; -export const GrainExtensions: Map = new Map([ +export const GrainExtensions: Map = new Map([ [pond.Grain.GRAIN_INVALID, defaultGrain], [pond.Grain.GRAIN_NONE, defaultGrain], [ @@ -205,7 +205,7 @@ export const GrainExtensions: Map = new Map } ], [ - 29, + pond.Grain.GRAIN_OATS_B, { name: "Oats b", group: "Oats", @@ -222,7 +222,7 @@ export const GrainExtensions: Map = new Map } ], [ - 30, + pond.Grain.GRAIN_OATS_C, { name: "Oats c", group: "Oats", From 7971b0a2180642f175b5adfbba0b54e678cab4ff Mon Sep 17 00:00:00 2001 From: csawatzky Date: Wed, 20 Aug 2025 10:22:28 -0600 Subject: [PATCH 20/44] fixed the bin cards so that mobil now has 2 per row again --- src/bin/BinCardV2.tsx | 3 -- src/bin/BinsList.tsx | 18 +----------- src/pages/Bins.tsx | 66 ------------------------------------------- 3 files changed, 1 insertion(+), 86 deletions(-) diff --git a/src/bin/BinCardV2.tsx b/src/bin/BinCardV2.tsx index 35fcd12..e559c11 100644 --- a/src/bin/BinCardV2.tsx +++ b/src/bin/BinCardV2.tsx @@ -506,9 +506,6 @@ export default function BinCard(props: Props) { + )} - {/* - - */} { position: "relative", minHeight: "233px", height: "auto !important", - width: "184px", padding: 2 }, hidden: { @@ -113,7 +112,7 @@ export default function BinsList(props: Props) { return ( {bins.map((b, i) => - isMobile ? ( + ( - ) : ( - { - !duplicate && goToBin(i) - }}> - - ) )} diff --git a/src/pages/Bins.tsx b/src/pages/Bins.tsx index 477aa05..9145a6a 100644 --- a/src/pages/Bins.tsx +++ b/src/pages/Bins.tsx @@ -1214,37 +1214,6 @@ export default function Bins(props: Props) { } ]} /> - {/* - { - setCardValDisplay("low"); - }}> - Low - - { - setCardValDisplay("average"); - }}> - Average - - { - setCardValDisplay("high"); - }}> - High - - */} @@ -1270,41 +1239,6 @@ export default function Bins(props: Props) { } ]} /> - {/* - { - setBinView("grid"); - sessionStorage.setItem("binsView", "grid"); - }}> - - */} - {/* hidden at dustins request so that grid view and list are the only two */} - {/* { - setBinView("scroll"); - sessionStorage.setItem("binsView", "scroll"); - }}> - - */} - {/* { - setBinView("list"); - sessionStorage.setItem("binsView", "list"); - }}> - - - */} { From 30806a61c47e82404101bb1a354b915cb4e37e23 Mon Sep 17 00:00:00 2001 From: csawatzky Date: Wed, 20 Aug 2025 16:06:40 -0600 Subject: [PATCH 21/44] 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 22/44] 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 23/44] 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 24/44] 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 25/44] 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) {