Merge branch 'staging_environment' into field_dashboard
This commit is contained in:
commit
a6b463eea2
12 changed files with 273 additions and 114 deletions
|
|
@ -71,6 +71,12 @@ http {
|
|||
add_header Cache-Control "no-store, no-cache, must-revalidate";
|
||||
}
|
||||
|
||||
# Force re-cache of old service-worker
|
||||
location = /service-worker.js {
|
||||
root /usr/share/nginx/html; # adjust if your build folder is elsewhere
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate";
|
||||
}
|
||||
|
||||
# Redirect old /index.html requests to new file
|
||||
location = /index.html {
|
||||
return 301 /indexV2.html;
|
||||
|
|
|
|||
2
package-lock.json
generated
2
package-lock.json
generated
|
|
@ -10911,7 +10911,7 @@
|
|||
},
|
||||
"node_modules/protobuf-ts": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#70351a87aa4a83bd6274adf8e3b7937090ab4cc2",
|
||||
"resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#c669ff3b4818861ef356c59eee671313ac090ddb",
|
||||
"dependencies": {
|
||||
"protobufjs": "^6.8.8"
|
||||
}
|
||||
|
|
|
|||
24
public/service-worker.js
Normal file
24
public/service-worker.js
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// public/service-worker.js
|
||||
self.addEventListener('install', () => self.skipWaiting());
|
||||
|
||||
self.addEventListener('activate', async () => {
|
||||
// Unregister old CRA SW
|
||||
const regs = await self.registration.scope ? [self.registration] : await self.clients.getRegistrations();
|
||||
for (const reg of regs) {
|
||||
if (reg && reg.scriptURL.endsWith('service-worker.js')) {
|
||||
await reg.unregister();
|
||||
}
|
||||
}
|
||||
|
||||
// Clear all caches
|
||||
if ('caches' in self) {
|
||||
const keys = await caches.keys();
|
||||
for (const key of keys) {
|
||||
await caches.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
// Reload all clients
|
||||
const clients = await self.clients.matchAll({ type: 'window' });
|
||||
clients.forEach(client => client.navigate(client.url));
|
||||
});
|
||||
|
|
@ -103,8 +103,10 @@ export default function BinCard(props: Props) {
|
|||
let filteredNodes = c.filteredNodes(true)
|
||||
|
||||
allTemps.push(...filteredNodes.temps);
|
||||
allHums.push(...filteredNodes.humids);
|
||||
allMoistures.push(...filteredNodes.moistures);
|
||||
if(avg(c.humidities) !== 0){ //if the average of the humidities is 0 that means that all the readings are 0 and it is a temp only cable
|
||||
allHums.push(...filteredNodes.humids);
|
||||
allMoistures.push(...filteredNodes.moistures);
|
||||
}
|
||||
|
||||
//set the hottest and coldest nodes
|
||||
if (coldestNode === undefined || Math.min(...filteredNodes.temps) < coldestNode.temp) {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ export default function BinDuplication(props: Props) {
|
|||
binAPI
|
||||
.addBin(settings)
|
||||
.then(resp => {
|
||||
openSnack("Successfully duplicated bin");
|
||||
openSnack("Successfully duplicated bin");
|
||||
})
|
||||
.catch(err => {
|
||||
openSnack("Failed to duplicate bin");
|
||||
|
|
|
|||
|
|
@ -476,11 +476,11 @@ export default function BinSVGV2(props: Props) {
|
|||
return cableGrainPath;
|
||||
};
|
||||
|
||||
const nodeClass = (nodeTemp: number) => {
|
||||
if (hottestNodeTemp && hottestNodeTemp.toFixed(2) === nodeTemp.toFixed(2)) {
|
||||
const nodeClass = (nodeTemp: number, underTop: boolean) => {
|
||||
if (hottestNodeTemp && hottestNodeTemp.toFixed(2) === nodeTemp.toFixed(2) && underTop) {
|
||||
return classes.hotNode;
|
||||
}
|
||||
if (coldestNodeTemp && coldestNodeTemp.toFixed(2) === nodeTemp.toFixed(2)) {
|
||||
if (coldestNodeTemp && coldestNodeTemp.toFixed(2) === nodeTemp.toFixed(2) && underTop) {
|
||||
return classes.coldNode;
|
||||
}
|
||||
return classes.cableNode;
|
||||
|
|
@ -507,12 +507,12 @@ export default function BinSVGV2(props: Props) {
|
|||
//if the cables have the same number of nodes
|
||||
if (b.temperatures.length === a.temperatures.length) {
|
||||
//sort by temp only last and any type that has humidity first
|
||||
if (
|
||||
a.settings.subtype === quack.GrainCableSubtype.GRAIN_CABLE_SUBTYPE_OPI_TEMP &&
|
||||
b.settings.subtype !== quack.GrainCableSubtype.GRAIN_CABLE_SUBTYPE_OPI_TEMP
|
||||
) {
|
||||
if ((avg(a.humidities) === 0 || a.humidities.length === 0) && (avg(b.humidities) !== 0 || b.humidities.length > 0)) {
|
||||
return 1;
|
||||
} else {
|
||||
} else if ((avg(b.humidities) === 0 || b.humidities.length === 0) && (avg(a.humidities) !== 0 || a.humidities.length > 0)) {
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
return a.key() > b.key() ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
|
@ -759,7 +759,7 @@ export default function BinSVGV2(props: Props) {
|
|||
return (
|
||||
<g key={e.key}>
|
||||
{e.nodeNumber === topNode && !e.excluded && topNodeHat(cablePos, e.y)}
|
||||
<circle cx={cablePos} cy={e.y} className={e.excluded ? classes.excludedNode : nodeClass(e.nodeTemp)} r="16"></circle>
|
||||
<circle cx={cablePos} cy={e.y} className={e.excluded ? classes.excludedNode : nodeClass(e.nodeTemp, e.nodeNumber <= topNode)} r="16"></circle>
|
||||
</g>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -250,6 +250,7 @@ export default function BinVisualizer(props: Props) {
|
|||
const [cfmHighOpen, setCFMHighOpen] = useState(false);
|
||||
const [{ user }] = useGlobalState();
|
||||
const [newPreset, setNewPreset] = useState<pond.BinMode>(pond.BinMode.BIN_MODE_NONE);
|
||||
const [newBinMode, setNewBinMode] = useState<pond.BinMode>(pond.BinMode.BIN_MODE_NONE);
|
||||
const [selectedCable, setSelectedCable] = useState<GrainCable>();
|
||||
const [openNodeDialog, setOpenNodeDialog] = useState(false);
|
||||
const [cableDevice, setCableDevice] = useState<Device | undefined>();
|
||||
|
|
@ -345,6 +346,7 @@ export default function BinVisualizer(props: Props) {
|
|||
setGrainOption(ToGrainOption(bin.settings.inventory.grainType));
|
||||
setBushPerTonne(bin.settings.inventory.bushelsPerTonne.toFixed(2));
|
||||
setGrainSubtype(bin.subtype());
|
||||
setNewBinMode(bin.settings.mode);
|
||||
}
|
||||
if (bin.settings) {
|
||||
let t = bin.settings.outdoorTemp;
|
||||
|
|
@ -384,8 +386,11 @@ export default function BinVisualizer(props: Props) {
|
|||
//also reverse it so that the node 1 (end of the cable) is in the first position
|
||||
let filteredNodes = cable.filteredNodes(true)
|
||||
temps.push(...filteredNodes.temps)
|
||||
humids.push(...filteredNodes.humids)
|
||||
emcs.push(...filteredNodes.moistures)
|
||||
//only push to the humidity values if the cable reads humidities
|
||||
if(cable.subType() !== quack.GrainCableSubtype.GRAIN_CABLE_SUBTYPE_OPI_TEMP){
|
||||
humids.push(...filteredNodes.humids)
|
||||
emcs.push(...filteredNodes.moistures)
|
||||
}
|
||||
// let tempClone = cloneDeep(cable.temperatures).reverse();
|
||||
// let humClone = cloneDeep(cable.humidities).reverse();
|
||||
// let emcClone = cloneDeep(cable.grainMoistures).reverse();
|
||||
|
|
@ -409,14 +414,15 @@ export default function BinVisualizer(props: Props) {
|
|||
|
||||
//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) {
|
||||
if (!lowNodeConditions || Math.min(...filteredNodes.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));
|
||||
filteredNodes.temps.indexOf(Math.min(...filteredNodes.temps)) === -1 ? 0 : filteredNodes.temps.indexOf(Math.min(...filteredNodes.temps));
|
||||
console.log(lowTempIndex)
|
||||
lowNodeConditions = {
|
||||
tempC: temps[lowTempIndex],
|
||||
humidity: humids[lowTempIndex],
|
||||
emc: emcs[lowTempIndex],
|
||||
tempC: filteredNodes.temps[lowTempIndex],
|
||||
humidity: filteredNodes.humids[lowTempIndex],
|
||||
emc: filteredNodes.moistures[lowTempIndex],
|
||||
tempCTrend: cableTrendData.coldNodeTrend?.tempTrend ?? 0,
|
||||
humidityTrend: cableTrendData.coldNodeTrend?.humidityTrend ?? 0,
|
||||
emcTrend: cableTrendData.coldNodeTrend?.emcTrend ?? 0
|
||||
|
|
@ -424,13 +430,13 @@ export default function BinVisualizer(props: Props) {
|
|||
}
|
||||
|
||||
//do the same for the high node
|
||||
if (!highNodeConditions || cable.maxTemp() > highNodeConditions.tempC) {
|
||||
if (!highNodeConditions || Math.max(...filteredNodes.temps) > highNodeConditions.tempC) {
|
||||
let highTempIndex =
|
||||
temps.indexOf(Math.max(...temps)) === -1 ? 0 : temps.indexOf(Math.max(...temps));
|
||||
filteredNodes.temps.indexOf(Math.max(...filteredNodes.temps)) === -1 ? 0 : filteredNodes.temps.indexOf(Math.max(...filteredNodes.temps));
|
||||
highNodeConditions = {
|
||||
tempC: temps[highTempIndex],
|
||||
humidity: humids[highTempIndex],
|
||||
emc: emcs[highTempIndex],
|
||||
tempC: filteredNodes.temps[highTempIndex],
|
||||
humidity: filteredNodes.humids[highTempIndex],
|
||||
emc: filteredNodes.humids[highTempIndex],
|
||||
tempCTrend: cableTrendData.hotNodeTrend?.tempTrend ?? 0,
|
||||
humidityTrend: cableTrendData.hotNodeTrend?.humidityTrend ?? 0,
|
||||
emcTrend: cableTrendData.hotNodeTrend?.emcTrend ?? 0
|
||||
|
|
@ -1967,6 +1973,7 @@ export default function BinVisualizer(props: Props) {
|
|||
|
||||
const setModeStorage = () => {
|
||||
setNewPreset(pond.BinMode.BIN_MODE_STORAGE);
|
||||
setNewBinMode(pond.BinMode.BIN_MODE_STORAGE);
|
||||
};
|
||||
|
||||
const setModeCooldown = () => {
|
||||
|
|
@ -1974,6 +1981,7 @@ export default function BinVisualizer(props: Props) {
|
|||
return;
|
||||
}
|
||||
setNewPreset(pond.BinMode.BIN_MODE_COOLDOWN);
|
||||
setNewBinMode(pond.BinMode.BIN_MODE_COOLDOWN);
|
||||
};
|
||||
|
||||
const setModeDrying = () => {
|
||||
|
|
@ -1982,13 +1990,16 @@ export default function BinVisualizer(props: Props) {
|
|||
bin.settings.inventory?.initialMoisture < bin.settings.inventory?.targetMoisture
|
||||
) {
|
||||
setNewPreset(pond.BinMode.BIN_MODE_HYDRATING);
|
||||
setNewBinMode(pond.BinMode.BIN_MODE_HYDRATING);
|
||||
} else {
|
||||
setNewPreset(pond.BinMode.BIN_MODE_DRYING);
|
||||
setNewBinMode(pond.BinMode.BIN_MODE_DRYING);
|
||||
}
|
||||
};
|
||||
|
||||
const closeMoistureDialog = () => {
|
||||
setNewPreset(0);
|
||||
setNewBinMode(bin.settings.mode);
|
||||
setShowInputMoisture(false);
|
||||
};
|
||||
|
||||
|
|
@ -2049,6 +2060,7 @@ export default function BinVisualizer(props: Props) {
|
|||
<Button
|
||||
onClick={() => {
|
||||
setNewPreset(0);
|
||||
setNewBinMode(bin.settings.mode);
|
||||
setShowInputMoisture(false);
|
||||
}}
|
||||
color="primary">
|
||||
|
|
@ -2090,7 +2102,13 @@ export default function BinVisualizer(props: Props) {
|
|||
}
|
||||
if (b.settings.outdoorHumidity !== undefined)
|
||||
b.settings.outdoorHumidity = Number(outdoorHumidityInput);
|
||||
b.settings.mode = newPreset;
|
||||
|
||||
if (b.settings.mode != newBinMode){
|
||||
if(b.settings.inventory){
|
||||
b.settings.inventory.initialTimestamp = moment().format();
|
||||
}
|
||||
b.settings.mode = newBinMode;
|
||||
}
|
||||
|
||||
binAPI.updateBin(bin.key(), b.settings, as).then(resp => {
|
||||
refresh();
|
||||
|
|
|
|||
|
|
@ -699,6 +699,86 @@ export default function ComponentForm(props: Props) {
|
|||
);
|
||||
};
|
||||
|
||||
const componentMode = () => {
|
||||
const { component, coefficient, offset } = form;
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Grid size={{ xs: 4, sm: 3 }}>
|
||||
<Tooltip
|
||||
title="Switch to be able to customize the mode of the component"
|
||||
placement="bottom">
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={component.settings.calibrate}
|
||||
onChange={toggleCalibrate}
|
||||
name="mode"
|
||||
aria-label="mode"
|
||||
color="secondary"
|
||||
/>
|
||||
}
|
||||
label="Mode"
|
||||
labelPlacement="top"
|
||||
className={classes.switchControl}
|
||||
disabled={!canEdit}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 10, sm: 4 }}>
|
||||
{compMode.mode.entryA && (
|
||||
<TextField
|
||||
id={compMode.mode.labelA}
|
||||
label={compMode.mode.labelA}
|
||||
disabled={!component.settings.calibrate}
|
||||
error={!isCoefficientValid()}
|
||||
value={coefficient}
|
||||
onChange={changeCoefficient}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
select={compMode.mode.entryA === "select"}
|
||||
type={compMode.mode.entryA}
|
||||
variant="outlined">
|
||||
{compMode.mode.entryA === "select" &&
|
||||
compMode.mode.dictionaryA.map((elem: any) => {
|
||||
if (!elem.restricted || (elem.restricted && user.hasAdmin())) {
|
||||
return (
|
||||
<MenuItem key={elem.key} value={elem.value}>
|
||||
{elem.key}
|
||||
</MenuItem>
|
||||
);
|
||||
}
|
||||
return undefined; //TODO-CS: Time permitting re-think the structure of this function so that I don't have to return undefined
|
||||
})}
|
||||
</TextField>
|
||||
)}
|
||||
</Grid>
|
||||
<Grid size={{ xs: 10, sm: 5 }}>
|
||||
{compMode.mode.entryB && (
|
||||
<TextField
|
||||
id={compMode.mode.labelB}
|
||||
label={compMode.mode.labelB}
|
||||
disabled={!component.settings.calibrate}
|
||||
error={!isOffsetValid(compMode.mode.minB, compMode.mode.maxB)}
|
||||
value={offset}
|
||||
onChange={changeOffset}
|
||||
onFocus={selectText}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
type={compMode.mode.entryB}
|
||||
variant="outlined">
|
||||
{compMode.mode.entryB === "select" &&
|
||||
compMode.mode.dictionaryB.map((elem: any) => (
|
||||
<MenuItem key={elem.key} value={elem.value}>
|
||||
{elem.key}
|
||||
</MenuItem>
|
||||
))}
|
||||
</TextField>
|
||||
)}
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
|
||||
const describeSource = (measurementType: quack.MeasurementType): MeasurementDescriber => {
|
||||
const { component } = form;
|
||||
return describeMeasurement(measurementType, component.type(), component.subType());
|
||||
|
|
@ -1046,87 +1126,17 @@ export default function ComponentForm(props: Props) {
|
|||
</AccordionDetails>
|
||||
</Accordion>
|
||||
}
|
||||
{!compMode ? (
|
||||
device.featureSupported("individualCalibrations") ? (
|
||||
individualCalibration()
|
||||
) : (
|
||||
blanketCalibration()
|
||||
)
|
||||
) : (
|
||||
{device.featureSupported("individualCalibrations") ? (
|
||||
<React.Fragment>
|
||||
<Grid size={{ xs: 4, sm: 3 }}>
|
||||
<Tooltip
|
||||
title="Switch to be able to customize the mode of the component"
|
||||
placement="bottom">
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={component.settings.calibrate}
|
||||
onChange={toggleCalibrate}
|
||||
name="mode"
|
||||
aria-label="mode"
|
||||
color="secondary"
|
||||
/>
|
||||
}
|
||||
label="Mode"
|
||||
labelPlacement="top"
|
||||
className={classes.switchControl}
|
||||
disabled={!canEdit}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 10, sm: 4 }}>
|
||||
{compMode.mode.entryA && (
|
||||
<TextField
|
||||
id={compMode.mode.labelA}
|
||||
label={compMode.mode.labelA}
|
||||
disabled={!component.settings.calibrate}
|
||||
error={!isCoefficientValid()}
|
||||
value={coefficient}
|
||||
onChange={changeCoefficient}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
select={compMode.mode.entryA === "select"}
|
||||
type={compMode.mode.entryA}
|
||||
variant="outlined">
|
||||
{compMode.mode.entryA === "select" &&
|
||||
compMode.mode.dictionaryA.map((elem: any) => {
|
||||
if (!elem.restricted || (elem.restricted && user.hasAdmin())) {
|
||||
return (
|
||||
<MenuItem key={elem.key} value={elem.value}>
|
||||
{elem.key}
|
||||
</MenuItem>
|
||||
);
|
||||
}
|
||||
return undefined; //TODO-CS: Time permitting re-think the structure of this function so that I don't have to return undefined
|
||||
})}
|
||||
</TextField>
|
||||
)}
|
||||
</Grid>
|
||||
<Grid size={{ xs: 10, sm: 5 }}>
|
||||
{compMode.mode.entryB && (
|
||||
<TextField
|
||||
id={compMode.mode.labelB}
|
||||
label={compMode.mode.labelB}
|
||||
disabled={!component.settings.calibrate}
|
||||
error={!isOffsetValid(compMode.mode.minB, compMode.mode.maxB)}
|
||||
value={offset}
|
||||
onChange={changeOffset}
|
||||
onFocus={selectText}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
type={compMode.mode.entryB}
|
||||
variant="outlined">
|
||||
{compMode.mode.entryB === "select" &&
|
||||
compMode.mode.dictionaryB.map((elem: any) => (
|
||||
<MenuItem key={elem.key} value={elem.value}>
|
||||
{elem.key}
|
||||
</MenuItem>
|
||||
))}
|
||||
</TextField>
|
||||
)}
|
||||
</Grid>
|
||||
{compMode && componentMode()}
|
||||
{individualCalibration()}
|
||||
</React.Fragment>
|
||||
) : (
|
||||
!compMode ? (
|
||||
blanketCalibration()
|
||||
):(
|
||||
componentMode()
|
||||
)
|
||||
)}
|
||||
<TextField
|
||||
id="dataAveraging"
|
||||
|
|
|
|||
|
|
@ -38,6 +38,45 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 12,
|
||||
"subtype": 1,
|
||||
"mode": {
|
||||
"labelA": "Power Mode",
|
||||
"entryA": "select",
|
||||
"dictionaryA": [
|
||||
{
|
||||
"key": "High Power",
|
||||
"value": 1,
|
||||
"restricted": false
|
||||
},
|
||||
{
|
||||
"key": "Low Power",
|
||||
"value": 2,
|
||||
"restricted": false
|
||||
},
|
||||
{
|
||||
"key": "Calibration",
|
||||
"value": 3,
|
||||
"restricted": true
|
||||
}
|
||||
],
|
||||
"labelB": "Number of Averages",
|
||||
"entryB": "number",
|
||||
"dictionaryB": [
|
||||
{
|
||||
"key": "min",
|
||||
"value": 1,
|
||||
"restricted": false
|
||||
},
|
||||
{
|
||||
"key": "max",
|
||||
"value": 8,
|
||||
"restricted": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 28,
|
||||
"subtype": 0,
|
||||
|
|
|
|||
|
|
@ -540,6 +540,66 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
|||
weightConversionKg: 27.2155,
|
||||
bushelsPerTonne: 36.744
|
||||
}
|
||||
],[
|
||||
pond.Grain.GRAIN_RYE_A,
|
||||
{
|
||||
name: "Rye a",
|
||||
group: "Rye",
|
||||
equation: Equation.henderson,
|
||||
a: 0.00006343,
|
||||
b: 2.2060,
|
||||
c: 13.1810,
|
||||
setTempC: defaultSetTemp,
|
||||
targetMC: 15.0,
|
||||
colour: "grey",
|
||||
weightConversionKg: 25.4,
|
||||
bushelsPerTonne: 39.368
|
||||
}
|
||||
],[
|
||||
pond.Grain.GRAIN_RYE_B,
|
||||
{
|
||||
name: "Rye b",
|
||||
group: "Rye",
|
||||
equation: Equation.chungPfost,
|
||||
a: 461.0230,
|
||||
b: 0.1840,
|
||||
c: 36.7410,
|
||||
setTempC: defaultSetTemp,
|
||||
targetMC: 15.0,
|
||||
colour: "grey",
|
||||
weightConversionKg: 25.4,
|
||||
bushelsPerTonne: 39.368
|
||||
},
|
||||
],[
|
||||
pond.Grain.GRAIN_RYE_C,
|
||||
{
|
||||
name: "Rye c",
|
||||
group: "Rye",
|
||||
equation: Equation.halsey,
|
||||
a: 4.2970,
|
||||
b: 0.380,
|
||||
c: 2.2710,
|
||||
setTempC: defaultSetTemp,
|
||||
targetMC: 15.0,
|
||||
colour: "grey",
|
||||
weightConversionKg: 25.4,
|
||||
bushelsPerTonne: 39.368
|
||||
},
|
||||
],[
|
||||
pond.Grain.GRAIN_RYE_D,
|
||||
{
|
||||
name: "Rye d",
|
||||
group: "Rye",
|
||||
equation: Equation.oswin,
|
||||
a: 11.8870,
|
||||
b: 0.0210,
|
||||
c: 3.2620,
|
||||
setTempC: defaultSetTemp,
|
||||
targetMC: 15.0,
|
||||
colour: "grey",
|
||||
weightConversionKg: 25.4,
|
||||
bushelsPerTonne: 39.368
|
||||
}
|
||||
]
|
||||
]);
|
||||
|
||||
|
|
|
|||
|
|
@ -273,7 +273,7 @@ export class GrainCable {
|
|||
let filtered: number[] = []
|
||||
values.forEach((val, index) => {
|
||||
//if the node is not excluded AND is either under the top node OR top node is not set
|
||||
if(!this.excludedNodes.includes(index) && (index <= this.topNode || this.topNode === 0)){
|
||||
if(!this.excludedNodes.includes(index) && (index < this.topNode || this.topNode === 0)){
|
||||
filtered.push(val)
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -62,14 +62,14 @@ const agFeatureList: ProductDetails[] = [
|
|||
// bulletPoints: ["bullet one", "bullet two"],
|
||||
// questions: [],
|
||||
},
|
||||
{
|
||||
featureName: "libra-cart",
|
||||
featureLogo: <LibraCartIcon />,
|
||||
featureCost: 0,
|
||||
cardImage: FeatureImageTest,
|
||||
featureTitle: "Libra Cart",
|
||||
longDescription: "Integrate with Libra Cart to bring your data into our platform"
|
||||
}
|
||||
// {
|
||||
// featureName: "libra-cart",
|
||||
// featureLogo: <LibraCartIcon />,
|
||||
// featureCost: 0,
|
||||
// cardImage: FeatureImageTest,
|
||||
// featureTitle: "Libra Cart",
|
||||
// longDescription: "Integrate with Libra Cart to bring your data into our platform"
|
||||
// }
|
||||
];
|
||||
|
||||
// const constructionFeatureList: ProductDetails[] = []
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue