Merge branch 'staging_environment' into 3d_bin
1
.env
|
|
@ -14,6 +14,7 @@ VITE_AUTH0_ADAPTIVE_CONSTRUCTION_CLIENT_ID=32rABabJzXRvJiWivTmeKFgwFiqh4ok7
|
|||
VITE_AUTH0_AEROGROW_CLIENT_ID=KHl9ooUt1nia1RYw5n224dyggCXdbsSd
|
||||
VITE_AUTH0_MIVENT_CLIENT_ID=VNALE7RW6l3dY5uYcxgwElZV0lcT25Fg
|
||||
VITE_AUTH0_OMNIAIR_CLIENT_ID=IblmarD8wFafiD6doxTmOHQ6Bx3L9wWl
|
||||
VITE_AUTH0_INTELLIFARMS_CLIENT_ID=RYtuAyOcB4DSaaqJMLDMf3pV8SFY9PdY
|
||||
|
||||
#Branding (Default theme)
|
||||
VITE_APP_WEBSITE_TITLE="Adaptive Dashboard"
|
||||
|
|
|
|||
14
README.md
|
|
@ -18,7 +18,10 @@ Steps to add a new white label
|
|||
- add a `CNAME` record pointing their custom subdomain (ex: dashboard.example.com) to brandxtech.ca
|
||||
- add a login button on their website point to `/login` of their custom subdomain (ex: dashboard.example.com/login)
|
||||
|
||||
It is recommended to start with the Auth0 stage once everything from the client has been recieved as things like the client ID will be needed in other stages
|
||||
|
||||
<!-- frontend steps -->
|
||||
Frontend Steps
|
||||
1. Create a PWA folder in `public` that is named after the client and generate PWA assets using [this](https://realfavicongenerator.net/) website (use the company logo but you might need to use a custom favicon depending on the result)
|
||||
|
||||
- https://maskable.app/ also create a maskable icon for PWA
|
||||
|
|
@ -29,22 +32,23 @@ Steps to add a new white label
|
|||
4. If there are any pages specific to the whitelabel be sure to update the side and bottom navigator
|
||||
|
||||
<!-- backend steps -->
|
||||
Backend Steps
|
||||
1. In `dynamic-config.prod.yml`, add a router entry for the new whitelabel
|
||||
2. In `pond/http/server.go`, add the sub-domain to the `allowedOrigins`
|
||||
3. In `pond/whitelabel.go`, add an entry for the new white label
|
||||
4. Enable the white-label sub-domain for CORS in the backend by adding it to the allowed origins http/server.go
|
||||
|
||||
<!-- Auth steps -->
|
||||
1. Create a new `Auth0` application for the client
|
||||
Auth0 Steps
|
||||
1. Create a new Single Page App on Auth0 using React as the tech
|
||||
2. Once you have the client ID add it to your .env file in the frontend
|
||||
3. Adjust settings accordingly in the new application
|
||||
- use a image bucket like [postimg](https://postimages.org/) to store their company logo and favicon
|
||||
- add a whitelabel logo
|
||||
- allow necessary `origins`, `callback URLs`, and `CORS domains` to the application settings (see the default application as a guideline)
|
||||
- allow necessary `origins`, `callback URLs`, and `CORS domains` to the application settings (see other applications/whitelabels as a guideline)
|
||||
- customize the Universal Login page to handle the new whitelabel
|
||||
- check if the client ID matches this client's Auth0 application
|
||||
- change the Universal Login theme using white-label colours and images stored in a bucket (ex: [postimg](https://postimages.org/))
|
||||
|
||||
- in [http.go](https://gitlab.com/brandx/backend/blob/master/pond/http.go), add the white-label sub-domain to the `AllowedOrigins` list
|
||||
|
||||
## Expanding the ESLint configuration
|
||||
|
||||
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
|
||||
|
|
|
|||
BIN
public/Intellifarms/IFND-2023-Logo-White.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
public/Intellifarms/IFND-2023-Logo.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
public/Intellifarms/android-chrome-192x192.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
public/Intellifarms/android-chrome-512x512.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
public/Intellifarms/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
9
public/Intellifarms/browserconfig.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="/mstile-150x150.png"/>
|
||||
<TileColor>#ffffff</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
||||
BIN
public/Intellifarms/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 712 B |
BIN
public/Intellifarms/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
public/Intellifarms/favicon-48x48.png
Normal file
|
After Width: | Height: | Size: 3 KiB |
BIN
public/Intellifarms/favicon.ico
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
19
public/Intellifarms/manifest.json
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "Intellifarms",
|
||||
"short_name": "Intellifarms",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
}
|
||||
BIN
public/Intellifarms/mstile-150x150.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
3
public/Intellifarms/safari-pinned-tab.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||
<image href="Intellifarms_Icon.png" height="512" width="512"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 134 B |
BIN
src/assets/whitelabels/Intellifarms/IFND-2023-Logo-White.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
src/assets/whitelabels/Intellifarms/IFND-2023-Logo.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
|
|
@ -57,6 +57,8 @@ interface Props {
|
|||
components?: Map<string, Component>;
|
||||
setComponents?: React.Dispatch<React.SetStateAction<Map<string, Component>>>;
|
||||
updateBinStatus?: (componentKeys: string[], removed?: boolean) => void;
|
||||
componentDevices?: Map<string, number>
|
||||
setComponentDevices?: React.Dispatch<React.SetStateAction<Map<string, number>>>;
|
||||
}
|
||||
|
||||
interface OpenState {
|
||||
|
|
@ -77,7 +79,9 @@ export default function BinActions(props: Props) {
|
|||
refreshCallback,
|
||||
userID,
|
||||
components,
|
||||
componentDevices,
|
||||
setComponents,
|
||||
setComponentDevices,
|
||||
updateBinStatus
|
||||
} = props;
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||
|
|
@ -245,7 +249,9 @@ export default function BinActions(props: Props) {
|
|||
open={openState.sensors}
|
||||
userID={userID}
|
||||
components={components}
|
||||
componentDevices={componentDevices}
|
||||
setComponents={setComponents}
|
||||
setComponentDevices={setComponentDevices}
|
||||
updateBinStatus={updateBinStatus}
|
||||
onClose={refresh => {
|
||||
if (refresh === true) {
|
||||
|
|
|
|||
|
|
@ -71,7 +71,9 @@ const useStyles = makeStyles((theme: Theme) => {
|
|||
|
||||
interface Props {
|
||||
components?: Map<string, Component>;
|
||||
componentDevices?: Map<string, number>;
|
||||
setComponents?: React.Dispatch<React.SetStateAction<Map<string, Component>>>;
|
||||
setComponentDevices?: React.Dispatch<React.SetStateAction<Map<string, number>>>;
|
||||
bin: string;
|
||||
binGrain: pond.Grain;
|
||||
updateBinStatus?: (componentKeys: string[], removed?: boolean) => void;
|
||||
|
|
@ -84,7 +86,7 @@ interface Option {
|
|||
}
|
||||
|
||||
export default function BinComponents(props: Props) {
|
||||
const { components, bin, setComponents, updateBinStatus, binGrain } = props;
|
||||
const { components, componentDevices, bin, setComponents, setComponentDevices, updateBinStatus, binGrain } = props;
|
||||
const [{as}] = useGlobalState();
|
||||
const classes = useStyles();
|
||||
const binAPI = useBinAPI();
|
||||
|
|
@ -208,20 +210,54 @@ export default function BinComponents(props: Props) {
|
|||
// }
|
||||
// }, [selectedDevice, componentAPI, deviceComponents, snackbar]);
|
||||
|
||||
const removeComponent = (component: string) => {
|
||||
binAPI.removeComponent(bin, component, as).then(() => {
|
||||
const removeComponent = (component: string, device?: number) => {
|
||||
console.log(device)
|
||||
binAPI.removeComponent(bin, component, device, as).then(() => {
|
||||
|
||||
if (components && setComponents) {
|
||||
if (components.delete(component)) {
|
||||
let newComponents = new Map(components);
|
||||
setComponents(newComponents);
|
||||
}
|
||||
}
|
||||
if(componentDevices && setComponentDevices) {
|
||||
if (componentDevices.delete(component)) {
|
||||
let newComponentDevices = new Map(componentDevices);
|
||||
setComponentDevices(newComponentDevices);
|
||||
}
|
||||
}
|
||||
snackbar.info("Component removed from bin");
|
||||
});
|
||||
setComponentToRemove(undefined);
|
||||
};
|
||||
|
||||
const removeComponentConfirmation = () => {
|
||||
const removeComponentConfirmation = (last?: boolean) => {
|
||||
let lastComponent = false;
|
||||
let devId: number | undefined;
|
||||
if(last){
|
||||
lastComponent = last
|
||||
}else{
|
||||
if (componentDevices && componentToRemove) {
|
||||
const id = componentDevices.get(componentToRemove.key());
|
||||
|
||||
if (id !== undefined) {
|
||||
devId = id
|
||||
let count = 0;
|
||||
|
||||
for (const val of componentDevices.values()) {
|
||||
if (val === devId) {
|
||||
count++;
|
||||
|
||||
if (count > 1) {
|
||||
break; // stop early once we know it's not the last
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lastComponent = count === 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (
|
||||
<ResponsiveDialog
|
||||
fullScreen={false}
|
||||
|
|
@ -229,19 +265,37 @@ export default function BinComponents(props: Props) {
|
|||
onClose={() => setComponentToRemove(undefined)}>
|
||||
<DialogTitle>Remove {componentToRemove?.name()}?</DialogTitle>
|
||||
<DialogContent>
|
||||
{lastComponent ?
|
||||
<DialogContentText>
|
||||
This component {componentToRemove?.name()} is the last component from its device. You can choose to remove only the component itself or the device along with it.
|
||||
Leaving the device may have unexpected results if the device will continue to be used and it is recommended to remove it if the device is being moved to a new bin.
|
||||
</DialogContentText>
|
||||
:
|
||||
<DialogContentText>
|
||||
This will remove {componentToRemove?.name()} from this bin. If you don't have direct
|
||||
access to this component or the device it is attached to, you will not be able to add it
|
||||
back.
|
||||
</DialogContentText>
|
||||
}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={() => setComponentToRemove(undefined)} color="primary">
|
||||
Cancel
|
||||
</Button>
|
||||
{lastComponent
|
||||
?
|
||||
<React.Fragment>
|
||||
<Button onClick={() => removeComponent(componentToRemove!.key())} color="primary">
|
||||
Remove Component
|
||||
</Button>
|
||||
<Button onClick={() => removeComponent(componentToRemove!.key(), devId)} color="primary">
|
||||
Remove Component And Device
|
||||
</Button>
|
||||
</React.Fragment> :
|
||||
<Button onClick={() => removeComponent(componentToRemove!.key())} color="primary">
|
||||
Remove
|
||||
</Button>
|
||||
}
|
||||
</DialogActions>
|
||||
</ResponsiveDialog>
|
||||
);
|
||||
|
|
@ -256,7 +310,7 @@ export default function BinComponents(props: Props) {
|
|||
<DialogTitle>Remove All Components?</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText>
|
||||
This will remove All attached components from this bin. If you don't have direct access
|
||||
This will remove All attached components and devices from this bin. If you don't have direct access
|
||||
to these components or the devices they are attached to, you will not be able to add
|
||||
them back.
|
||||
</DialogContentText>
|
||||
|
|
@ -320,6 +374,12 @@ export default function BinComponents(props: Props) {
|
|||
setComponents(newComponents);
|
||||
}
|
||||
}
|
||||
if(componentDevices && setComponentDevices) {
|
||||
if (componentDevices.set(component.key(), device)) {
|
||||
let newComponentDevices = new Map(componentDevices);
|
||||
setComponentDevices(newComponentDevices);
|
||||
}
|
||||
}
|
||||
//if a grain cable was added to the bin update the components grain type to match the bin
|
||||
if (preferences.type === pond.BinComponent.BIN_COMPONENT_GRAIN_CABLE) {
|
||||
let settings = component.settings;
|
||||
|
|
@ -338,16 +398,41 @@ export default function BinComponents(props: Props) {
|
|||
}
|
||||
});
|
||||
} else {
|
||||
binAPI.removeComponent(bin, component.key(), as).then(resp => {
|
||||
let lastComponent = false;
|
||||
if (componentDevices) {
|
||||
console.log(componentDevices)
|
||||
let count = 0;
|
||||
for (const val of componentDevices.values()) {
|
||||
if (val === device) {
|
||||
count++;
|
||||
|
||||
if (count > 1) {
|
||||
break; // stop early once we know it's not the last
|
||||
}
|
||||
}
|
||||
}
|
||||
lastComponent = count === 1;
|
||||
}
|
||||
if(lastComponent){
|
||||
setComponentToRemove(component)
|
||||
}else{
|
||||
binAPI.removeComponent(bin, component.key(), undefined, as).then(resp => {
|
||||
if (components && setComponents) {
|
||||
if (components.delete(component.key())) {
|
||||
let newComponents = new Map(components);
|
||||
setComponents(newComponents);
|
||||
}
|
||||
}
|
||||
if(componentDevices && setComponentDevices) {
|
||||
if (componentDevices.delete(component.key())) {
|
||||
let newComponentDevices = new Map(componentDevices);
|
||||
setComponentDevices(newComponentDevices);
|
||||
}
|
||||
}
|
||||
snackbar.info("Component removed from bin");
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const removeAll = () => {
|
||||
|
|
@ -567,7 +652,10 @@ export default function BinComponents(props: Props) {
|
|||
</ListItemAvatar>
|
||||
<ListItemText inset={cIcon === undefined}>{component.name()}</ListItemText>
|
||||
<ListItemSecondaryAction>
|
||||
<IconButton onClick={() => setComponentToRemove(component)}>
|
||||
<IconButton onClick={() => {
|
||||
setComponentToRemove(component)
|
||||
|
||||
}}>
|
||||
<Remove />
|
||||
</IconButton>
|
||||
</ListItemSecondaryAction>
|
||||
|
|
|
|||
|
|
@ -30,7 +30,9 @@ interface Props {
|
|||
coords?: { longitude: number; latitude: number };
|
||||
binYards?: pond.BinYardSettings[];
|
||||
components?: Map<string, Component>;
|
||||
componentDevices?: Map<string, number>
|
||||
setComponents?: React.Dispatch<React.SetStateAction<Map<string, Component>>>;
|
||||
setComponentDevices?: React.Dispatch<React.SetStateAction<Map<string, number>>>;
|
||||
updateBinStatus?: (componentKeys: string[], removed?: boolean) => void;
|
||||
}
|
||||
|
||||
|
|
@ -43,7 +45,9 @@ export default function BinSensors(props: Props) {
|
|||
mode,
|
||||
openedBinYard,
|
||||
components,
|
||||
componentDevices,
|
||||
setComponents,
|
||||
setComponentDevices,
|
||||
updateBinStatus
|
||||
} = props;
|
||||
const [initialized, setInitialized] = useState(false);
|
||||
|
|
@ -93,7 +97,9 @@ export default function BinSensors(props: Props) {
|
|||
<Box padding={1}>
|
||||
<BinComponents
|
||||
components={components ? components : undefined}
|
||||
componentDevices={componentDevices}
|
||||
setComponents={setComponents}
|
||||
setComponentDevices={setComponentDevices}
|
||||
bin={bin.key()}
|
||||
binGrain={bin.grain()}
|
||||
updateBinStatus={updateBinStatus}
|
||||
|
|
|
|||
|
|
@ -38,10 +38,12 @@ interface Props {
|
|||
multiGraphZoom?: (domain: number[] | string[]) => void;
|
||||
colourAboveZero?: ColourData
|
||||
colourBelowZero?: ColourData
|
||||
minY?: string | number
|
||||
maxY?: string | number
|
||||
}
|
||||
|
||||
export default function SingleSetAreaChart(props: Props) {
|
||||
const { data, maxRef, minRef, newXDomain, multiGraphZoom, yAxisLabel, colourAboveZero, colourBelowZero, tooltipLabel, tooltipUnit } = props;
|
||||
const { data, maxRef, minRef, newXDomain, multiGraphZoom, yAxisLabel, colourAboveZero, colourBelowZero, tooltipLabel, tooltipUnit, minY, maxY } = props;
|
||||
const [xDomain, setXDomain] = useState<string[] | number[]>(["dataMin", "dataMax"]);
|
||||
const [refLeft, setRefLeft] = useState<number | undefined>();
|
||||
const [refRight, setRefRight] = useState<number | undefined>();
|
||||
|
|
@ -152,7 +154,8 @@ export default function SingleSetAreaChart(props: Props) {
|
|||
/>
|
||||
<YAxis
|
||||
type="number"
|
||||
domain={["auto", "auto"]}
|
||||
allowDataOverflow
|
||||
domain={[minY ?? "auto", maxY ?? "auto"]}
|
||||
label={{
|
||||
value: yAxisLabel,
|
||||
position: "insideLeft",
|
||||
|
|
|
|||
|
|
@ -211,6 +211,8 @@ export default function GateDeltaTempGraph(props: Props){
|
|||
/>
|
||||
<SingleSetAreaChart
|
||||
data={data}
|
||||
minY={-40} //-40C is the same as -40F
|
||||
maxY={(user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? 104 : 40)}
|
||||
tooltipLabel="Delta Temp"
|
||||
tooltipUnit={user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? " °F" : " °C"}
|
||||
yAxisLabel={"Delta T" + (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? " °F" : " °C")}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import BinsIcon from "products/Bindapt/BinsIcon";
|
|||
import { useGlobalState } from "providers";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useNavigate, useLocation } from "react-router-dom";
|
||||
import { IsAdaptiveAgriculture, isBXT, IsMiVent, IsAdCon, IsOmniAir, IsMiPCA } from "services/whiteLabel";
|
||||
import { IsAdaptiveAgriculture, isBXT, IsMiVent, IsAdCon, IsOmniAir, IsMiPCA, IsIntellifarms } from "services/whiteLabel";
|
||||
import FieldsIcon from "products/AgIcons/FieldsIcon";
|
||||
import NexusSTIcon from "products/Construction/NexusSTIcon";
|
||||
import OmniAirDeviceIcon from "products/AviationIcons/OmniAirDeviceIcon";
|
||||
|
|
@ -36,7 +36,8 @@ export default function BottomNavigator(props: Props) {
|
|||
const { isAuthenticated } = useAuth0();
|
||||
const [{ user }] = useGlobalState();
|
||||
const [route, setRoute] = useState(sideIsOpen ? "side" : "");
|
||||
const isAdaptive = IsAdaptiveAgriculture();
|
||||
const isAg = IsAdaptiveAgriculture();
|
||||
const isIntel = IsIntellifarms();
|
||||
const isMiVent = IsMiVent();
|
||||
const isAdCon = IsAdCon();
|
||||
const isOmni = IsOmniAir();
|
||||
|
|
@ -45,7 +46,7 @@ export default function BottomNavigator(props: Props) {
|
|||
const reRoute = useCallback(
|
||||
(path: string) => {
|
||||
if (path === "") {
|
||||
if (isAdaptive) {
|
||||
if (isAg || isIntel) {
|
||||
return "bins";
|
||||
}
|
||||
if (isMiVent) {
|
||||
|
|
@ -74,7 +75,7 @@ export default function BottomNavigator(props: Props) {
|
|||
}
|
||||
return path;
|
||||
},
|
||||
[isAdaptive, isMiVent]
|
||||
[isAg, isMiVent, isIntel]
|
||||
);
|
||||
|
||||
const autoDetectRoute = useCallback(() => {
|
||||
|
|
@ -105,10 +106,10 @@ export default function BottomNavigator(props: Props) {
|
|||
const authenticatedNavigation = () => {
|
||||
return (
|
||||
<BottomNavigation value={route} onChange={(_, newValue) => handleRouteChange(newValue)}>
|
||||
{isAdaptive && (
|
||||
{isAg || isIntel && (
|
||||
<BottomNavigationAction label="Farm" icon={<FieldsIcon type={getType()} />} value="visualFarm" />
|
||||
)}
|
||||
{isAdaptive && (
|
||||
{isAg || isIntel && (
|
||||
<BottomNavigationAction label="Bins" icon={<BinsIcon type={getType()} />} value="bins" />
|
||||
)}
|
||||
{isAdCon && (
|
||||
|
|
@ -136,7 +137,7 @@ export default function BottomNavigator(props: Props) {
|
|||
<BottomNavigationAction
|
||||
label="Devices"
|
||||
icon={
|
||||
isAdaptive ? (
|
||||
(isAg || isIntel) ? (
|
||||
<BindaptIcon type={getType()} />
|
||||
) : isAdCon ? (
|
||||
<NexusSTIcon type={getType()} />
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import {
|
|||
IsAdaptiveAgriculture,
|
||||
// hasTutorialPlaylist,
|
||||
IsAdCon,
|
||||
IsIntellifarms,
|
||||
IsMiPCA,
|
||||
// isBXT,
|
||||
IsMiVent,
|
||||
|
|
@ -166,13 +167,14 @@ export default function SideNavigator(props: Props) {
|
|||
const authenticatedSideMenu = () => {
|
||||
const isMiVent = IsMiVent();
|
||||
const isAg = IsAdaptiveAgriculture()
|
||||
const isIntel = IsIntellifarms()
|
||||
const isStreamline = IsStreamline()
|
||||
const isOmni = IsOmniAir()
|
||||
const isMiPCA = IsMiPCA()
|
||||
const isAdCon = IsAdCon()
|
||||
return (
|
||||
<List className={classes.list} component="nav">
|
||||
{(isAg || isStreamline || user.hasFeature("admin")) && (
|
||||
{(isAg || isIntel || isStreamline || user.hasFeature("admin")) && (
|
||||
<Tooltip title="Visual Farm" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-visual-farm"
|
||||
|
|
@ -214,7 +216,7 @@ export default function SideNavigator(props: Props) {
|
|||
</ListItemButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
{(isAg || isStreamline || user.hasFeature("admin")) && (
|
||||
{(isAg || isIntel || isStreamline || user.hasFeature("admin")) && (
|
||||
<Tooltip title="Contracts" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-contracts"
|
||||
|
|
@ -228,7 +230,7 @@ export default function SideNavigator(props: Props) {
|
|||
</ListItemButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
{(isAg || isStreamline || user.hasFeature("admin")) && (
|
||||
{(isAg || isIntel || isStreamline || user.hasFeature("admin")) && (
|
||||
<Tooltip title="Bins" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-bins"
|
||||
|
|
@ -270,7 +272,7 @@ export default function SideNavigator(props: Props) {
|
|||
</ListItemButton>
|
||||
</Tooltip>
|
||||
}
|
||||
{(isAg || isStreamline || user.hasFeature("admin")) && (
|
||||
{(isAg || isIntel || isStreamline || user.hasFeature("admin")) && (
|
||||
<Tooltip title="Transactions" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-transactions"
|
||||
|
|
@ -362,7 +364,7 @@ export default function SideNavigator(props: Props) {
|
|||
{open && <ListItemText primary="Users" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
{(isAg || isStreamline || user.hasFeature("admin")) && (
|
||||
{(isAg || isIntel || isStreamline || user.hasFeature("admin")) && (
|
||||
<Tooltip title="My Fields" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-field-list"
|
||||
|
|
@ -376,7 +378,7 @@ export default function SideNavigator(props: Props) {
|
|||
</ListItemButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
{(isAg || isStreamline || user.hasFeature("admin")) && (
|
||||
{(isAg || isIntel || isStreamline || user.hasFeature("admin")) && (
|
||||
<Tooltip title="Grain Types" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-grain-types"
|
||||
|
|
@ -460,7 +462,7 @@ export default function SideNavigator(props: Props) {
|
|||
</ListItemButton>
|
||||
</Tooltip>
|
||||
}
|
||||
{(isAg || isStreamline || user.hasFeature("admin")) &&
|
||||
{(isAg || isIntel || isStreamline || user.hasFeature("admin")) &&
|
||||
<Tooltip title="Marketplace" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-marketplace"
|
||||
|
|
|
|||
|
|
@ -271,7 +271,7 @@ export default function Bin(props: Props) {
|
|||
resp.data.devices.forEach((dev: any) => {
|
||||
let device = Device.create(dev);
|
||||
if (attachedDevIds.includes(device.id())) {
|
||||
devs.push(Device.create(dev));
|
||||
devs.push(device);
|
||||
}
|
||||
});
|
||||
setDevices(devs);
|
||||
|
|
@ -676,6 +676,8 @@ export default function Bin(props: Props) {
|
|||
userID={user.id()}
|
||||
components={components}
|
||||
setComponents={setComponents}
|
||||
componentDevices={componentDevices}
|
||||
setComponentDevices={setComponentDevices}
|
||||
updateBinStatus={updateStatus}
|
||||
/>
|
||||
</Grid>
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ export interface IBinAPIContext {
|
|||
removeComponent: (
|
||||
bin: string,
|
||||
component: string,
|
||||
device?: number,
|
||||
otherTeam?: string
|
||||
) => Promise<AxiosResponse<pond.RemoveBinComponentResponse>>;
|
||||
removeAllComponents: (bin: string, otherTeam?: string) => Promise<AxiosResponse<pond.RemoveAllBinComponentsResponse>>;
|
||||
|
|
@ -254,10 +255,11 @@ export default function BinProvider(props: PropsWithChildren<Props>) {
|
|||
})
|
||||
};
|
||||
|
||||
const removeComponent = (bin: string, component: string, otherTeam?: string) => {
|
||||
const removeComponent = (bin: string, component: string, device?: number, otherTeam?: string) => {
|
||||
const view = otherTeam ? otherTeam : as
|
||||
let url = "/bins/" + bin + "/removeComponent/" + component;
|
||||
if (view) url = url + "?as=" + view;
|
||||
if (device) url = url + "?deviceToRemove=" + device
|
||||
if (view) url = url + (device ? "&as=" : "?as=") + view;
|
||||
return new Promise<AxiosResponse<pond.RemoveBinComponentResponse>>((resolve, reject)=>{
|
||||
post<pond.RemoveBinComponentResponse>(pondURL(url)).then(resp => {
|
||||
resp.data = pond.RemoveBinComponentResponse.fromObject(resp.data)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ import MiVentLightLogo from "../assets/whitelabels/MiVent/lightLogo.png";
|
|||
// import OmniAirLogo from "../assets/whitelabels/OmniAir/OmniAirLogo.png";
|
||||
import MiPCALogo from "../assets/whitelabels/MiPCA/MiPCALogo.png";
|
||||
import StreamlineLogo from "../assets/whitelabels/Streamline/stream-logo.png"
|
||||
import IntellifarmsLogo from "../assets/whitelabels/Intellifarms/IFND-2023-Logo.png"
|
||||
import IntellifarmsLogoWhite from "../assets/whitelabels/Intellifarms/IFND-2023-Logo-White.png"
|
||||
// import { green, yellow } from "@mui/material/colors";
|
||||
|
||||
const protips: string[] = [
|
||||
|
|
@ -180,6 +182,32 @@ export function IsAdaptiveAgriculture(): boolean {
|
|||
);
|
||||
}
|
||||
|
||||
const INTELLIFARMS_WHITE_LABEL: WhiteLabel = {
|
||||
name: "Intellifarms",
|
||||
primaryColour: "#9E1B32",
|
||||
secondaryColour: "#4A4F55",
|
||||
signatureColour: "#272727",
|
||||
signatureAccentColour: "#fff",
|
||||
auth0ClientId: import.meta.env.VITE_AUTH0_INTELLIFARMS_CLIENT_ID,
|
||||
redirectOnLogout: true,
|
||||
logoutRedirectTarget: "https://myintellifarms.com",
|
||||
darkLogo: IntellifarmsLogo,
|
||||
lightLogo: IntellifarmsLogoWhite,
|
||||
transparentLogoBG: true,
|
||||
blacklist: [],
|
||||
docs: "Platform",
|
||||
protips: protips,
|
||||
homePage: "/bins"
|
||||
};
|
||||
|
||||
export function IsIntellifarms(): boolean {
|
||||
return (
|
||||
getName() === "Intellifarms"
|
||||
// window.location.origin.includes("staging") ||
|
||||
// window.location.origin.includes("localhost")
|
||||
);
|
||||
}
|
||||
|
||||
export function IsStreamline(): boolean {
|
||||
return (
|
||||
getName() === "Streamline"
|
||||
|
|
@ -324,7 +352,8 @@ const whitelabels = new Map<string, WhiteLabel>([
|
|||
["adaptiveconstruction", ADAPTIVE_CONSTRUCTION_WHITE_LABEL],
|
||||
["omniair", OMNIAIR_WHITE_LABEL],
|
||||
["mipca", MIPCA_WHITE_LABEL],
|
||||
["mionetech", MIPCA_WHITE_LABEL]
|
||||
["mionetech", MIPCA_WHITE_LABEL],
|
||||
["intellifarms", INTELLIFARMS_WHITE_LABEL]
|
||||
]);
|
||||
|
||||
export function getWhitelabel(): WhiteLabel {
|
||||
|
|
@ -337,7 +366,7 @@ export function getWhitelabel(): WhiteLabel {
|
|||
return BXT_WHITE_LABEL;
|
||||
}
|
||||
if (window.location.origin.includes("localhost")) {
|
||||
return STREAMLINE_WHITE_LABEL;
|
||||
return INTELLIFARMS_WHITE_LABEL;
|
||||
}
|
||||
if (window.location.origin.includes("staging") || import.meta.env.VITE_LOCAL_STAGING=='true') {
|
||||
return STAGING_WHITELABEL;
|
||||
|
|
|
|||