diff --git a/package-lock.json b/package-lock.json
index abf6c85..0e25c26 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#master",
+ "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",
@@ -10953,7 +10953,7 @@
},
"node_modules/protobuf-ts": {
"version": "1.0.0",
- "resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#c08965a296f2cd0799472fd8b163186cf6885d4c",
+ "resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#3f647071f211c4552c2acc23a8ecabb6904a4156",
"dependencies": {
"protobufjs": "^6.8.8"
}
diff --git a/package.json b/package.json
index ee0e9b7..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#master",
+ "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",
diff --git a/src/bin/BinTour.tsx b/src/bin/BinTour.tsx
index a685ada..e885527 100644
--- a/src/bin/BinTour.tsx
+++ b/src/bin/BinTour.tsx
@@ -1,6 +1,6 @@
// import { useAuth0 } from "@auth0/auth0-react";
import { Typography } from "@mui/material";
-import Tour from "common/Tour";
+import Tour, { TourStep } from "common/Tour";
import { random } from "lodash";
import moment from "moment";
import { useGlobalState, useSnackbar, useUserAPI } from "providers";
@@ -8,8 +8,13 @@ import React, { useEffect, useState } from "react";
import { Step } from "react-joyride";
// import Emoji from "react-emoji-render";
-export default function BinTour() {
+interface Props {
+ setDetailTabState?: ( detail: "inventory" | "sensors" | "analytics" | "presets" | "alerts" | "transactions", buttonIndex: number) => void
+}
+
+export default function BinTour(props: Props) {
// const { userID } = useAuth0();
+ const {setDetailTabState} = props
const [{ user }, dispatch] = useGlobalState();
const userID = user.id()
const { error } = useSnackbar();
@@ -35,8 +40,8 @@ export default function BinTour() {
}
};
- const getTourSteps = (): Step[] => {
- let steps: Step[] = [
+ const getTourSteps = (): TourStep[] => {
+ let steps: TourStep[] = [
{
title: (
@@ -103,24 +108,12 @@ export default function BinTour() {
disableBeacon: false
},
{
- title: "Graphs",
+ title: "View Other Data",
content: (
- Bin related analytics are displayed here.
-
-
- ),
- target: "#tour-graphs",
- placement: "left",
- disableBeacon: false
- },
- {
- title: "Choose your graphs",
- content: (
-
-
- Use this tab to view other sets of data. Sensors must be attached to view sensor data.
+ Use these tabs to view other Bin Details such as inventory levels over time,
+ alerts and interactions for connected components, and data for attached sensors
),
@@ -128,6 +121,122 @@ export default function BinTour() {
placement: "bottom",
disableBeacon: false
},
+ {
+ title: "Inventory",
+ content: (
+
+
+ The inventory tab shows your bins inventory level over a specified window as well as the times the bin mode was changed.
+
+
+ ),
+ target: "#tour-details",
+ placement: "left-start",
+ disableBeacon: false,
+ onNext: () => {
+ if (setDetailTabState) setDetailTabState("sensors", 1)
+ }
+ },
+ {
+ title: "Sensors",
+ content: (
+
+
+ The sensors tab shows readings from attached sensors over time
+
+
+ ),
+ target: "#tour-details",
+ placement: "left-start",
+ disableBeacon: false,
+ onNext: () => {
+ if (setDetailTabState) setDetailTabState("analytics", 2)
+ }
+ },
+ {
+ title: "Analytics",
+ content: (
+
+
+ The analysis tab shows analytic bin data using attached sensors
+
+
+ ),
+ target: "#tour-details",
+ placement: "left-start",
+ disableBeacon: false,
+ onNext: () => {
+ if (setDetailTabState) setDetailTabState("alerts", 3)
+ }
+ },
+ {
+ title: "Alerts and Interactions",
+ content: (
+
+
+ The Alerts tab allows you to view or add any new interactions or alerts for connected components
+ and displays recent notifications from those alerts
+
+
+ ),
+ target: "#tour-details",
+ placement: "left-start",
+ disableBeacon: false,
+ onNext: () => {
+ if (setDetailTabState) setDetailTabState("presets", 4)
+ }
+ },
+ {
+ title: "Bin Mode Presets",
+ content: (
+
+
+ The Presets tab allows you to create custom presets for the interactions for a device when changing bin modes
+
+
+ ),
+ target: "#tour-details",
+ placement: "left-start",
+ disableBeacon: false,
+ onNext: () => {
+ if (setDetailTabState) setDetailTabState("transactions", 5)
+ }
+ },
+ {
+ title: "Bin Transactions",
+ content: (
+
+
+ The transactions tab allows view any pending transaction when using a hybrid inventory control
+
+
+ ),
+ target: "#tour-details",
+ placement: "left-start",
+ disableBeacon: false,
+ onNext: () => {
+ if (setDetailTabState) setDetailTabState("inventory", 0)
+ }
+ },
+ {
+ title: "Bin Conditions",
+ content: (
+
+
+ This section will display conditions based on the bin mode
+
+
+ Storage Mode: simply displays the Storage conditions by itself with the target temperature and moisture set in the bin settings
+
+
+ Other Modes: will display the interactions for the bins devices that are controlling a fan or heater on the bin as well as the storage conditions
+
+
+ ),
+ target: "#tour-conditions",
+ placement: "right",
+ disableBeacon: false
+ },
{
title: "Change Mode",
content: (
@@ -138,12 +247,15 @@ export default function BinTour() {
Storage mode: default
- Drying mode: use heat to dry grain ☀️
+ Cooldown mode: use fans to hold bin temperature lower ❆❅
+ {/* */}
+
+
+ Drying mode: use heat to dry grain ☀️ (only visible when the target moisture is lower than the starting moisture in the bin settings)
{/* */}
- Cooldown mode: use fans to hold bin temperature lower ❆❅
- {/* */}
+ Hydrating mode: use humid air to hydrate grain (only visible when the target moisture is higher than the starting moisture in the bin settings)
diff --git a/src/bin/BinVisualizerV2.tsx b/src/bin/BinVisualizerV2.tsx
index 5b3dc62..9036b91 100644
--- a/src/bin/BinVisualizerV2.tsx
+++ b/src/bin/BinVisualizerV2.tsx
@@ -1727,32 +1727,34 @@ export default function BinVisualizer(props: Props) {
{modeChangeInProgress &&
}
- {
- setModeStorage()
+
+ {
+ setModeStorage()
+ }
+ },
+ {
+ title: "Cooldown",
+ function: () => {
+ setModeCooldown()
+ }
+ },
+ {
+ title: bin.settings.inventory && bin.settings.inventory?.initialMoisture < bin.settings.inventory?.targetMoisture ? "Hydrating" : "Drying",
+ function: () => {
+ // setShowInputMoisture(true)
+ setModeConditioning() //will set it to either drying or hydrating based on the initial and target moisture
+ }
}
- },
- {
- title: "Cooldown",
- function: () => {
- setModeCooldown()
- }
- },
- {
- title: bin.settings.inventory && bin.settings.inventory?.initialMoisture < bin.settings.inventory?.targetMoisture ? "Hydrating" : "Drying",
- function: () => {
- // setShowInputMoisture(true)
- setModeConditioning() //will set it to either drying or hydrating based on the initial and target moisture
- }
- }
- ]}
- toggledButtons={determineToggle(mode)}
- toggle
- />
+ ]}
+ toggledButtons={determineToggle(mode)}
+ toggle
+ />
+
);
};
diff --git a/src/bin/BinsList.tsx b/src/bin/BinsList.tsx
index 483df50..ad7ae64 100644
--- a/src/bin/BinsList.tsx
+++ b/src/bin/BinsList.tsx
@@ -23,6 +23,12 @@ interface Props {
//startingTranslate: number;
valDisplay?: "high" | "low" | "average";
insert?: boolean
+ /**
+ * optional function for when you want clicking the card to do something other than navigate to the bin page
+ * @param bin the bin model for the card that was clicked
+ * @returns void
+ */
+ cardClickFunction?: (bin: Bin) => void
}
const useStyles = makeStyles((_theme) => {
@@ -40,7 +46,7 @@ const useStyles = makeStyles((_theme) => {
});
export default function BinsList(props: Props) {
- const { bins, duplicateBin, title, gridView, loadMore, valDisplay, insert } = props;
+ const { bins, duplicateBin, title, gridView, loadMore, valDisplay, insert, cardClickFunction } = props;
const classes = useStyles();
// const history = useHistory();
const navigate = useNavigate()
@@ -53,6 +59,14 @@ export default function BinsList(props: Props) {
navigate(path, { state: {bin: bins[i]} });
};
+ const cardClicked = (index: number) => {
+ if(cardClickFunction) {
+ cardClickFunction(bins[index])
+ }else{
+ goToBin(index)
+ }
+ }
+
const leftArrow = () => {
const visibility = useContext(VisibilityContext);
//const isFirstVisible = visibility.useIsVisible('first', false)
@@ -95,7 +109,7 @@ export default function BinsList(props: Props) {
key={i}
className={classes.gridListTile}
onClick={() => {
- !duplicate && goToBin(i)
+ !duplicate && cardClicked(i)
}}>
{
- !duplicate && goToBin(i)
+ !duplicate && cardClicked(i)
}}>
void
}
const useStyles = makeStyles((theme: Theme) => ({
@@ -82,7 +87,7 @@ const useStyles = makeStyles((theme: Theme) => ({
}));
export default function BinyardDisplay(props: Props) {
- const { yardKey, insert } = props;
+ const { yardKey, insert, binClicked } = props;
const classes = useStyles();
const binAPI = useBinAPI();
const theme = useTheme();
@@ -321,6 +326,7 @@ export default function BinyardDisplay(props: Props) {
bins={grainBins}
duplicateBin={duplicateBin}
title={"Grain Bins"}
+ cardClickFunction={binClicked}
/>
@@ -338,6 +344,7 @@ export default function BinyardDisplay(props: Props) {
bins={fertBins}
duplicateBin={duplicateBin}
title={"Fertilizer Bins"}
+ cardClickFunction={binClicked}
/>
@@ -355,6 +362,7 @@ export default function BinyardDisplay(props: Props) {
bins={emptyBins}
duplicateBin={duplicateBin}
title={"Empty Bins"}
+ cardClickFunction={binClicked}
// loadMore={newTranslation => {
// //only triggered in the scroll view so this will never trigger in grid view
// if (yardBins.length < binTotal) {
diff --git a/src/common/ButtonGroup.tsx b/src/common/ButtonGroup.tsx
index 3c2c64c..e326d64 100644
--- a/src/common/ButtonGroup.tsx
+++ b/src/common/ButtonGroup.tsx
@@ -57,6 +57,7 @@ interface Props {
* When true will disable all of the buttons in the group, will be overridded by individual buttons disabled state in the button data
*/
disableAll?: boolean
+
}
const useStyles = makeStyles((theme: Theme) => {
diff --git a/src/device/DeviceWizard.tsx b/src/device/DeviceWizard.tsx
index 32387eb..3bb7fb9 100644
--- a/src/device/DeviceWizard.tsx
+++ b/src/device/DeviceWizard.tsx
@@ -141,6 +141,28 @@ export default function DeviceWizard(props: Props) {
)}
+ {selectedPort &&
+ selectedPort.addressType === quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY &&
+ device.featureSupported("detectOneWire") &&
+ selectedPort.autoDetectable && (
+
+
+
+ )}
{portComponents.length > 0 && (
Current Components
@@ -204,7 +226,6 @@ export default function DeviceWizard(props: Props) {
*/
const adjustAvailablePositions = (port: PortInformation, availability: DeviceAvailabilityMap) => {
let currentAvailability = availability;
- console.log(port)
switch (port.addressType) {
case quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY:
currentAvailability.set(port.addressType, [{ address: port.address, label: port.label }]);
diff --git a/src/device/autoDetect/DeviceScannedComponents.tsx b/src/device/autoDetect/DeviceScannedComponents.tsx
index 0381281..2be89a9 100644
--- a/src/device/autoDetect/DeviceScannedComponents.tsx
+++ b/src/device/autoDetect/DeviceScannedComponents.tsx
@@ -7,9 +7,11 @@ import { useEffect, useState } from "react";
import ScannedI2C from "./ScannedI2C";
import ComponentForm from "component/ComponentForm";
import { Component, Device } from "models";
-import { DeviceAvailabilityMap, OffsetAvailabilityMap } from "pbHelpers/DeviceAvailability";
+import { DeviceAvailabilityMap, FindAvailablePositions, OffsetAvailabilityMap } from "pbHelpers/DeviceAvailability";
import ResponsiveDialog from "common/ResponsiveDialog";
import { useComponentAPI, useDeviceAPI, useSnackbar } from "hooks";
+import { ConfigurablePin } from "pbHelpers/AddressTypes";
+import ScannedOneWirePort from "./OneWire/ScannedOneWirePort";
interface Props {
scannedComponents: pond.ComponentAddressMap
@@ -31,17 +33,19 @@ export default function DeviceScannedComponents(props: Props){
const compAPI = useComponentAPI();
const deviceAPI = useDeviceAPI()
const [scannedI2C, setScannedI2C] = useState() //the unmodified scan of addresses
- const [validCompAddresses, setValidComponentAddresses] = useState([]) //the filtered array of address data
+ const [scannedOneWire, setScannedOneWire] = useState([])
+ const [validI2CCompAddresses, setValidI2CComponentAddresses] = useState([]) //the filtered array of address data
const [components, setComponents] = useState([])
const [steps, setSteps] = useState([]);
const { error, success } = useSnackbar();
const [currentStep, setCurrentStep] = useState(0)
const [settingsValid, setSettingsValid] = useState(false);
const [openDialog, setOpenDialog] = useState(false);
+ const [clearOpen, setClearOpen] = useState(false);
useEffect(()=>{
- //console.log(scannedComponents)
if (scannedComponents.i2c) setScannedI2C(scannedComponents.i2c)
+ if (scannedComponents.oneWire) setScannedOneWire(scannedComponents.oneWire)
//makes the array empty for testing
// if (scannedComponents.i2c) {
// let clone = cloneDeep(scannedComponents.i2c)
@@ -76,7 +80,7 @@ export default function DeviceScannedComponents(props: Props){
}
})
}
- setValidComponentAddresses(valid)
+ setValidI2CComponentAddresses(valid)
},[scannedI2C])
const stepper = () => {
@@ -200,11 +204,12 @@ export default function DeviceScannedComponents(props: Props){
})
})
}
+ console.log(cloneList)
setComponents(cloneList)
}
- const removeScan = (key: string) => {
- deviceAPI.removeFoundComponents(device.settings.deviceId, key)
+ const removeScan = (key: string, type: pond.ObjectType) => {
+ deviceAPI.removeFoundComponents(device.settings.deviceId, key, type)
.then(resp => {
console.log("Cleared this scan")
}).catch(err => {
@@ -212,20 +217,51 @@ export default function DeviceScannedComponents(props: Props){
})
}
+ const removeAllScans = () => {
+ deviceAPI.removeAllFoundComponents(device.settings.deviceId)
+ .then(resp => {
+ console.log("Cleared all scans")
+ refreshCallback()
+ }).catch(err => {
+ console.log("There was a problem clearing scans")
+ })
+ }
+
+ const clearWarning = () => {
+ return (
+ {setClearOpen(false)}}>
+ Clear All Scans
+ This action will clear all scans for this device.
+
+
+
+
+
+ )
+ }
+
return (
+ {clearWarning()}
+
+ Sensor Scan
+
+
{scannedI2C !== undefined &&
-
+
I2C Sensors
-
+
- {validCompAddresses.length > 0 ? validCompAddresses.map((addr, index) => {
+ {validI2CCompAddresses.length > 0 ? validI2CCompAddresses.map((addr, index) => {
return (
()}/>
)
@@ -240,7 +276,39 @@ export default function DeviceScannedComponents(props: Props){
}
-
+
+ }
+ {scannedOneWire.length > 0 &&
+
+
+
+ Pin Port Sensors
+
+
+ {scannedOneWire.map((scan,i) => {
+ let map = FindAvailablePositions([], device.settings.product).availability.get(quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY)
+ let portAddress = scan.settings?.oneWireData?.port
+ let portLabel = ""
+
+ map?.forEach(entry => {
+ let pin = entry as ConfigurablePin
+ if (pin.address && pin.address === portAddress) {
+ portLabel = pin.label
+ }
+ })
+ return(
+
+
+ Port: {portLabel}
+
+
+
+
+ )
+ })}
+
}
diff --git a/src/device/autoDetect/OneWire/PortComponent.tsx b/src/device/autoDetect/OneWire/PortComponent.tsx
new file mode 100644
index 0000000..b1e26e1
--- /dev/null
+++ b/src/device/autoDetect/OneWire/PortComponent.tsx
@@ -0,0 +1,150 @@
+import { Box, Checkbox, Grid2, MenuItem, TextField, Tooltip, Typography } from "@mui/material"
+import { useMobile } from "hooks"
+import { getFriendlyName, getSubtypes, Subtype } from "pbHelpers/ComponentType"
+import { quack } from "protobuf-ts/quack"
+import React, { useEffect, useState } from "react"
+
+interface Props {
+ compData: quack.OneWireComponentData
+ componentSelect: (selected: boolean, componentData: quack.OneWireComponentData) => void
+}
+
+export default function PortComponent(props: Props){
+ const {compData, componentSelect} = props
+ // const [selectedSubtype, setSelectedSubtype] = useState(0)
+ const [subtypeVal, setSubtypeVal] = useState("no subtype")//note that this is the friendly name and not the key or the value because it needs to be different from the other alias options
+ const [subtypeMap, setSubtypeMap] = useState
-
-
-
+
+ setDetail("inventory")
+ function: () => {
+ setDetail("inventory")
+ setActiveDetails([0])
+ }
},
{
title: "Sensors",
- function: () => setDetail("sensors")
+ function: () => {
+ setDetail("sensors")
+ setActiveDetails([1])
+ }
},
{
title: "Analysis",
- function: () => setDetail("analytics")
+ function: () => {
+ setDetail("analytics")
+ setActiveDetails([2])
+ }
},
{
title: "Alerts",
- function: () => setDetail("alerts")
+ function: () => {
+ setDetail("alerts")
+ setActiveDetails([3])
+ }
},
{
title: "Presets",
- function: () => setDetail("presets")
+ function: () => {
+ setDetail("presets")
+ setActiveDetails([4])
+ }
},
{
title: "Transactions",
- function: () => setDetail("transactions")
+ function: () => {
+ setDetail("transactions")
+ setActiveDetails([5])
+ }
}
]}
/>
- {/*
- setDetail("inventory")}>
- Inventory
-
- setDetail("sensors")}
- value={"sensors"}
- aria-label="Bin Sensor Graphs">
- Sensors
-
- setDetail("analytics")}
- value={"analytics"}
- aria-label="Bin Analysis Graphs">
- Analysis
-
- setDetail("alerts")}
- value={"alerts"}
- aria-label="Device Alerts">
- Alerts
-
- setDetail("presets")}
- value={"presets"}
- aria-label="Bin Mode Presets">
- Presets
-
- */}
{detail === "alerts" && (
-
)}
@@ -916,23 +900,27 @@ export default function Bin(props: Props) {
/>
)}
- {(detail === "inventory" || detail === "sensors" || detail === "analytics") && (
-
- )}
{detail === "transactions" &&
+
+
}
+ {(detail === "inventory" || detail === "sensors" || detail === "analytics") && (
+
+
+
+ )}
@@ -1033,11 +1021,13 @@ export default function Bin(props: Props) {
-
@@ -1175,7 +1165,11 @@ export default function Bin(props: Props) {
{objectTeams()}
{deviceMenu()}
-
+ {
+ setDetail(detail)
+ setActiveDetails([buttonIndex])
+ }}/>
);
}
diff --git a/src/pages/Device.tsx b/src/pages/Device.tsx
index 9195c3d..ee4ae56 100644
--- a/src/pages/Device.tsx
+++ b/src/pages/Device.tsx
@@ -1,4 +1,4 @@
-import { Button, Card, Divider, List, ListItem, Typography } from "@mui/material";
+import { Box, Button, Card, Divider, List, ListItem, Typography } from "@mui/material";
import Grid from '@mui/material/Grid2';
import { Component, Device, Interaction, User } from "models";
import { getContextKeys, getContextTypes } from "pbHelpers/Context";
@@ -169,8 +169,8 @@ export default function DevicePage() {
const loadPortScan = () => {
deviceAPI.listFoundComponents(parseInt(deviceID))
.then(resp => {
- if (resp.data.foundComponents?.i2c){
- setScannedAddresses(resp.data.foundComponents ?? undefined)
+ if (resp.data.foundComponents?.i2c || resp.data.foundComponents?.oneWire){
+ setScannedAddresses(pond.ListFoundComponentsResponse.fromObject(resp.data).foundComponents ?? undefined)
}
})
.catch(err => {
@@ -411,7 +411,16 @@ export default function DevicePage() {
/>
{/* add grid card here for I2C detected components */}
-
+ {(scannedAddresses?.i2c || scannedAddresses?.oneWire) &&
+
+
+
+ }
{diagnosticComponents.map(comp => (
- {scannedAddresses &&
-
+ {(scannedAddresses?.i2c || scannedAddresses?.oneWire) &&
+ (globalState.user);
useEffect(() => {
setLoading(true)
@@ -55,6 +58,124 @@ export default function SignupCallback () {
return loading === false && doneBins && doneTeams && doneDevices
}
+ const changePressureUnit = (value: any) => {
+ let updatedUser = User.clone(user)
+ let pressureUnit: pond.PressureUnit;
+ switch (value) {
+ case 1:
+ pressureUnit = pond.PressureUnit.PRESSURE_UNIT_KILOPASCALS;
+ break;
+ case 2:
+ pressureUnit = pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER;
+ break;
+ default:
+ pressureUnit = pond.PressureUnit.PRESSURE_UNIT_UNKNOWN;
+ break;
+ }
+ updatedUser.settings.pressureUnit = pressureUnit;
+ setUser(updatedUser)
+ };
+
+ const changeTemperatureUnit = (value: any) => {
+ let updatedUser = User.clone(user);
+ let temperatureUnit: pond.TemperatureUnit;
+ switch (value) {
+ case 1:
+ temperatureUnit = pond.TemperatureUnit.TEMPERATURE_UNIT_CELSIUS;
+ break;
+ case 2:
+ temperatureUnit = pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT;
+ break;
+ default:
+ temperatureUnit = pond.TemperatureUnit.TEMPERATURE_UNIT_UNKNOWN;
+ break;
+ }
+ updatedUser.settings.temperatureUnit = temperatureUnit;
+ setUser(updatedUser);
+ };
+
+ const unitPreferences = () => {
+ const { pressureUnit, temperatureUnit, distanceUnit, grainUnit } = user.settings;
+ return (
+
+
+ changePressureUnit(event.target.value)}
+ margin="normal"
+ variant="outlined"
+ InputLabelProps={{ shrink: true }}>
+
+
+
+
+
+ changeTemperatureUnit(event.target.value)}
+ margin="normal"
+ variant="outlined"
+ InputLabelProps={{ shrink: true }}>
+
+
+
+
+
+ changeDistanceUnit(event.target.value)}
+ margin="normal"
+ variant="outlined"
+ InputLabelProps={{ shrink: true }}>
+
+
+
+
+ {IsAdaptiveAgriculture() && (
+
+ changeGrainUnit(event.target.value)}
+ margin="normal"
+ variant="outlined"
+ InputLabelProps={{ shrink: true }}>
+
+
+
+
+ )}
+
+ );
+ };
+
const content = () => {
return (
@@ -104,12 +225,17 @@ export default function SignupCallback () {
content: (
<>
- In the user menu, you can make changes to your profile, and adjust unit preferences.
+ In the user menu, you can make changes to your profile, such as adjusting unit preferences.
If you are part of a team, you can select it here as well.
+
+
+ Set your unit preferences here now, they can be changed later from this menu:
+
+ {unitPreferences()}
>
),
target: "#tour-user-menu",
@@ -150,35 +276,104 @@ export default function SignupCallback () {
target: "#tour-dashboard",
placement: "right"
})
- if (IsAdaptiveAgriculture()) steps.push({
- title: "Bins",
+ steps.push({
+ title: "Tasks",
content: (
<>
- You can view your bins and their inventory here.
+ You can view and create tasks here and assign a start and end time for them.
- If you are viewing as a team, your team's bins will be displayed here instead.
+ If you are viewing as a team you will see the teams tasks, you can even assign tasks to team members.
>
),
- target: "#tour-bins",
- placement: "right",
- disableBeacon: true,
+ target: "#tour-tasks",
+ placement: "right"
})
+ //tasks step
+ if (IsAdaptiveAgriculture()) {
+ steps.push({
+ title: "Visual Farm",
+ content: (
+ <>
+
+ You can view your Visual Farm here, it will allow tou to draw fields and plot bins an a map.
+
+
+
+ If you are viewing as a team, your team's fields and bins will be displayed here instead.
+
+ >
+ ),
+ target: "#tour-visual-farm",
+ placement: "right",
+ disableBeacon: true,
+ })
+ steps.push({
+ title: "Fields",
+ content: (
+ <>
+
+ You can view your fields you have drawn on the map here.
+
+
+
+ If you are viewing as a team, your team's fields will be displayed here instead.
+
+ >
+ ),
+ target: "#tour-field-list",
+ placement: "right",
+ disableBeacon: true,
+ })
+ steps.push({
+ title: "Bins",
+ content: (
+ <>
+
+ You can view your bins and their inventory here.
+
+
+
+ If you are viewing as a team, your team's bins will be displayed here instead.
+
+ >
+ ),
+ target: "#tour-bins",
+ placement: "right",
+ disableBeacon: true,
+ })
+ steps.push({
+ title: "Contracts",
+ content: (
+ <>
+
+ You can view and track any contracts you have created here.
+
+
+
+ If you are viewing as a team, your team's contracts will be displayed here instead.
+
+ >
+ ),
+ target: "#tour-contracts",
+ placement: "right",
+ disableBeacon: true,
+ })
+ }
return steps;
};
const endTour = () => {
setIsTourRunning(false);
- // if (user) {
- // user.status.finishedBinIntro = moment().toJSON();
- // userAPI
- // .updateUser(userID, user.protobuf())
- // .then(() => dispatch({ key: "user", value: user }))
- // .catch((err: any) => error(err));
- // }
+ if (user) {
+ userAPI
+ .updateUser(user.id(), user.protobuf())
+ .then(() => dispatch({ key: "user", value: user }))
+ .catch((err: any) => console.error(err));
+ }
};
const closeDialog = () => {
diff --git a/src/pbHelpers/ComponentType.tsx b/src/pbHelpers/ComponentType.tsx
index 60f14cd..03be638 100644
--- a/src/pbHelpers/ComponentType.tsx
+++ b/src/pbHelpers/ComponentType.tsx
@@ -168,6 +168,7 @@ export interface ComponentTypeExtension {
//if the map does not exist then just use the array from the device availability,
//if the map does exist filter the availability after claims to find matching address between them and use that
subtypeI2CMap?: Map
+ isChainable?: boolean
}
export interface Summary {
diff --git a/src/pbHelpers/ComponentTypes/CapacitorCable.ts b/src/pbHelpers/ComponentTypes/CapacitorCable.ts
index cc56e27..8843952 100644
--- a/src/pbHelpers/ComponentTypes/CapacitorCable.ts
+++ b/src/pbHelpers/ComponentTypes/CapacitorCable.ts
@@ -68,6 +68,7 @@ export function CapacitorCable(subtype: number = 0): ComponentTypeExtension {
isSource: true,
isArray: true,
isCalibratable: false,
+ isChainable: true,
addressTypes: addressTypes,
interactionResultTypes: [],
states: [],
diff --git a/src/pbHelpers/ComponentTypes/GrainCable.ts b/src/pbHelpers/ComponentTypes/GrainCable.ts
index c715611..bacc514 100644
--- a/src/pbHelpers/ComponentTypes/GrainCable.ts
+++ b/src/pbHelpers/ComponentTypes/GrainCable.ts
@@ -176,6 +176,7 @@ export function GrainCable(subtype: number = 0): ComponentTypeExtension {
isSource: true,
isArray: true,
isCalibratable: false,
+ isChainable: true,
addressTypes: [quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY, quack.AddressType.ADDRESS_TYPE_I2C],
interactionResultTypes: [],
states: [],
diff --git a/src/pbHelpers/ComponentTypes/PressureCable.ts b/src/pbHelpers/ComponentTypes/PressureCable.ts
index f03cc9e..3a22362 100644
--- a/src/pbHelpers/ComponentTypes/PressureCable.ts
+++ b/src/pbHelpers/ComponentTypes/PressureCable.ts
@@ -64,6 +64,7 @@ export function PressureCable(subtype: number = 0): ComponentTypeExtension {
isArray: true,
hasFan: true,
isCalibratable: false,
+ isChainable: true,
addressTypes: [quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY],
interactionResultTypes: [],
states: [],
diff --git a/src/providers/pond/deviceAPI.tsx b/src/providers/pond/deviceAPI.tsx
index fbaefc0..241781b 100644
--- a/src/providers/pond/deviceAPI.tsx
+++ b/src/providers/pond/deviceAPI.tsx
@@ -23,6 +23,7 @@ export interface IDeviceAPIContext {
) => Promise>;
getMulti: (ids: number[] | string[], otherTeam?: string) => Promise>;
detectI2C: (id: number, otherTeam?: string) => Promise>;
+ detectOneWire: (id: number, port: number, otherTeam?: string) => Promise>
listFoundComponents: (id: number, otherTeam?: string) => Promise>
getGeoJson: (id: number | string, demo?: boolean, otherTeam?: string) => Promise;
getMultiGeoJson: (ids: number[] | string[], otherTeam?: string) => Promise;
@@ -148,7 +149,8 @@ export interface IDeviceAPIContext {
keys?: string[],
types?: string[]
) => Promise;
- removeFoundComponents: (id: number, key: string, otherTeam?: string) => Promise>;
+ removeAllFoundComponents: (id: number,otherTeam?: string) => Promise>;
+ removeFoundComponents: (id: number, key: string, type: pond.ObjectType, otherTeam?: string) => Promise>;
}
export const DeviceAPIContext = createContext({} as IDeviceAPIContext);
@@ -962,6 +964,19 @@ export default function DeviceProvider(props: PropsWithChildren) {
})
}
+ const detectOneWire = (id: number, port: number, otherTeam?: string) => {
+ let url = "/devices/" + id + "/detectOneWire?port=" + port;
+ const view = otherTeam ? otherTeam : as
+ if(view) url = url + "?as=" + view
+ return new Promise>((resolve, reject) => {
+ put(pondURL(url)).then(resp => {
+ return resolve(resp)
+ }).catch(err => {
+ return reject(err)
+ })
+ })
+ }
+
const listFoundComponents = (id: number, otherTeam?: string) => {
let url = "/devices/" + id + "/listScannedComponents";
const view = otherTeam ? otherTeam : as
@@ -975,10 +990,10 @@ export default function DeviceProvider(props: PropsWithChildren) {
})
}
- const removeFoundComponents = (id: number, key: string, otherTeam?: string) => {
- let url = "/devices/" + id + "/removeFoundComponents/" + key;
+ const removeFoundComponents = (id: number, key: string, type: pond.ObjectType, otherTeam?: string) => {
+ let url = "/devices/" + id + "/removeFoundComponents/" + key + "?scanType=" + type;
const view = otherTeam ? otherTeam : as
- if(view) url = url + "?as=" + view
+ if(view) url = url + "&as=" + view
return new Promise>((resolve, reject) => {
del(pondURL(url)).then(resp => {
return resolve(resp)
@@ -988,6 +1003,19 @@ export default function DeviceProvider(props: PropsWithChildren) {
})
}
+ const removeAllFoundComponents = (id: number, otherTeam?: string) => {
+ let url = "/devices/" + id + "/removeAllFoundComponents";
+ const view = otherTeam ? otherTeam : as
+ if(view) url = url + "?as=" + view
+ return new Promise>((resolve, reject) => {
+ del(pondURL(url)).then(resp => {
+ return resolve(resp)
+ }).catch(err => {
+ return reject(err)
+ })
+ })
+ }
+
return (
) {
updateComponentPreferences,
listDeviceComponentPreferences,
detectI2C,
+ detectOneWire,
listFoundComponents,
- removeFoundComponents
+ removeFoundComponents,
+ removeAllFoundComponents
}}>
{children}