Merge branch 'staging_environment' into upgrade_device
This commit is contained in:
commit
809acae6fc
31 changed files with 1027 additions and 1021 deletions
|
|
@ -419,16 +419,12 @@ export default function BinCard(props: Props) {
|
|||
Math.round(current * 35.239).toLocaleString() +
|
||||
"/" +
|
||||
Math.round(capacity * 35.239).toLocaleString() +
|
||||
(lidarBushels ? "(" + Math.round(lidarBushels * 35.239).toLocaleString() + " est)" : "") +
|
||||
" L"
|
||||
);
|
||||
}
|
||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && bin.bushelsPerTonne() > 1) {
|
||||
return (
|
||||
bin.grainTonnes().toLocaleString() +
|
||||
(lidarBushels
|
||||
? "(" + Math.round(lidarBushels / bin.bushelsPerTonne()).toLocaleString() + " est)"
|
||||
: "") +
|
||||
" mT " +
|
||||
bin.fillPercent() +
|
||||
"%"
|
||||
|
|
@ -438,7 +434,6 @@ export default function BinCard(props: Props) {
|
|||
current.toLocaleString() +
|
||||
"/" +
|
||||
capacity.toLocaleString() +
|
||||
(lidarBushels ? "(" + lidarBushels.toLocaleString() + " est)" : "") +
|
||||
" bu"
|
||||
);
|
||||
};
|
||||
|
|
@ -469,10 +464,10 @@ export default function BinCard(props: Props) {
|
|||
|
||||
const info = () => {
|
||||
const inv = bin.settings.inventory;
|
||||
let bushelAmount = inv?.grainBushels;
|
||||
let bushelAmount = bin.bushels();
|
||||
let bushelCapacity = bin.settings.specs?.bushelCapacity;
|
||||
const empty =
|
||||
!inv || inv.empty || !bushelCapacity || bushelCapacity <= 0 || inv.grainBushels <= 0;
|
||||
!inv || inv.empty || !bushelCapacity || bushelCapacity <= 0 || bushelAmount <= 0;
|
||||
return (
|
||||
<Box width={1} marginTop={0}>
|
||||
<Typography align="center" color="textSecondary" noWrap style={{ fontSize: "0.65rem" }}>
|
||||
|
|
|
|||
|
|
@ -832,7 +832,6 @@ export default function BinSVGV2(props: Props) {
|
|||
cableGrainEndY = cableGrainStartY;
|
||||
}
|
||||
if (cableEstimate && cables.length > 0 && cableGrainPathPoints.length === cables.length) {
|
||||
console.log("calc cable path");
|
||||
let cablePath = cableGrainEstimate(
|
||||
cableGrainPathPoints,
|
||||
spacingX,
|
||||
|
|
|
|||
|
|
@ -362,95 +362,95 @@ export default function BinVisualizer(props: Props) {
|
|||
let trendCables = cables;
|
||||
if (bin.key() !== "" && !loadingTrend) {
|
||||
setLoadingTrend(true);
|
||||
// binAPI
|
||||
// .getBinsTrendData([bin.key()], 7)
|
||||
// .then(resp => {
|
||||
// let binTrend = resp.data.trendData[bin.key()];
|
||||
// //the variables to use to build the average conditions
|
||||
// let temps: number[] = [];
|
||||
// let humids: number[] = [];
|
||||
// let emcs: number[] = [];
|
||||
// let tempTrends: number[] = [];
|
||||
// let humidTrends: number[] = [];
|
||||
// let emcTrends: number[] = [];
|
||||
binAPI
|
||||
.getBinsTrendData([bin.key()], 7)
|
||||
.then(resp => {
|
||||
let binTrend = resp.data.trendData[bin.key()];
|
||||
//the variables to use to build the average conditions
|
||||
let temps: number[] = [];
|
||||
let humids: number[] = [];
|
||||
let emcs: number[] = [];
|
||||
let tempTrends: number[] = [];
|
||||
let humidTrends: number[] = [];
|
||||
let emcTrends: number[] = [];
|
||||
|
||||
// let lowNodeConditions: GrainConditions | undefined = undefined;
|
||||
// let highNodeConditions: GrainConditions | undefined = undefined;
|
||||
// let avgConditions: GrainConditions | undefined = undefined;
|
||||
// trendCables.forEach(cable => {
|
||||
// //only use the values below the top node
|
||||
// //because splice mutates the original array make a clone in the cables so the svg still has all of them for display
|
||||
// //also reverse it so that the node 1 (end of the cable) is in the first position
|
||||
// let tempClone = cloneDeep(cable.temperatures).reverse();
|
||||
// let humClone = cloneDeep(cable.humidities).reverse();
|
||||
// let emcClone = cloneDeep(cable.grainMoistures).reverse();
|
||||
// //add the cable data to the proper arrays
|
||||
// if (cable.topNode > 0) {
|
||||
// temps.push(...tempClone.splice(0, cable.topNode));
|
||||
// humids.push(...humClone.splice(0, cable.topNode));
|
||||
// emcs.push(...emcClone.splice(0, cable.topNode));
|
||||
// } else {
|
||||
// //if the cable has no fill set (top node) then use all of the nodes
|
||||
// temps = tempClone;
|
||||
// humids = humClone;
|
||||
// emcs = emcClone;
|
||||
// }
|
||||
// //add the trend data to the proper arrays if the top node is set
|
||||
// let cableTrendData = binTrend.cableTrend[cable.key()];
|
||||
// tempTrends.push(cableTrendData.grainCelciusTrend);
|
||||
// humidTrends.push(cableTrendData.grainHumidityTrend);
|
||||
// emcTrends.push(cableTrendData.grainEmcTrend);
|
||||
let lowNodeConditions: GrainConditions | undefined = undefined;
|
||||
let highNodeConditions: GrainConditions | undefined = undefined;
|
||||
let avgConditions: GrainConditions | undefined = undefined;
|
||||
trendCables.forEach(cable => {
|
||||
//only use the values below the top node
|
||||
//because splice mutates the original array make a clone in the cables so the svg still has all of them for display
|
||||
//also reverse it so that the node 1 (end of the cable) is in the first position
|
||||
let tempClone = cloneDeep(cable.temperatures).reverse();
|
||||
let humClone = cloneDeep(cable.humidities).reverse();
|
||||
let emcClone = cloneDeep(cable.grainMoistures).reverse();
|
||||
//add the cable data to the proper arrays
|
||||
if (cable.topNode > 0) {
|
||||
temps.push(...tempClone.splice(0, cable.topNode));
|
||||
humids.push(...humClone.splice(0, cable.topNode));
|
||||
emcs.push(...emcClone.splice(0, cable.topNode));
|
||||
} else {
|
||||
//if the cable has no fill set (top node) then use all of the nodes
|
||||
temps = tempClone;
|
||||
humids = humClone;
|
||||
emcs = emcClone;
|
||||
}
|
||||
//add the trend data to the proper arrays if the top node is set
|
||||
let cableTrendData = binTrend.cableTrend[cable.key()];
|
||||
tempTrends.push(cableTrendData.grainCelciusTrend);
|
||||
humidTrends.push(cableTrendData.grainHumidityTrend);
|
||||
emcTrends.push(cableTrendData.grainEmcTrend);
|
||||
|
||||
// //if the lowest temp for this cable is less than the temp in the low node conditions or the low node conditions are not set
|
||||
// //use this cables lowest node and trend data in the condition
|
||||
// if (!lowNodeConditions || Math.min(...temps) < lowNodeConditions.tempC) {
|
||||
// //determine which node is the coldest so that the data displayed is for the same node
|
||||
// let lowTempIndex =
|
||||
// temps.indexOf(Math.min(...temps)) === -1 ? 0 : temps.indexOf(Math.min(...temps));
|
||||
// lowNodeConditions = {
|
||||
// tempC: temps[lowTempIndex],
|
||||
// humidity: humids[lowTempIndex],
|
||||
// emc: emcs[lowTempIndex],
|
||||
// tempCTrend: cableTrendData.coldNodeTrend?.tempTrend ?? 0,
|
||||
// humidityTrend: cableTrendData.coldNodeTrend?.humidityTrend ?? 0,
|
||||
// emcTrend: cableTrendData.coldNodeTrend?.emcTrend ?? 0
|
||||
// };
|
||||
// }
|
||||
//if the lowest temp for this cable is less than the temp in the low node conditions or the low node conditions are not set
|
||||
//use this cables lowest node and trend data in the condition
|
||||
if (!lowNodeConditions || Math.min(...temps) < lowNodeConditions.tempC) {
|
||||
//determine which node is the coldest so that the data displayed is for the same node
|
||||
let lowTempIndex =
|
||||
temps.indexOf(Math.min(...temps)) === -1 ? 0 : temps.indexOf(Math.min(...temps));
|
||||
lowNodeConditions = {
|
||||
tempC: temps[lowTempIndex],
|
||||
humidity: humids[lowTempIndex],
|
||||
emc: emcs[lowTempIndex],
|
||||
tempCTrend: cableTrendData.coldNodeTrend?.tempTrend ?? 0,
|
||||
humidityTrend: cableTrendData.coldNodeTrend?.humidityTrend ?? 0,
|
||||
emcTrend: cableTrendData.coldNodeTrend?.emcTrend ?? 0
|
||||
};
|
||||
}
|
||||
|
||||
// //do the same for the high node
|
||||
// if (!highNodeConditions || cable.maxTemp() > highNodeConditions.tempC) {
|
||||
// let highTempIndex =
|
||||
// temps.indexOf(Math.max(...temps)) === -1 ? 0 : temps.indexOf(Math.max(...temps));
|
||||
// highNodeConditions = {
|
||||
// tempC: temps[highTempIndex],
|
||||
// humidity: humids[highTempIndex],
|
||||
// emc: emcs[highTempIndex],
|
||||
// tempCTrend: cableTrendData.hotNodeTrend?.tempTrend ?? 0,
|
||||
// humidityTrend: cableTrendData.hotNodeTrend?.humidityTrend ?? 0,
|
||||
// emcTrend: cableTrendData.hotNodeTrend?.emcTrend ?? 0
|
||||
// };
|
||||
// }
|
||||
// });
|
||||
// //set the average conditions
|
||||
// avgConditions = {
|
||||
// tempC: average(temps),
|
||||
// humidity: average(humids),
|
||||
// emc: average(emcs),
|
||||
// tempCTrend: average(tempTrends),
|
||||
// humidityTrend: average(humidTrends),
|
||||
// emcTrend: average(emcTrends)
|
||||
// };
|
||||
// setAverageConditions(avgConditions);
|
||||
// setLowNodeConditions(lowNodeConditions);
|
||||
// setHighNodeConditions(highNodeConditions);
|
||||
// })
|
||||
// .catch(err => {
|
||||
// console.log(err);
|
||||
// openSnack("Failed to retrieve trend data");
|
||||
// })
|
||||
// .finally(() => {
|
||||
// setLoadingTrend(false);
|
||||
// });
|
||||
//do the same for the high node
|
||||
if (!highNodeConditions || cable.maxTemp() > highNodeConditions.tempC) {
|
||||
let highTempIndex =
|
||||
temps.indexOf(Math.max(...temps)) === -1 ? 0 : temps.indexOf(Math.max(...temps));
|
||||
highNodeConditions = {
|
||||
tempC: temps[highTempIndex],
|
||||
humidity: humids[highTempIndex],
|
||||
emc: emcs[highTempIndex],
|
||||
tempCTrend: cableTrendData.hotNodeTrend?.tempTrend ?? 0,
|
||||
humidityTrend: cableTrendData.hotNodeTrend?.humidityTrend ?? 0,
|
||||
emcTrend: cableTrendData.hotNodeTrend?.emcTrend ?? 0
|
||||
};
|
||||
}
|
||||
});
|
||||
//set the average conditions
|
||||
avgConditions = {
|
||||
tempC: average(temps),
|
||||
humidity: average(humids),
|
||||
emc: average(emcs),
|
||||
tempCTrend: average(tempTrends),
|
||||
humidityTrend: average(humidTrends),
|
||||
emcTrend: average(emcTrends)
|
||||
};
|
||||
setAverageConditions(avgConditions);
|
||||
setLowNodeConditions(lowNodeConditions);
|
||||
setHighNodeConditions(highNodeConditions);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
openSnack("Failed to retrieve trend data");
|
||||
})
|
||||
.finally(() => {
|
||||
setLoadingTrend(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [binAPI, bin, cables, openSnack]); //eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
|
@ -485,7 +485,7 @@ export default function BinVisualizer(props: Props) {
|
|||
if (bin.settings.inventory && bin.settings.specs) {
|
||||
const isEmpty = bin.settings.inventory?.empty === true;
|
||||
const capacity = bin.settings.specs.bushelCapacity;
|
||||
const grainBushels = bin.settings.inventory.grainBushels;
|
||||
const grainBushels = bin.bushels();
|
||||
setSliderCoulour("gold");
|
||||
if (!capacity) {
|
||||
setFillPercentage(null);
|
||||
|
|
@ -535,7 +535,7 @@ export default function BinVisualizer(props: Props) {
|
|||
|
||||
const inventoryOverview = () => {
|
||||
const capacity = bin.settings.specs?.bushelCapacity ?? 0;
|
||||
const grainBushels = bin.settings.inventory?.grainBushels ?? 0;
|
||||
const grainBushels = bin.bushels();
|
||||
const isEmpty = bin.settings.inventory?.empty === true || !grainBushels || grainBushels <= 0;
|
||||
const grainType = bin.settings.inventory?.grainType;
|
||||
const grainTypeName = isEmpty || !grainType ? "" : GrainDescriber(grainType).name;
|
||||
|
|
@ -1481,9 +1481,7 @@ export default function BinVisualizer(props: Props) {
|
|||
onChange={(_, value) => {
|
||||
setFillPercentage(value as number);
|
||||
const capacity = bin.settings.specs ? bin.settings.specs.bushelCapacity : 0;
|
||||
const current = bin.settings.inventory
|
||||
? bin.settings.inventory.grainBushels
|
||||
: 0;
|
||||
const current = bin.bushels()
|
||||
let grainAmount = ((value as number) / 100) * capacity;
|
||||
|
||||
if (grainAmount < current) {
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@ const useStyles = makeStyles((theme: Theme) => {
|
|||
borderTopLeftRadius: "6px",
|
||||
borderTopRightRadius: "6px",
|
||||
background: theme.palette.background.default,
|
||||
fontWeight: 1000,
|
||||
transform: "0.3s ease-in-out",
|
||||
// "linear-gradient(rgba(150, 150, 150, 0.3),"
|
||||
// + theme.palette.background.default + " 80%)"
|
||||
|
|
|
|||
|
|
@ -123,10 +123,11 @@ export default function BinyardDisplay(props: Props) {
|
|||
});
|
||||
|
||||
const loadBins = useCallback(() => {
|
||||
setBinsLoading(true);
|
||||
if (yardKey === "") return
|
||||
//load the bins based on the yard key
|
||||
setBinsLoading(true);
|
||||
binAPI
|
||||
.listBinsAndData(maxBins, 0, "asc", "name", undefined, as, undefined, [yardKey], ["binyard"])
|
||||
.listBinsAndData(maxBins, 0, "asc", "name", undefined, undefined, undefined, [yardKey], ["binyard"])
|
||||
.then(resp => {
|
||||
let yardBins: Bin[] = [];
|
||||
let grainBins: Bin[] = [];
|
||||
|
|
@ -315,17 +316,10 @@ export default function BinyardDisplay(props: Props) {
|
|||
<Grid size={12}>
|
||||
<BinsList
|
||||
gridView
|
||||
valDisplay="average"
|
||||
bins={grainBins}
|
||||
duplicateBin={duplicateBin}
|
||||
title={"Grain Bins"}
|
||||
// because this only triggers in scroll view it is no longer necessary as we dont do the scroll here
|
||||
// loadMore={newTranslation => {
|
||||
// //only triggered in the scroll view so this will never trigger in grid view
|
||||
// if (yardBins.length < binTotal) {
|
||||
// loadMoreBins(contentFilter);
|
||||
// setScrollTranslations({ ...scrollTranslations, bins: newTranslation });
|
||||
// }
|
||||
// }}
|
||||
/>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
|
|
@ -338,16 +332,10 @@ export default function BinyardDisplay(props: Props) {
|
|||
<Grid size={12}>
|
||||
<BinsList
|
||||
gridView
|
||||
valDisplay="average"
|
||||
bins={fertBins}
|
||||
duplicateBin={duplicateBin}
|
||||
title={"Fertilizer Bins"}
|
||||
// loadMore={newTranslation => {
|
||||
// //only triggered in the scroll view so this will never trigger in grid view
|
||||
// if (yardBins.length < binTotal) {
|
||||
// loadMoreBins(contentFilter);
|
||||
// setScrollTranslations({ ...scrollTranslations, fertilizer: newTranslation });
|
||||
// }
|
||||
// }}
|
||||
/>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
|
|
@ -360,6 +348,7 @@ export default function BinyardDisplay(props: Props) {
|
|||
<Grid size={12}>
|
||||
<BinsList
|
||||
gridView
|
||||
valDisplay="average"
|
||||
bins={emptyBins}
|
||||
duplicateBin={duplicateBin}
|
||||
title={"Empty Bins"}
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ export default function DisplayDrawer(props: Props) {
|
|||
</Grid>
|
||||
<Grid>
|
||||
<Box>
|
||||
<Typography align="center" variant="h5">
|
||||
<Typography sx={{ color: "black", fontWeight: 650}} align="center" variant="h5">
|
||||
{title}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { Beenhere } from "@mui/icons-material";
|
|||
import { useThemeType } from "hooks";
|
||||
import moment from "moment";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Map, { Marker } from "react-map-gl/mapbox-legacy";
|
||||
import Map, { Marker } from "react-map-gl/mapbox";
|
||||
|
||||
const MAPBOX_TOKEN = import.meta.env.VITE_MAPBOX_ACCESS_TOKEN;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ import {
|
|||
Button,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
Grid,
|
||||
Grid2 as Grid,
|
||||
TextField,
|
||||
Theme,
|
||||
Typography
|
||||
} from "@mui/material";
|
||||
|
|
@ -13,6 +14,8 @@ import ResponsiveDialog from "common/ResponsiveDialog";
|
|||
import { DateRangePreset, GetDefaultDateRange, SetDefaultPreset } from "./DateRange";
|
||||
import { useThemeType } from "hooks";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
import { cloneDeep } from "lodash";
|
||||
import { color } from "@mui/system";
|
||||
|
||||
interface Props {
|
||||
startDate: Moment;
|
||||
|
|
@ -26,10 +29,12 @@ type DateRange<T> = [T | null, T | null];
|
|||
const useStyles = makeStyles((_theme: Theme) => {
|
||||
return ({
|
||||
activeButtonLight: {
|
||||
border: "1px solid black"
|
||||
border: "1px solid black",
|
||||
color: "black"
|
||||
},
|
||||
acitveButtonDark: {
|
||||
border: "1px solid white"
|
||||
border: "1px solid white",
|
||||
color: "white"
|
||||
}
|
||||
})
|
||||
});
|
||||
|
|
@ -49,7 +54,7 @@ export default function TimeBar(props: Props) {
|
|||
|
||||
const submitDateRange = () => {
|
||||
const startDate = dateRange[0] ? dateRange[0].clone() : moment();
|
||||
const endDate = dateRange[1] ? dateRange[1].clone() : moment();
|
||||
const endDate = dateRange[1] ? dateRange[1].add(1, "day").clone() : moment(); //add 1 day to the end time to include that day rather than have it be the cutoff
|
||||
updateDateRange(startDate, endDate, false);
|
||||
setDateRangeDialog(false);
|
||||
setActiveView("selectRange");
|
||||
|
|
@ -85,19 +90,30 @@ export default function TimeBar(props: Props) {
|
|||
onClose={() => setDateRangeDialog(false)}
|
||||
aria-labelledby="date-range-dialog">
|
||||
<DialogContent>
|
||||
{/* <StaticDateRangePicker
|
||||
disableFuture
|
||||
value={dateRange}
|
||||
onChange={date => setDateRange(date)}
|
||||
renderInput={(startProps, endProps) => (
|
||||
<React.Fragment>
|
||||
<TextField {...startProps} />
|
||||
<DateRangeDelimiter> to </DateRangeDelimiter>
|
||||
<TextField {...endProps} />
|
||||
</React.Fragment>
|
||||
)}
|
||||
/> */}
|
||||
DATE PICKER GOES HERE
|
||||
<TextField
|
||||
fullWidth
|
||||
margin="normal"
|
||||
type="date"
|
||||
label="Start Time"
|
||||
value={dateRange[0]?.format("YYYY-MM-DD")}
|
||||
onChange={e => {
|
||||
let range = cloneDeep(dateRange)
|
||||
range[0] = moment(e.target.value)
|
||||
setDateRange(range)
|
||||
}}
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
margin="normal"
|
||||
type="date"
|
||||
label="End Time"
|
||||
value={dateRange[1]?.format("YYYY-MM-DD")}
|
||||
onChange={e => {
|
||||
let range = cloneDeep(dateRange)
|
||||
range[1] = moment(e.target.value)
|
||||
setDateRange(range)
|
||||
}}
|
||||
/>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={() => setDateRangeDialog(false)} color="primary">
|
||||
|
|
@ -115,7 +131,7 @@ export default function TimeBar(props: Props) {
|
|||
<React.Fragment>
|
||||
{datePickerDialog()}
|
||||
<Grid container direction="row" spacing={1} wrap="nowrap">
|
||||
<Grid item>
|
||||
<Grid>
|
||||
<Button
|
||||
style={{ borderRadius: "25px" }}
|
||||
className={
|
||||
|
|
@ -132,7 +148,7 @@ export default function TimeBar(props: Props) {
|
|||
<Typography style={{ fontWeight: 650 }}>1H</Typography>
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Grid>
|
||||
<Button
|
||||
style={{ borderRadius: "25px" }}
|
||||
className={
|
||||
|
|
@ -149,7 +165,7 @@ export default function TimeBar(props: Props) {
|
|||
<Typography style={{ fontWeight: 650 }}>1D</Typography>
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Grid>
|
||||
<Button
|
||||
style={{ borderRadius: "25px" }}
|
||||
className={
|
||||
|
|
@ -166,7 +182,7 @@ export default function TimeBar(props: Props) {
|
|||
<Typography style={{ fontWeight: 650 }}>1W</Typography>
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Grid>
|
||||
<Button
|
||||
style={{ borderRadius: "25px" }}
|
||||
className={
|
||||
|
|
@ -183,7 +199,7 @@ export default function TimeBar(props: Props) {
|
|||
<Typography style={{ fontWeight: 650 }}>1M</Typography>
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Grid>
|
||||
<Button
|
||||
style={{ borderRadius: "25px" }}
|
||||
className={
|
||||
|
|
|
|||
|
|
@ -237,8 +237,7 @@ export default function ComponentForm(props: Props) {
|
|||
};
|
||||
|
||||
useEffect(() => {
|
||||
let comp = tidyComponent(form.component);
|
||||
componentChanged(comp, isFormValid());
|
||||
componentChanged(form.component, isFormValid());
|
||||
}, [form.component, componentChanged]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const isNameValid = (name: string): boolean => {
|
||||
|
|
@ -950,7 +949,7 @@ export default function ComponentForm(props: Props) {
|
|||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={measure}
|
||||
checked={measure}
|
||||
onChange={toggleMeasure}
|
||||
name="measure"
|
||||
aria-label="measure"
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {
|
|||
DialogTitle,
|
||||
Divider,
|
||||
Grid2,
|
||||
IconButton,
|
||||
lighten,
|
||||
List,
|
||||
ListItem,
|
||||
|
|
@ -36,12 +37,23 @@ import { useGlobalState } from "providers";
|
|||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import RemoveGroup from "./RemoveGroup";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { Add, Remove } from "@mui/icons-material";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => {
|
||||
return ({
|
||||
deviceListContainer: {
|
||||
marginBottom: theme.spacing(1)
|
||||
},
|
||||
listTitle: {
|
||||
fontSize: 20,
|
||||
fontWeight: 650
|
||||
},
|
||||
listButton: {
|
||||
cursor: "pointer",
|
||||
"&:hover": {
|
||||
backgroundColor: lighten(theme.palette.background.default, 0.25)
|
||||
}
|
||||
},
|
||||
devicesList: {
|
||||
overflow: "auto",
|
||||
minHeight: "25vh",
|
||||
|
|
@ -87,6 +99,7 @@ export default function GroupSettings(props: Props) {
|
|||
const deviceAPI = useDeviceAPI();
|
||||
const snackbar = useSnackbar()
|
||||
const [devices, setDevices] = useState<Device[]>([]);
|
||||
const [nonGroupDevices, setNonGroupDevices] = useState<Device[]>([]);
|
||||
const [group, setGroup] = useState<Group>(initialGroup ? Group.clone(initialGroup) : new Group());
|
||||
const [isRemoveGroupOpen, setIsRemoveGroupOpen] = useState<boolean>(
|
||||
mode === "remove" ? true : false
|
||||
|
|
@ -109,13 +122,14 @@ export default function GroupSettings(props: Props) {
|
|||
|
||||
const loadDevices = useCallback(() => {
|
||||
setLoadingDevices(true);
|
||||
//this lists the devices for the user/team viewing
|
||||
deviceAPI
|
||||
.list(1000000, 0, "asc")
|
||||
.then((response: any) => {
|
||||
let rDevices: Device[] = response.data.devices
|
||||
? response.data.devices.map((device: any) => Device.any(device))
|
||||
: [];
|
||||
|
||||
//remove duplicates from the options
|
||||
setDevices(rDevices);
|
||||
})
|
||||
.catch((_error: any) => {
|
||||
|
|
@ -124,6 +138,16 @@ export default function GroupSettings(props: Props) {
|
|||
.finally(() => setLoadingDevices(false));
|
||||
}, [deviceAPI, as]);
|
||||
|
||||
useEffect(()=>{
|
||||
let ungrouped: Device[] = []
|
||||
devices.forEach(device => {
|
||||
if(!groupDeviceNumbers.includes(device.id())){
|
||||
ungrouped.push(device)
|
||||
}
|
||||
})
|
||||
setNonGroupDevices(ungrouped)
|
||||
},[groupDeviceNumbers, devices])
|
||||
|
||||
useEffect(() => {
|
||||
if (prevInitialGroup !== initialGroup) {
|
||||
setGroup(initialGroup ? Group.clone(initialGroup) : new Group());
|
||||
|
|
@ -317,27 +341,58 @@ export default function GroupSettings(props: Props) {
|
|||
</ListItem>
|
||||
</List>
|
||||
) : (
|
||||
<List dense className={classes.devicesList}>
|
||||
{filterDevices(deviceSearch, devices, [])
|
||||
.sort((a, b: Device) => a.name().localeCompare(b.name()))
|
||||
.map(device => {
|
||||
const label = `checkbox-list-secondary-label-${device.id()}`;
|
||||
return (
|
||||
<ListItem key={device.id()} onClick={() => changeDevices(device.id())}>
|
||||
<ListItemText id={label} primary={device.name()} />
|
||||
<ListItemSecondaryAction>
|
||||
<Checkbox
|
||||
edge="end"
|
||||
onChange={() => changeDevices(device.id())}
|
||||
checked={group.settings.devices.includes(device.id())}
|
||||
inputProps={{ "aria-labelledby": label }}
|
||||
disabled={!canEdit}
|
||||
/>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
);
|
||||
})}
|
||||
</List>
|
||||
<React.Fragment>
|
||||
{groupDevices &&
|
||||
<List dense className={classes.devicesList}>
|
||||
{filterDevices(deviceSearch, groupDevices, [])
|
||||
.sort((a, b: Device) => a.name().localeCompare(b.name()))
|
||||
.map(device => {
|
||||
const label = `checkbox-list-secondary-label-${device.id()}`;
|
||||
return (
|
||||
<ListItem className={classes.listButton} key={device.id()} onClick={() => {
|
||||
removeDevice(device.id())
|
||||
}}>
|
||||
<ListItemText id={label} primary={device.name()} />
|
||||
<ListItemSecondaryAction>
|
||||
{/* <Checkbox
|
||||
edge="end"
|
||||
onChange={() => changeDevices(device.id())}
|
||||
checked={group.settings.devices.includes(device.id())}
|
||||
inputProps={{ "aria-labelledby": label }}
|
||||
disabled={!canEdit}
|
||||
/> */}
|
||||
-
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
);
|
||||
})}
|
||||
</List>
|
||||
}
|
||||
<List dense className={classes.devicesList}>
|
||||
{filterDevices(deviceSearch, nonGroupDevices, [])
|
||||
.sort((a, b: Device) => a.name().localeCompare(b.name()))
|
||||
.map(device => {
|
||||
const label = `checkbox-list-secondary-label-${device.id()}`;
|
||||
return (
|
||||
<ListItem className={classes.listButton} key={device.id()} onClick={() => {
|
||||
addDevice(device.id())
|
||||
}}>
|
||||
<ListItemText id={label} primary={device.name()} />
|
||||
<ListItemSecondaryAction>
|
||||
{/* <Checkbox
|
||||
edge="end"
|
||||
onChange={() => changeDevices(device.id())}
|
||||
checked={group.settings.devices.includes(device.id())}
|
||||
inputProps={{ "aria-labelledby": label }}
|
||||
disabled={!canEdit}
|
||||
/> */}
|
||||
+
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
);
|
||||
})}
|
||||
</List>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</Paper>
|
||||
);
|
||||
|
|
@ -383,16 +438,49 @@ export default function GroupSettings(props: Props) {
|
|||
</ListItem>
|
||||
</List>
|
||||
) : (
|
||||
<React.Fragment>
|
||||
{groupDevices &&
|
||||
<React.Fragment>
|
||||
<Typography className={classes.listTitle}>Grouped Devices</Typography>
|
||||
<List dense className={classes.devicesList}>
|
||||
{filterDevices(deviceSearch, groupDevices, [])
|
||||
.sort((a, b: Device) => a.name().localeCompare(b.name()))
|
||||
.map(device => {
|
||||
const label = `checkbox-list-secondary-label-${device.id()}`;
|
||||
return (
|
||||
<ListItem className={classes.listButton} key={device.id()} onClick={() => {
|
||||
removeDevice(device.id())
|
||||
}}>
|
||||
<ListItemText id={label} primary={device.name()} />
|
||||
<ListItemSecondaryAction>
|
||||
{/* <Checkbox
|
||||
edge="end"
|
||||
onChange={() => changeDevices(device.id())}
|
||||
checked={group.settings.devices.includes(device.id())}
|
||||
inputProps={{ "aria-labelledby": label }}
|
||||
disabled={!canEdit}
|
||||
/> */}
|
||||
<Remove />
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
);
|
||||
})}
|
||||
</List>
|
||||
</React.Fragment>
|
||||
}
|
||||
<Typography className={classes.listTitle}>Devices You Can Add</Typography>
|
||||
<List dense className={classes.devicesList}>
|
||||
{filterDevices(deviceSearch, devices, [])
|
||||
{filterDevices(deviceSearch, nonGroupDevices, [])
|
||||
.sort((a, b: Device) => a.name().localeCompare(b.name()))
|
||||
.map(device => {
|
||||
const label = `checkbox-list-secondary-label-${device.id()}`;
|
||||
return (
|
||||
<ListItem key={device.id()} onClick={() => changeDevices(device.id())}>
|
||||
<ListItem className={classes.listButton} key={device.id()} onClick={() => {
|
||||
addDevice(device.id())
|
||||
}}>
|
||||
<ListItemText id={label} primary={device.name()} />
|
||||
<ListItemSecondaryAction>
|
||||
<Checkbox
|
||||
{/* <Checkbox
|
||||
edge="end"
|
||||
onChange={(_, checked) => {
|
||||
if (checked) addDevice(device.id());
|
||||
|
|
@ -402,12 +490,14 @@ export default function GroupSettings(props: Props) {
|
|||
checked={groupDeviceNumbers.includes(device.id())}
|
||||
inputProps={{ "aria-labelledby": label }}
|
||||
disabled={!canEdit}
|
||||
/>
|
||||
/> */}
|
||||
<Add />
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
);
|
||||
})}
|
||||
</List>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</Paper>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ import { GeometryMapping, shapeFromCoords } from "models/GeometryMapping";
|
|||
import { FeatureCollection, Feature } from "geojson";
|
||||
import DrawController from "./mapControllers/drawController";
|
||||
//import { Geometry } from "geojson";
|
||||
import Map, { MapRef, Marker, MarkerDragEvent } from "react-map-gl/mapbox-legacy";
|
||||
import Map, { MapRef, Marker, MarkerDragEvent } from "react-map-gl/mapbox";
|
||||
import { getDistanceUnit } from "utils";
|
||||
import { MapMouseEvent } from "mapbox-gl";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { ControlPosition, useMap } from "react-map-gl/mapbox-legacy";
|
||||
import { ControlPosition, useMap } from "react-map-gl/mapbox";
|
||||
import MapboxGeocoder, { Result } from "@mapbox/mapbox-gl-geocoder";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useEffect, useRef } from "react";
|
||||
import { useMap } from "react-map-gl/mapbox-legacy";
|
||||
import { useMap } from "react-map-gl/mapbox";
|
||||
import { FeatureCollection } from "geojson";
|
||||
import MapboxDraw from "@mapbox/mapbox-gl-draw";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useEffect } from "react";
|
||||
import { Layer, Source } from "react-map-gl/mapbox-legacy";
|
||||
import { Layer, Source } from "react-map-gl/mapbox";
|
||||
import { FeatureCollection } from "geojson";
|
||||
|
||||
interface Props {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { useMobile } from "hooks";
|
|||
import { clone } from "lodash";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { Marker } from "react-map-gl/mapbox-legacy";
|
||||
import { Marker } from "react-map-gl/mapbox";
|
||||
|
||||
//interface for markers
|
||||
export interface MarkerData {
|
||||
|
|
|
|||
|
|
@ -185,6 +185,8 @@ import { Result } from "@mapbox/mapbox-gl-geocoder";
|
|||
const [measurement, setMeasurement] = useState(false);
|
||||
const [measurementData, setMeasurementData] = useState<Map<string, MeasurementData>>(new Map());
|
||||
const measurementRef = useRef(measurementData);
|
||||
const zoomRef = useRef(15)
|
||||
const fieldMarkerZoom = 15
|
||||
|
||||
//watches for changes to the viewing as and sets the load boolean to trigger a load
|
||||
useEffect(() => {
|
||||
|
|
@ -591,12 +593,13 @@ import { Result } from "@mapbox/mapbox-gl-geocoder";
|
|||
}
|
||||
let newFM = fieldMarkers.get(newKey);
|
||||
if (newFM) {
|
||||
setCurrentView({
|
||||
let view = {
|
||||
latitude: newFM.lat(),
|
||||
longitude: newFM.long(),
|
||||
zoom: 12,
|
||||
zoom: currentView.zoom,
|
||||
transitionDuration: 1000
|
||||
});
|
||||
}
|
||||
setCurrentView(view);
|
||||
}
|
||||
setObjectKey(newKey);
|
||||
setFMIndexKey(newID);
|
||||
|
|
@ -621,12 +624,13 @@ import { Result } from "@mapbox/mapbox-gl-geocoder";
|
|||
}
|
||||
let newFM = fieldMarkers.get(newKey);
|
||||
if (newFM) {
|
||||
setCurrentView({
|
||||
let view = {
|
||||
latitude: newFM.lat(),
|
||||
longitude: newFM.long(),
|
||||
zoom: 12,
|
||||
zoom: currentView.zoom,
|
||||
transitionDuration: 1000
|
||||
});
|
||||
}
|
||||
setCurrentView(view);
|
||||
}
|
||||
setObjectKey(newKey);
|
||||
setFMIndexKey(newID);
|
||||
|
|
@ -699,7 +703,12 @@ import { Result } from "@mapbox/mapbox-gl-geocoder";
|
|||
</Grid>
|
||||
</Grid>
|
||||
<Grid size={3}>
|
||||
<Button style={{ margin: "auto" }} onClick={() => setOpenFMSettings(true)}>
|
||||
<Button
|
||||
style={{ margin: "auto" }}
|
||||
onClick={() => {
|
||||
setOpenFMSettings(true)
|
||||
setAnchorFieldMarker(null)
|
||||
}}>
|
||||
<Edit />
|
||||
</Button>
|
||||
</Grid>
|
||||
|
|
@ -728,13 +737,14 @@ import { Result } from "@mapbox/mapbox-gl-geocoder";
|
|||
subtype: fm.type(),
|
||||
mini: true,
|
||||
clickFunc: (event, index) => {
|
||||
console.log(zoomRef)
|
||||
clickDelay();
|
||||
closeDrawers();
|
||||
setIgnoreFeatures(true);
|
||||
setCurrentView({
|
||||
latitude: fm.lat(),
|
||||
longitude: fm.long(),
|
||||
zoom: 12,
|
||||
zoom: zoomRef.current,
|
||||
transitionDuration: 0
|
||||
//transitionInterpolator: new FlyToInterpolator()
|
||||
});
|
||||
|
|
@ -1115,14 +1125,16 @@ import { Result } from "@mapbox/mapbox-gl-geocoder";
|
|||
let xOff = !mobileOffset ? -250 : undefined;
|
||||
let yOff = mobileOffset ? -150 : undefined;
|
||||
|
||||
setCurrentView({
|
||||
let view = {
|
||||
latitude: lat,
|
||||
longitude: long,
|
||||
zoom: zoom,
|
||||
transitionDuration: transDuration,
|
||||
xOffset: center ? 0 : xOff,
|
||||
yOffset: center ? 0 : yOff
|
||||
});
|
||||
}
|
||||
setCurrentView(view);
|
||||
zoomRef.current = zoom
|
||||
};
|
||||
|
||||
const markerDialog = () => {
|
||||
|
|
|
|||
|
|
@ -125,11 +125,23 @@ export class Bin {
|
|||
return colour;
|
||||
}
|
||||
|
||||
public bushels(): number {
|
||||
let bushels = this.settings.inventory?.grainBushels || 0
|
||||
if (this.settings.inventory?.inventoryControl === pond.BinInventoryControl.BIN_INVENTORY_CONTROL_AUTOMATIC_LIDAR){
|
||||
bushels = this.status.grainBushels
|
||||
}
|
||||
return bushels
|
||||
}
|
||||
|
||||
public fillPercent(): number {
|
||||
let fill = 0;
|
||||
if (this.settings.inventory && this.settings.specs) {
|
||||
let bushels = this.settings.inventory.grainBushels
|
||||
if (this.settings.inventory.inventoryControl === pond.BinInventoryControl.BIN_INVENTORY_CONTROL_AUTOMATIC_LIDAR){
|
||||
bushels = this.status.grainBushels
|
||||
}
|
||||
fill = Math.round(
|
||||
(this.settings.inventory.grainBushels / this.settings.specs.bushelCapacity) * 100
|
||||
(bushels / this.settings.specs.bushelCapacity) * 100
|
||||
);
|
||||
}
|
||||
return fill;
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ export default function BottomNavigator(props: Props) {
|
|||
return (
|
||||
<BottomNavigation value={route} onChange={(_, newValue) => handleRouteChange(newValue)}>
|
||||
{isAdaptive && (
|
||||
<BottomNavigationAction label="Farm" icon={<FieldsIcon type={getType()} />} value="fields" />
|
||||
<BottomNavigationAction label="Farm" icon={<FieldsIcon type={getType()} />} value="visualFarm" />
|
||||
)}
|
||||
{isAdaptive && (
|
||||
<BottomNavigationAction label="Bins" icon={<BinsIcon type={getType()} />} value="bins" />
|
||||
|
|
@ -114,7 +114,7 @@ export default function BottomNavigator(props: Props) {
|
|||
<BottomNavigationAction
|
||||
label="Site Map"
|
||||
icon={<FieldsIcon type={getType()} />}
|
||||
value="constructionsiteMap"
|
||||
value="constructionMap"
|
||||
/>
|
||||
)}
|
||||
{isOmni && (
|
||||
|
|
|
|||
|
|
@ -160,84 +160,6 @@ export default function SideNavigator(props: Props) {
|
|||
const isAdCon = IsAdCon()
|
||||
return (
|
||||
<List className={classes.list} component="nav">
|
||||
{(isAg || user.hasFeature("admin")) && (
|
||||
<Tooltip title="Bins" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-dashboard"
|
||||
onClick={() => goTo("/bins")}
|
||||
classes={getClasses("/bin")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<BinsIcon height={"26px"}/>
|
||||
</ListItemIcon>
|
||||
{open && <ListItemText primary="Bins" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
{(isMiPCA || user.hasFeature("admin")) && (
|
||||
<Tooltip title="Terminals" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-terminals"
|
||||
onClick={() => goTo("/terminals")}
|
||||
classes={getClasses("/terminal")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<PlaneIcon />
|
||||
</ListItemIcon>
|
||||
{open && <ListItemText primary="Terminals" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip title="Devices" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-dashboard"
|
||||
onClick={() => goTo("/devices")}
|
||||
classes={getClasses("/device")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<BindaptIcon />
|
||||
</ListItemIcon>
|
||||
{open && <ListItemText primary="Devices" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
{(isMiVent || user.hasFeature("admin")) && (
|
||||
<Tooltip title="Mines" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-dashboard"
|
||||
onClick={() => goTo("/mines")}
|
||||
classes={getClasses("/mine")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<MiningIcon height={"26px"} width={"26px"} />
|
||||
</ListItemIcon>
|
||||
{open && <ListItemText primary="Mines" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip title="Teams" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-dashboard"
|
||||
onClick={() => goTo("/teams")}
|
||||
classes={getClasses("/team")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<People style={{ color: getThemeType() === "light" ? "black" : undefined }}/>
|
||||
</ListItemIcon>
|
||||
{open && <ListItemText primary="Teams" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Users" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-dashboard"
|
||||
onClick={() => goTo("/users")}
|
||||
classes={getClasses("/user")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<Person style={{ color: getThemeType() === "light" ? "black" : undefined }}/>
|
||||
</ListItemIcon>
|
||||
{open && <ListItemText primary="Users" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
{(isAg || user.hasFeature("admin")) && (
|
||||
<Tooltip title="Visual Farm" placement="right">
|
||||
<ListItemButton
|
||||
|
|
@ -252,20 +174,6 @@ export default function SideNavigator(props: Props) {
|
|||
</ListItemButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
{(isAg || user.hasFeature("admin")) && (
|
||||
<Tooltip title="My Fields" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-field-list"
|
||||
onClick={() => goTo("/fields")}
|
||||
classes={getClasses("/fields")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<FieldListIcon />
|
||||
</ListItemIcon>
|
||||
{open && <ListItemText primary="My Fields" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
{(isMiPCA || user.hasFeature("admin")) && (
|
||||
<Tooltip title="Aviation Map" placement="right">
|
||||
<ListItemButton
|
||||
|
|
@ -294,6 +202,169 @@ export default function SideNavigator(props: Props) {
|
|||
</ListItemButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
{(isAg || user.hasFeature("admin")) && (
|
||||
<Tooltip title="Contracts" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-contracts"
|
||||
onClick={() => goTo("/contracts")}
|
||||
classes={getClasses("/contracts")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<ContractsIcon />
|
||||
</ListItemIcon>
|
||||
{open && <ListItemText primary="Contracts" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
{(isAg || user.hasFeature("admin")) && (
|
||||
<Tooltip title="Bins" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-dashboard"
|
||||
onClick={() => goTo("/bins")}
|
||||
classes={getClasses("/bin")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<BinsIcon height={"26px"}/>
|
||||
</ListItemIcon>
|
||||
{open && <ListItemText primary="Bins" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
{(isMiPCA || user.hasFeature("admin")) && (
|
||||
<Tooltip title="Terminals" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-terminals"
|
||||
onClick={() => goTo("/terminals")}
|
||||
classes={getClasses("/terminal")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<PlaneIcon />
|
||||
</ListItemIcon>
|
||||
{open && <ListItemText primary="Terminals" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
{(user.hasFeature("installer") && isAg || user.hasFeature("admin")) &&
|
||||
<Tooltip title="Cable Estimator" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-cable-estimator"
|
||||
onClick={() => goTo("/cableEstimate")}
|
||||
classes={getClasses("/cableEstimate")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<CableIcon />
|
||||
</ListItemIcon>
|
||||
{open && <ListItemText primary="Cable Estimator" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
}
|
||||
{(isAg || user.hasFeature("admin")) && (
|
||||
<Tooltip title="Transactions" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-transactions"
|
||||
onClick={() => goTo("/transactions")}
|
||||
classes={getClasses("/transactions")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<SyncAlt />
|
||||
</ListItemIcon>
|
||||
{open && <ListItemText primary="Transactions" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
{(isMiVent || user.hasFeature("admin")) && (
|
||||
<Tooltip title="Mines" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-dashboard"
|
||||
onClick={() => goTo("/mines")}
|
||||
classes={getClasses("/mine")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<MiningIcon height={"26px"} width={"26px"} />
|
||||
</ListItemIcon>
|
||||
{open && <ListItemText primary="Mines" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip title="Devices" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-dashboard"
|
||||
onClick={() => goTo("/devices")}
|
||||
classes={getClasses("/device")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<BindaptIcon />
|
||||
</ListItemIcon>
|
||||
{open && <ListItemText primary="Devices" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
{user.hasFeature("admin") &&
|
||||
<Tooltip title="Firmware" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-firmware"
|
||||
onClick={() => goTo("/firmware")}
|
||||
classes={getClasses("/firmware")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<Memory />
|
||||
</ListItemIcon>
|
||||
{open && <ListItemText primary="Logs" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
}
|
||||
{user.hasFeature("admin") &&
|
||||
<Tooltip title="Logs" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-logs"
|
||||
onClick={() => goTo("/logs")}
|
||||
classes={getClasses("/logs")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<DataDuckIcon />
|
||||
</ListItemIcon>
|
||||
{open && <ListItemText primary="Logs" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
}
|
||||
<Tooltip title="Teams" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-dashboard"
|
||||
onClick={() => goTo("/teams")}
|
||||
classes={getClasses("/team")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<People style={{ color: getThemeType() === "light" ? "black" : undefined }}/>
|
||||
</ListItemIcon>
|
||||
{open && <ListItemText primary="Teams" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Users" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-dashboard"
|
||||
onClick={() => goTo("/users")}
|
||||
classes={getClasses("/user")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<Person style={{ color: getThemeType() === "light" ? "black" : undefined }}/>
|
||||
</ListItemIcon>
|
||||
{open && <ListItemText primary="Users" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
{(isAg || user.hasFeature("admin")) && (
|
||||
<Tooltip title="My Fields" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-field-list"
|
||||
onClick={() => goTo("/fields")}
|
||||
classes={getClasses("/fields")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<FieldListIcon />
|
||||
</ListItemIcon>
|
||||
{open && <ListItemText primary="My Fields" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
{(isAdCon || user.hasFeature("admin")) && (
|
||||
<Tooltip title="Jobsites" placement="right">
|
||||
<ListItemButton
|
||||
|
|
@ -334,48 +405,7 @@ export default function SideNavigator(props: Props) {
|
|||
{open && <ListItemText primary="Tasks" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
{(isAg || user.hasFeature("admin")) && (
|
||||
<Tooltip title="Transactions" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-transactions"
|
||||
onClick={() => goTo("/transactions")}
|
||||
classes={getClasses("/transactions")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<SyncAlt />
|
||||
</ListItemIcon>
|
||||
{open && <ListItemText primary="Transactions" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
{(isAg || user.hasFeature("admin")) && (
|
||||
<Tooltip title="Contracts" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-contracts"
|
||||
onClick={() => goTo("/contracts")}
|
||||
classes={getClasses("/contracts")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<ContractsIcon />
|
||||
</ListItemIcon>
|
||||
{open && <ListItemText primary="Contracts" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
{(user.hasFeature("installer") && isAg || user.hasFeature("admin")) &&
|
||||
<Tooltip title="Cable Estimator" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-cable-estimator"
|
||||
onClick={() => goTo("/cableEstimate")}
|
||||
classes={getClasses("/cableEstimate")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<CableIcon />
|
||||
</ListItemIcon>
|
||||
{open && <ListItemText primary="Cable Estimator" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
}
|
||||
|
||||
{user.hasFeature("developer") &&
|
||||
<Tooltip title="API documentation" placement="right">
|
||||
<ListItemButton
|
||||
|
|
@ -390,34 +420,6 @@ export default function SideNavigator(props: Props) {
|
|||
</ListItemButton>
|
||||
</Tooltip>
|
||||
}
|
||||
{user.hasFeature("admin") &&
|
||||
<Tooltip title="Firmware" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-firmware"
|
||||
onClick={() => goTo("/firmware")}
|
||||
classes={getClasses("/firmware")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<Memory />
|
||||
</ListItemIcon>
|
||||
{open && <ListItemText primary="Logs" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
}
|
||||
{user.hasFeature("admin") &&
|
||||
<Tooltip title="Logs" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-logs"
|
||||
onClick={() => goTo("/logs")}
|
||||
classes={getClasses("/logs")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<DataDuckIcon />
|
||||
</ListItemIcon>
|
||||
{open && <ListItemText primary="Logs" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
}
|
||||
{user.hasFeature("admin") && window.NDEFReader &&
|
||||
<Tooltip title="NFC" placement="right">
|
||||
<ListItemButton
|
||||
|
|
|
|||
|
|
@ -547,7 +547,6 @@ export default function Bin(props: Props) {
|
|||
};
|
||||
|
||||
const tasks = () => {
|
||||
console.log(showTasks())
|
||||
if (showTasks()) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ export default function DevicePage() {
|
|||
}
|
||||
}
|
||||
});
|
||||
setDiagnosticComponents(diagComponents)
|
||||
setComponents(rComponents)
|
||||
let interactions: Interaction[] = [];
|
||||
resp.data.interactions.forEach((interaction: pond.Interaction) => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import {
|
||||
GraphComponent,
|
||||
GraphOrientation,
|
||||
GraphPoint,
|
||||
// GraphComponent,
|
||||
// GraphOrientation,
|
||||
// GraphPoint,
|
||||
GraphType,
|
||||
InteractionLine
|
||||
} from "common/Graph";
|
||||
|
|
@ -41,15 +41,15 @@ import {
|
|||
Weight,
|
||||
CapacitorCable
|
||||
} from "pbHelpers/ComponentTypes";
|
||||
import { multilineGrainCableData } from "pbHelpers/ComponentTypes/GrainCable";
|
||||
import { multilineCapCableData } from "./ComponentTypes/CapacitorCable";
|
||||
//import { multilineGrainCableData } from "pbHelpers/ComponentTypes/GrainCable";
|
||||
//import { multilineCapCableData } from "./ComponentTypes/CapacitorCable";
|
||||
import { findInteractionsAsSource } from "pbHelpers/Interaction";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { quack } from "protobuf-ts/quack";
|
||||
|
||||
import { notNull, or } from "utils/types";
|
||||
import { emptyComponentId } from "./Component";
|
||||
import { multilinePressureCableData } from "./ComponentTypes/PressureCable";
|
||||
//import { emptyComponentId } from "./Component";
|
||||
//import { multilinePressureCableData } from "./ComponentTypes/PressureCable";
|
||||
import { describeMeasurement, MeasurementDescriber } from "./MeasurementDescriber";
|
||||
import { convertedUnitMeasurement, MeasurementsFor, UnitMeasurement } from "models/UnitMeasurement";
|
||||
import { Sen5x } from "./ComponentTypes/Sen5x";
|
||||
|
|
@ -622,194 +622,194 @@ export function GetComponentIcon(
|
|||
}
|
||||
|
||||
//TODO: deprecated function, new graphs are handled in measurementChart (using reCharts instead of victory)
|
||||
export function getGraphProps(
|
||||
componentType: quack.ComponentType,
|
||||
subtype: number,
|
||||
measurements: pond.Measurement[],
|
||||
interactions: Interaction[],
|
||||
overlays: pond.ComponentOverlays[],
|
||||
orientation: GraphOrientation,
|
||||
filters?: GraphFilters
|
||||
): any {
|
||||
const componentID: quack.IComponentID = quack.ComponentID.fromObject(
|
||||
or(measurements[0].measurement, {
|
||||
id: emptyComponentId()
|
||||
}).id as any
|
||||
);
|
||||
let graphProps = {
|
||||
orientation: orientation
|
||||
} as any;
|
||||
let ext = extension(componentType, subtype);
|
||||
ext.measurements.forEach((componentMeasurement: ComponentMeasurement, index: number) => {
|
||||
let describer = describeMeasurement(
|
||||
componentMeasurement.measurementType,
|
||||
componentType,
|
||||
subtype
|
||||
);
|
||||
let range =
|
||||
filters && filters.ranges && filters.ranges[index] ? filters.ranges[index] : undefined;
|
||||
let selectedInteractions =
|
||||
filters && filters.selectedInteractions ? filters.selectedInteractions : [];
|
||||
let interactionLines = getInteractionLines(
|
||||
componentType,
|
||||
subtype,
|
||||
componentMeasurement.measurementType,
|
||||
componentID,
|
||||
interactions,
|
||||
selectedInteractions
|
||||
);
|
||||
let selectedOverlays = filters?.selectedOverlays ?? [];
|
||||
let overlayAreas = getOverlayAreas(
|
||||
componentMeasurement.measurementType,
|
||||
overlays,
|
||||
selectedOverlays
|
||||
);
|
||||
graphProps["graphComponent" + (index + 1).toString()] = {
|
||||
label: componentMeasurement.label,
|
||||
data: [],
|
||||
tick: describer.unit(),
|
||||
colour: componentMeasurement.colour,
|
||||
type: componentMeasurement.graphType,
|
||||
range: range,
|
||||
isBoolean:
|
||||
componentMeasurement.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_BOOLEAN,
|
||||
isPercent:
|
||||
componentMeasurement.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_PERCENT ||
|
||||
(componentMeasurement.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_ANALOG &&
|
||||
subtype === quack.AnalogInputSubtype.ANALOG_INPUT_SUBTYPE_FUEL),
|
||||
interactionLines: interactionLines,
|
||||
states: ext.states,
|
||||
decimals: describer.decimals(),
|
||||
overlays: overlayAreas
|
||||
} as GraphComponent;
|
||||
});
|
||||
// export function getGraphProps(
|
||||
// componentType: quack.ComponentType,
|
||||
// subtype: number,
|
||||
// measurements: pond.Measurement[],
|
||||
// interactions: Interaction[],
|
||||
// overlays: pond.ComponentOverlays[],
|
||||
// orientation: GraphOrientation,
|
||||
// filters?: GraphFilters
|
||||
// ): any {
|
||||
// const componentID: quack.IComponentID = quack.ComponentID.fromObject(
|
||||
// or(measurements[0].measurement, {
|
||||
// id: emptyComponentId()
|
||||
// }).id as any
|
||||
// );
|
||||
// let graphProps = {
|
||||
// orientation: orientation
|
||||
// } as any;
|
||||
// let ext = extension(componentType, subtype);
|
||||
// ext.measurements.forEach((componentMeasurement: ComponentMeasurement, index: number) => {
|
||||
// let describer = describeMeasurement(
|
||||
// componentMeasurement.measurementType,
|
||||
// componentType,
|
||||
// subtype
|
||||
// );
|
||||
// let range =
|
||||
// filters && filters.ranges && filters.ranges[index] ? filters.ranges[index] : undefined;
|
||||
// let selectedInteractions =
|
||||
// filters && filters.selectedInteractions ? filters.selectedInteractions : [];
|
||||
// let interactionLines = getInteractionLines(
|
||||
// componentType,
|
||||
// subtype,
|
||||
// componentMeasurement.measurementType,
|
||||
// componentID,
|
||||
// interactions,
|
||||
// selectedInteractions
|
||||
// );
|
||||
// let selectedOverlays = filters?.selectedOverlays ?? [];
|
||||
// let overlayAreas = getOverlayAreas(
|
||||
// componentMeasurement.measurementType,
|
||||
// overlays,
|
||||
// selectedOverlays
|
||||
// );
|
||||
// graphProps["graphComponent" + (index + 1).toString()] = {
|
||||
// label: componentMeasurement.label,
|
||||
// data: [],
|
||||
// tick: describer.unit(),
|
||||
// colour: componentMeasurement.colour,
|
||||
// type: componentMeasurement.graphType,
|
||||
// range: range,
|
||||
// isBoolean:
|
||||
// componentMeasurement.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_BOOLEAN,
|
||||
// isPercent:
|
||||
// componentMeasurement.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_PERCENT ||
|
||||
// (componentMeasurement.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_ANALOG &&
|
||||
// subtype === quack.AnalogInputSubtype.ANALOG_INPUT_SUBTYPE_FUEL),
|
||||
// interactionLines: interactionLines,
|
||||
// states: ext.states,
|
||||
// decimals: describer.decimals(),
|
||||
// overlays: overlayAreas
|
||||
// } as GraphComponent;
|
||||
// });
|
||||
|
||||
//for new cables add here to get the data for multiline
|
||||
if (showMultilineCable(componentType, filters)) {
|
||||
let cableData: any = {};
|
||||
if (componentType === quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE) {
|
||||
cableData = multilineGrainCableData(measurements, filters);
|
||||
} else if (componentType === quack.ComponentType.COMPONENT_TYPE_PRESSURE_CABLE) {
|
||||
cableData = multilinePressureCableData(measurements, filters);
|
||||
} else if (componentType === quack.ComponentType.COMPONENT_TYPE_CAPACITOR_CABLE) {
|
||||
cableData = multilineCapCableData(measurements, filters);
|
||||
}
|
||||
//will loop through the keys in cableData
|
||||
//IMPORTANT keys must be data1, data2, etc in the multiline function in the component
|
||||
for (let i = 1; i <= Object.keys(cableData).length; i++) {
|
||||
let gc = "graphComponent" + i;
|
||||
if (graphProps[gc]) {
|
||||
graphProps[gc].data = cableData["data" + i];
|
||||
graphProps[gc].type = GraphType.MULTILINE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
measurements.forEach((reading: pond.Measurement, readIndex) => {
|
||||
if (notNull(reading) && notNull(reading.timestamp) && notNull(reading.measurement)) {
|
||||
let date = new Date(Date.parse(reading.timestamp));
|
||||
for (let index = 0; index < ext.measurements.length; index++) {
|
||||
let componentMeasurement: ComponentMeasurement = ext.measurements[index];
|
||||
if (componentMeasurement.isErrorMeasurement(reading.measurement)) {
|
||||
break;
|
||||
}
|
||||
let dataPoint = null;
|
||||
switch (componentMeasurement.graphType) {
|
||||
case GraphType.AREA:
|
||||
let avg = componentMeasurement.extract(
|
||||
or(reading.measurement, {} as quack.Measurement),
|
||||
filters
|
||||
);
|
||||
if (avg && avg.low !== null && avg.high !== null) {
|
||||
dataPoint = {
|
||||
x: date,
|
||||
y: avg.low,
|
||||
y0: avg.high
|
||||
} as GraphPoint;
|
||||
}
|
||||
break;
|
||||
case GraphType.SCATTER:
|
||||
let scatter = componentMeasurement.extract(
|
||||
or(reading.measurement, {} as quack.Measurement),
|
||||
filters
|
||||
);
|
||||
if (scatter && scatter.value !== undefined && scatter.value !== null) {
|
||||
dataPoint = {
|
||||
x: date,
|
||||
y: Number(scatter.value),
|
||||
bubble: or(scatter.bubble, 0)
|
||||
} as GraphPoint;
|
||||
}
|
||||
break;
|
||||
case GraphType.RADAR:
|
||||
if (subtype === quack.AnalogInputSubtype.ANALOG_INPUT_SUBTYPE_WIND_DIRECTION) {
|
||||
let value = componentMeasurement.extract(
|
||||
or(reading.measurement, {} as quack.Measurement),
|
||||
filters
|
||||
);
|
||||
// //for new cables add here to get the data for multiline
|
||||
// if (showMultilineCable(componentType, filters)) {
|
||||
// let cableData: any = {};
|
||||
// if (componentType === quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE) {
|
||||
// cableData = multilineGrainCableData(measurements, filters);
|
||||
// } else if (componentType === quack.ComponentType.COMPONENT_TYPE_PRESSURE_CABLE) {
|
||||
// cableData = multilinePressureCableData(measurements, filters);
|
||||
// } else if (componentType === quack.ComponentType.COMPONENT_TYPE_CAPACITOR_CABLE) {
|
||||
// cableData = multilineCapCableData(measurements, filters);
|
||||
// }
|
||||
// //will loop through the keys in cableData
|
||||
// //IMPORTANT keys must be data1, data2, etc in the multiline function in the component
|
||||
// for (let i = 1; i <= Object.keys(cableData).length; i++) {
|
||||
// let gc = "graphComponent" + i;
|
||||
// if (graphProps[gc]) {
|
||||
// graphProps[gc].data = cableData["data" + i];
|
||||
// graphProps[gc].type = GraphType.MULTILINE;
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// measurements.forEach((reading: pond.Measurement, readIndex) => {
|
||||
// if (notNull(reading) && notNull(reading.timestamp) && notNull(reading.measurement)) {
|
||||
// let date = new Date(Date.parse(reading.timestamp));
|
||||
// for (let index = 0; index < ext.measurements.length; index++) {
|
||||
// let componentMeasurement: ComponentMeasurement = ext.measurements[index];
|
||||
// if (componentMeasurement.isErrorMeasurement(reading.measurement)) {
|
||||
// break;
|
||||
// }
|
||||
// let dataPoint = null;
|
||||
// switch (componentMeasurement.graphType) {
|
||||
// case GraphType.AREA:
|
||||
// let avg = componentMeasurement.extract(
|
||||
// or(reading.measurement, {} as quack.Measurement),
|
||||
// filters
|
||||
// );
|
||||
// if (avg && avg.low !== null && avg.high !== null) {
|
||||
// dataPoint = {
|
||||
// x: date,
|
||||
// y: avg.low,
|
||||
// y0: avg.high
|
||||
// } as GraphPoint;
|
||||
// }
|
||||
// break;
|
||||
// case GraphType.SCATTER:
|
||||
// let scatter = componentMeasurement.extract(
|
||||
// or(reading.measurement, {} as quack.Measurement),
|
||||
// filters
|
||||
// );
|
||||
// if (scatter && scatter.value !== undefined && scatter.value !== null) {
|
||||
// dataPoint = {
|
||||
// x: date,
|
||||
// y: Number(scatter.value),
|
||||
// bubble: or(scatter.bubble, 0)
|
||||
// } as GraphPoint;
|
||||
// }
|
||||
// break;
|
||||
// case GraphType.RADAR:
|
||||
// if (subtype === quack.AnalogInputSubtype.ANALOG_INPUT_SUBTYPE_WIND_DIRECTION) {
|
||||
// let value = componentMeasurement.extract(
|
||||
// or(reading.measurement, {} as quack.Measurement),
|
||||
// filters
|
||||
// );
|
||||
|
||||
dataPoint = {
|
||||
x: getWindDirection(value).dString,
|
||||
y: getWindDirection(value).direction
|
||||
};
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//linear and bar
|
||||
let value = componentMeasurement.extract(
|
||||
or(reading.measurement, {} as quack.Measurement),
|
||||
filters
|
||||
);
|
||||
// dataPoint = {
|
||||
// x: getWindDirection(value).dString,
|
||||
// y: getWindDirection(value).direction
|
||||
// };
|
||||
// }
|
||||
// break;
|
||||
// default:
|
||||
// //linear and bar
|
||||
// let value = componentMeasurement.extract(
|
||||
// or(reading.measurement, {} as quack.Measurement),
|
||||
// filters
|
||||
// );
|
||||
|
||||
if (value !== undefined && value !== null) {
|
||||
if (componentType === quack.ComponentType.COMPONENT_TYPE_ANALOG_INPUT) {
|
||||
if (subtype === quack.AnalogInputSubtype.ANALOG_INPUT_SUBTYPE_FUEL) {
|
||||
if (value > 100) {
|
||||
value = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (componentType === quack.ComponentType.COMPONENT_TYPE_EDGE_TRIGGERED) {
|
||||
if (subtype === quack.EdgeTriggeredSubtype.EDGE_TRIGGERED_SUBTYPE_WIND_SPEED) {
|
||||
if (readIndex < measurements.length - 1) {
|
||||
//do math
|
||||
//get the time of both the current reading and the reading before it
|
||||
let currentTime = new Date(
|
||||
Date.parse(measurements[readIndex].timestamp)
|
||||
).valueOf();
|
||||
let prevTime = new Date(
|
||||
Date.parse(measurements[readIndex + 1].timestamp)
|
||||
).valueOf();
|
||||
// if (value !== undefined && value !== null) {
|
||||
// if (componentType === quack.ComponentType.COMPONENT_TYPE_ANALOG_INPUT) {
|
||||
// if (subtype === quack.AnalogInputSubtype.ANALOG_INPUT_SUBTYPE_FUEL) {
|
||||
// if (value > 100) {
|
||||
// value = 0;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (componentType === quack.ComponentType.COMPONENT_TYPE_EDGE_TRIGGERED) {
|
||||
// if (subtype === quack.EdgeTriggeredSubtype.EDGE_TRIGGERED_SUBTYPE_WIND_SPEED) {
|
||||
// if (readIndex < measurements.length - 1) {
|
||||
// //do math
|
||||
// //get the time of both the current reading and the reading before it
|
||||
// let currentTime = new Date(
|
||||
// Date.parse(measurements[readIndex].timestamp)
|
||||
// ).valueOf();
|
||||
// let prevTime = new Date(
|
||||
// Date.parse(measurements[readIndex + 1].timestamp)
|
||||
// ).valueOf();
|
||||
|
||||
//get the difference in seconds between the two
|
||||
let deltaTime = (currentTime - prevTime) / 1000;
|
||||
// //get the difference in seconds between the two
|
||||
// let deltaTime = (currentTime - prevTime) / 1000;
|
||||
|
||||
//divide the ticks by the time between intervals for the average ticks per second and multiply
|
||||
//by 2.4 to convert to km/h
|
||||
value = (Number(value) / deltaTime) * 2.4;
|
||||
} else {
|
||||
value = 0;
|
||||
}
|
||||
}
|
||||
if (subtype === quack.EdgeTriggeredSubtype.EDGE_TRIGGERED_SUBTYPE_RAIN) {
|
||||
value = Math.round(value * 0.2794);
|
||||
}
|
||||
}
|
||||
dataPoint = {
|
||||
x: date,
|
||||
y: Number(value)
|
||||
} as GraphPoint;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (dataPoint !== null) {
|
||||
graphProps["graphComponent" + (index + 1).toString()].data.push(dataPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return graphProps;
|
||||
}
|
||||
// //divide the ticks by the time between intervals for the average ticks per second and multiply
|
||||
// //by 2.4 to convert to km/h
|
||||
// value = (Number(value) / deltaTime) * 2.4;
|
||||
// } else {
|
||||
// value = 0;
|
||||
// }
|
||||
// }
|
||||
// if (subtype === quack.EdgeTriggeredSubtype.EDGE_TRIGGERED_SUBTYPE_RAIN) {
|
||||
// value = Math.round(value * 0.2794);
|
||||
// }
|
||||
// }
|
||||
// dataPoint = {
|
||||
// x: date,
|
||||
// y: Number(value)
|
||||
// } as GraphPoint;
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
// if (dataPoint !== null) {
|
||||
// graphProps["graphComponent" + (index + 1).toString()].data.push(dataPoint);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// return graphProps;
|
||||
// }
|
||||
|
||||
function getWindDirection(value: number) {
|
||||
//determine the general direction based on the value
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import GrainCableLightIcon from "assets/components/grainCableLight.png";
|
|||
import TemperatureHumidityDarkIcon from "assets/components/temperatureHumidityDark.png";
|
||||
import TemperatureHumidityLightIcon from "assets/components/temperatureHumidityLight.png";
|
||||
import { ExtractMoisture, grainName } from "grain";
|
||||
import { GraphPoint } from "common/Graph";
|
||||
import moment from "moment";
|
||||
//import { GraphPoint } from "common/Graph";
|
||||
//import moment from "moment";
|
||||
import {
|
||||
AreaChartData,
|
||||
ComponentMeasurement,
|
||||
|
|
@ -418,38 +418,38 @@ export function binSplitAt(filters?: GraphFilters): number {
|
|||
}
|
||||
|
||||
//TODO: deprecated function with new measurements
|
||||
export function multilineGrainCableData(
|
||||
measurements: Array<pond.Measurement>,
|
||||
filters?: GraphFilters
|
||||
) {
|
||||
let temperature: Array<Array<GraphPoint>> = [];
|
||||
let humidity: Array<Array<GraphPoint>> = []; //humidity is not being used by the graphs
|
||||
let moisture: Array<Array<GraphPoint>> = [];
|
||||
measurements.forEach((measurement: pond.Measurement, i) => {
|
||||
let nodes = extractNodes(measurement.measurement);
|
||||
let selectedNodes = filters ? or(filters.selectedNodes, []) : [];
|
||||
for (let j = 0; j < selectedNodes.length; j++) {
|
||||
if (i === 0) {
|
||||
temperature[j] = [];
|
||||
humidity[j] = [];
|
||||
moisture[j] = [];
|
||||
}
|
||||
let nodeIndex = selectedNodes[j];
|
||||
if (nodeIndex < nodes.length) {
|
||||
let node = nodes[nodeIndex];
|
||||
let ts = moment(measurement.timestamp);
|
||||
temperature[j].push({ x: ts, y: node.temperature });
|
||||
humidity[j].push({ x: ts, y: node.humidity });
|
||||
let grain =
|
||||
isBinSplit(filters) && nodeIndex >= binSplitAt(filters)
|
||||
? pond.Grain.GRAIN_NONE
|
||||
: or(filters, { grainType: pond.Grain.GRAIN_NONE }).grainType;
|
||||
moisture[j].push({
|
||||
x: ts,
|
||||
y: ExtractMoisture(grain, node.temperature, node.humidity)
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return { data1: temperature, data2: moisture, data3: humidity };
|
||||
}
|
||||
// export function multilineGrainCableData(
|
||||
// measurements: Array<pond.Measurement>,
|
||||
// filters?: GraphFilters
|
||||
// ) {
|
||||
// let temperature: Array<Array<GraphPoint>> = [];
|
||||
// let humidity: Array<Array<GraphPoint>> = []; //humidity is not being used by the graphs
|
||||
// let moisture: Array<Array<GraphPoint>> = [];
|
||||
// measurements.forEach((measurement: pond.Measurement, i) => {
|
||||
// let nodes = extractNodes(measurement.measurement);
|
||||
// let selectedNodes = filters ? or(filters.selectedNodes, []) : [];
|
||||
// for (let j = 0; j < selectedNodes.length; j++) {
|
||||
// if (i === 0) {
|
||||
// temperature[j] = [];
|
||||
// humidity[j] = [];
|
||||
// moisture[j] = [];
|
||||
// }
|
||||
// let nodeIndex = selectedNodes[j];
|
||||
// if (nodeIndex < nodes.length) {
|
||||
// let node = nodes[nodeIndex];
|
||||
// let ts = moment(measurement.timestamp);
|
||||
// temperature[j].push({ x: ts, y: node.temperature });
|
||||
// humidity[j].push({ x: ts, y: node.humidity });
|
||||
// let grain =
|
||||
// isBinSplit(filters) && nodeIndex >= binSplitAt(filters)
|
||||
// ? pond.Grain.GRAIN_NONE
|
||||
// : or(filters, { grainType: pond.Grain.GRAIN_NONE }).grainType;
|
||||
// moisture[j].push({
|
||||
// x: ts,
|
||||
// y: ExtractMoisture(grain, node.temperature, node.humidity)
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// return { data1: temperature, data2: moisture, data3: humidity };
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -110,6 +110,10 @@ export class MeasurementDescriber {
|
|||
}
|
||||
if (componentType === quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE) {
|
||||
this.details.graph = GraphType.AREA;
|
||||
if(componentSubtype === quack.GrainCableSubtype.GRAIN_CABLE_SUBTYPE_OPI_DIAG){
|
||||
this.details.label = "Cable ID"
|
||||
this.details.unit = ""
|
||||
}
|
||||
}
|
||||
if (componentType === quack.ComponentType.COMPONENT_TYPE_VAPOUR_PRESSURE_DEFICIT) {
|
||||
this.details.path = "vpd.celciusTimes10";
|
||||
|
|
@ -194,6 +198,10 @@ export class MeasurementDescriber {
|
|||
if (componentType === quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE) {
|
||||
this.details.label = "Humidity";
|
||||
this.details.graph = GraphType.AREA;
|
||||
if(componentSubtype === quack.GrainCableSubtype.GRAIN_CABLE_SUBTYPE_OPI_DIAG){
|
||||
this.details.label = "Cable Type"
|
||||
this.details.unit = ""
|
||||
}
|
||||
// can be used for testing node splitting on a cable if you dont have a component that uses it
|
||||
// this.details.nodeDetails = {
|
||||
// colours: ["white", "black"],
|
||||
|
|
|
|||
|
|
@ -126,6 +126,10 @@ export interface IBinAPIContext {
|
|||
showErrors?: boolean,
|
||||
otherTeam?: string
|
||||
) => Promise<AxiosResponse<pond.ListObjectMeasurementsResponse>>;
|
||||
getBinsTrendData: (
|
||||
bins: string[],
|
||||
days: number
|
||||
) => Promise<AxiosResponse<pond.GetBinsTrendDataResponse>>;
|
||||
}
|
||||
|
||||
export const BinAPIContext = createContext<IBinAPIContext>({} as IBinAPIContext);
|
||||
|
|
@ -629,6 +633,12 @@ export default function BinProvider(props: PropsWithChildren<Props>) {
|
|||
})
|
||||
};
|
||||
|
||||
const getBinsTrendData = (bins: string[], days: number) => {
|
||||
return get<pond.GetBinsTrendDataResponse>(
|
||||
pondURL("/binTrends?bins=" + bins.toString() + "&days=" + days + (as ? "&as=" + as : ""))
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<BinAPIContext.Provider
|
||||
value={{
|
||||
|
|
@ -655,7 +665,8 @@ export default function BinProvider(props: PropsWithChildren<Props>) {
|
|||
listHistoryBetween,
|
||||
listBinPrefs,
|
||||
updateTopNodes,
|
||||
listBinMeasurements
|
||||
listBinMeasurements,
|
||||
getBinsTrendData
|
||||
}}>
|
||||
{children}
|
||||
</BinAPIContext.Provider>
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ export default function GroupProvider(props: PropsWithChildren<Props>) {
|
|||
|
||||
const addDevice = (group: number, device: number) => {
|
||||
let url = "/groups/" + group + "/devices/" + device + "/add";
|
||||
if (as) url = pondURL(url + as)
|
||||
if (as) url = url + "?as=" + as
|
||||
return new Promise<AxiosResponse>((resolve, reject) => {
|
||||
post(pondURL(url), group).then(resp => {
|
||||
return resolve(resp)
|
||||
|
|
@ -100,7 +100,7 @@ export default function GroupProvider(props: PropsWithChildren<Props>) {
|
|||
|
||||
const removeDevice = (group: number, device: number) => {
|
||||
let url = "/groups/" + group + "/devices/" + device + "/remove";
|
||||
if (as) url = pondURL(url + as)
|
||||
if (as) url = url + "?as=" + as
|
||||
return new Promise<AxiosResponse>((resolve, reject) => {
|
||||
post(pondURL(url), group).then(resp => {
|
||||
return resolve(resp)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue