diff --git a/cbpi4ui/CBPI-ConfigForTesting/config.7z b/cbpi4ui/CBPI-ConfigForTesting/config.7z
new file mode 100644
index 0000000..24b78ff
Binary files /dev/null and b/cbpi4ui/CBPI-ConfigForTesting/config.7z differ
diff --git a/cbpi4ui/src/components/dashboard/DashboardContext.js b/cbpi4ui/src/components/dashboard/DashboardContext.js
index 223a9e4..676d75c 100644
--- a/cbpi4ui/src/components/dashboard/DashboardContext.js
+++ b/cbpi4ui/src/components/dashboard/DashboardContext.js
@@ -105,7 +105,6 @@ export const DashboardProvider = ({ children }) => {
};
const update_prop = (id, key, value) => {
-
const data = [...elements2];
const index = data.findIndex((e) => e.id === selected.id);
data[index].props[key] = value;
@@ -114,10 +113,28 @@ export const DashboardProvider = ({ children }) => {
};
- const update_path_condition = (id, data) => {
+ const update_path_condition = (id, data, direction) => {
+ const index = pathes.findIndex((e) => e.id === id);
+ const temp_pathes = [...pathes];
+ if(direction === "left")
+ {
+ temp_pathes[index].condition.left = data;
+ }
+ if(direction === "right")
+ {
+ temp_pathes[index].condition.right = data;
+ }
+ setPathes([...temp_pathes]);
+ };
+
+ // New method for updating path animation condition based on boolean expression
+ const update_path_condition_exp = (id, direction, data) => {
const index = pathes.findIndex((e) => e.id === id);
const temp_pathes = [...pathes];
- temp_pathes[index].condition = data;
+ if(direction === "leftExpression")
+ temp_pathes[index].condition.leftExpression = data;
+ if(direction=== "rightExpression")
+ temp_pathes[index].condition.rightExpression = data;
setPathes([...temp_pathes]);
};
@@ -206,6 +223,7 @@ export const DashboardProvider = ({ children }) => {
update_default_prop,
update_prop,
update_path_condition,
+ update_path_condition_exp, // New Method added for the boolean expression
update_coordinates,
setDraggable,
update_path,
diff --git a/cbpi4ui/src/components/dashboard/DashboardLayer.js b/cbpi4ui/src/components/dashboard/DashboardLayer.js
index 8dbcfc7..4933581 100644
--- a/cbpi4ui/src/components/dashboard/DashboardLayer.js
+++ b/cbpi4ui/src/components/dashboard/DashboardLayer.js
@@ -152,9 +152,10 @@ const PathSettingsItem = ({ item, checked, handleToggle }) => {
-
);
+
+
};
const PathSettings = () => {
@@ -176,14 +177,19 @@ const PathSettings = () => {
const currentIndex = checked.indexOf(value);
const newChecked = [...checked];
- if (currentIndex === -1) {
+ if (currentIndex === -1)
+ {
newChecked.push(value);
- } else {
+ }
+ else
+ {
newChecked.splice(currentIndex, 1);
}
setChecked(newChecked);
- actions.update_path_condition(selected_id, {left: newChecked, right: checkedRight});
- } else {
+ actions.update_path_condition(selected_id, {left: newChecked, right: checkedRight},direction);
+ }
+ else
+ {
const currentIndex = checkedRight.indexOf(value);
const newChecked = [...checkedRight];
@@ -193,7 +199,19 @@ const PathSettings = () => {
newChecked.splice(currentIndex, 1);
}
setCheckedRight(newChecked);
- actions.update_path_condition(selected_id, {left: checked, right: newChecked});
+ actions.update_path_condition(selected_id, {left: checked, right: newChecked},direction);
+ }
+ };
+
+ // Handle change of the boolean expression for path animation.
+ const data = useModel(selected_id);
+ const handleChange = (e, direction) => {
+ if (direction === "left")
+ {
+ actions.update_path_condition_exp(selected_id, "leftExpression", e.target.value);
+ }
+ else{
+ actions.update_path_condition_exp(selected_id, "rightExpression", e.target.value);
}
};
@@ -205,6 +223,11 @@ const PathSettings = () => {
return "";
}
+ const item = state.pathes.find((e) => e.id === selected_id);
+
+
+// Add a TextField for adding the booleanExpression
+ var helperTextExpression = "sample expression : (\"actor1\" && \"actor2\") || (\"actor2\" && \"actor3\") \n don't forget the quote";
return (
<>
{
))}
+
handleChange(e, "left")} />
+
Flow Right
{actor.map((item) => (
handleToggle(id, "right")} />
))}
+ handleChange(e, "right")} />
>
);
diff --git a/cbpi4ui/src/components/dashboard/widgets/Path.js b/cbpi4ui/src/components/dashboard/widgets/Path.js
index f7b3998..a5daec7 100644
--- a/cbpi4ui/src/components/dashboard/widgets/Path.js
+++ b/cbpi4ui/src/components/dashboard/widgets/Path.js
@@ -10,9 +10,10 @@ export const Path = ({ id, coordinates, condition = null, stroke = 10, max_x = 4
const [dragging, setDragging] = useState(false);
const [origin, setOrigin] = useState({ x: 0, y: 0 });
const [active, setActive] = useState(false);
- const [flowLeft, setFlowLeft] = useState(false)
- const [flowRight, setFlowRight] = useState(false)
-
+ const [flowLeft, setFlowLeft] = useState(false);
+ const [flowRight, setFlowRight] = useState(false) ;
+ const[rightExpression, SetFlowExpRight] = useState(false); // rightExpression and useState Hook for SetFlowRightExp
+ const[leftExpression, SetFlowExpLeft] = useState(false); // leftExpression and useState Hook for SetFlowleftExp
useEffect(() => {
@@ -21,18 +22,106 @@ export const Path = ({ id, coordinates, condition = null, stroke = 10, max_x = 4
return obj;
}, {});
+ // Add a cache of actor states by name, used for calculate the expression
+ const actor_cacheFromName = actor.reduce((obj, item) => {
+ obj[item.name] = item.state;
+ return obj;
+ }, {});
+
const p = state.pathes.find((e) => e.id === id);
- if (!p.condition?.left || p.condition?.left.length === 0) {
- setFlowLeft(false)
- } else {
- setFlowLeft(p.condition?.left.reduce((sum, next) => sum && actor_cache[next], true));
- }
- if (!p.condition?.right || p.condition?.right.length === 0) {
- setFlowRight(false)
- } else {
+
+ // Add a control to check if a boolean expression is added in path properties
+ // If an expression is present in the left or right direction, we don't check the checked value for calculating animation state.
+ if((!p.condition?.leftExpression || p.condition?.leftExpression.length === 0)
+ && (!p.condition?.rightExpression || p.condition?.rightExpression.length === 0))
+ {
+ if (!p.condition?.left || p.condition?.left.length === 0)
+ {
+ setFlowLeft(false)
+ }
+ else
+ {
+ setFlowLeft(p.condition?.left.reduce((sum, next) => sum && actor_cache[next], true));
+ }
+
+ if (!p.condition?.right || p.condition?.right.length === 0)
+ {
+ setFlowRight(false)
+ }
+ else
+ {
setFlowRight(p.condition?.right.reduce((sum, next) => sum && actor_cache[next], true));
+ }
}
+
+ // If the leftexpression value is entered in the path property.
+ // TODO : variable count optimisation
+ if(p.condition?.leftExpression)
+ {
+ // split the expression
+ var actorsId = p.condition.leftExpression.split("\"");
+ var bStateAction = false;
+ var boolExpressionLeft;
+ boolExpressionLeft = p.condition.leftExpression
+
+ // For each part of the string, we check if this is an actor name, if so we replace the actor name by the resulting state.
+ for(var actorId of actorsId)
+ {
+ // Check if we process an actorId
+ if(typeof actor_cacheFromName[actorId] === "boolean")
+ {
+ boolExpressionLeft = boolExpressionLeft.replace('\"'+ actorId + '\"', actor_cacheFromName[actorId].toString());
+ }
+ }
+ // Evaluation of the expression
+ // TODO : in order to be safer, plane to use something else than eval (in the craftbeerpi context, i'm not sur it can cause any security problem : TO BE CONFIRMED)
+ try
+ {
+ bStateAction = eval(boolExpressionLeft);
+ console.trace("Right, Eval de : " + boolExpressionLeft + " Result = " + bStateAction.toString());
+ setFlowLeft(bStateAction, true);
+ }
+ catch (error)
+ {
+ console.error("Evaluation of boolean expression failure : check your boolean expression for path animation");
+ }
+ }
+
+ // If the rightExpression value is entered in the path property.
+ // TODO : variable count optimisation
+ if(p.condition?.rightExpression)
+ {
+ // split the expression
+ var actorsId =p.condition.rightExpression.split("\"");
+ var bStateAction = false;
+ var boolExpressionRight;
+ boolExpressionRight = p.condition.rightExpression
+
+ // For each part of the string, we check if this is an actor name, if so we replace the actor name by the resulting state.
+ for(var actorId of actorsId)
+ {
+ // Check if we process an actorId
+ if(typeof actor_cacheFromName[actorId] === "boolean") // Check if this is an actor ID or just an operator.
+ {
+ boolExpressionRight.replace('\"' + actorId + '\"', actor_cacheFromName[actorId].toString());
+ }
+ }
+ // Evaluation of the expression
+ // TODO : in order to be safer, plane to use something else than eval (in the craftbeerpi context, i'm not sur it can cause any security problem : TO BE CONFIRMED)
+ bStateAction = eval(boolExpressionRight);
+ if (bStateAction != undefined)
+ {
+ console.trace("Left, Eval de : " + boolExpressionLeft + " Result = " + bStateAction.toString());
+ setFlowRight(bStateAction, true);
+ }
+ else
+ {
+ console.trace("Evaluation of boolean expression failure : check your boolean expression for path animation");
+ }
+ }
+
+
}, [actor]);
const draggable = state.draggable;
diff --git a/cbpi4ui/src/components/dashboard/widgets/config.js b/cbpi4ui/src/components/dashboard/widgets/config.js
index 21e230a..26c3877 100644
--- a/cbpi4ui/src/components/dashboard/widgets/config.js
+++ b/cbpi4ui/src/components/dashboard/widgets/config.js
@@ -3,7 +3,7 @@ import QueryBuilderIcon from '@material-ui/icons/QueryBuilder';
import ShowChartIcon from '@material-ui/icons/ShowChart';
import TextFieldsIcon from '@material-ui/icons/TextFields';
import ToggleOffIcon from '@material-ui/icons/ToggleOff';
-import { CBPiCalculatorIcon, CBPiControlIcon, CBPiKettle, CBPiKettle2Icon, CBPiLedIcon, CBPiLiquidIcon, CBPiSensorIcon, CBPiSVGIcon, CBPiTankIcon, CBPiThermometerIcon } from '../../util/icons/CBPiSensorIcon';
+import { CBPiCalculatorIcon, CBPiControlIcon, CBPiKettle, CBPiKettle2Icon, CBPiLedIcon, CBPiLiquidIcon, CBPiPipeIcon, CBPiSensorIcon, CBPiSVGIcon, CBPiTankIcon, CBPiThermometerIcon } from '../../util/icons/CBPiSensorIcon';
import { DashboardButton } from "./Button";
import { Calculator } from "./Calculator";
import Chart from "./Chart";
@@ -12,6 +12,7 @@ import CustomSVG from "./CustomSVG";
import { KettleControl } from "./KettleControl";
import { Led } from "./Led";
import { Liquid } from './Liquid';
+import {Path} from './Path';
import { SensorData } from "./SensorData";
import Steps from "./Steps";
import KettleSVG from "./svg/kettle.svg";
@@ -163,9 +164,7 @@ export const widget_list = [
{ name: "height", default: 40, type: "number" },
{ name: "sensor", default: "", type: "sensor" }
],
- }
-
-
+ },
];