|
|
|
|
@@ -1,4 +1,5 @@
|
|
|
|
|
import React, { useEffect, useRef, useState } from "react";
|
|
|
|
|
import React, { useEffect, useMemo, useRef, useState } from "react";
|
|
|
|
|
import * as THREE from "three";
|
|
|
|
|
import {
|
|
|
|
|
AddIcon,
|
|
|
|
|
RemoveIcon,
|
|
|
|
|
@@ -9,6 +10,7 @@ import RenameInput from "../../../../../ui/inputs/RenameInput";
|
|
|
|
|
import { handleResize } from "../../../../../../functions/handleResizePannel";
|
|
|
|
|
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
|
|
|
|
import { useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore";
|
|
|
|
|
import { upsertProductOrEventApi } from "../../../../../../services/simulation/UpsertProductOrEventApi";
|
|
|
|
|
|
|
|
|
|
type TriggerProps = {
|
|
|
|
|
selectedPointData?: PointsScheme | undefined;
|
|
|
|
|
@@ -18,35 +20,215 @@ type TriggerProps = {
|
|
|
|
|
const Trigger = ({ selectedPointData, type }: TriggerProps) => {
|
|
|
|
|
const [currentAction, setCurrentAction] = useState<string | undefined>();
|
|
|
|
|
const { selectedProduct } = useSelectedProduct();
|
|
|
|
|
const { getActionByUuid } = useProductStore();
|
|
|
|
|
const { getActionByUuid, addTrigger, removeTrigger, updateTrigger, renameTrigger, getProductById } = useProductStore();
|
|
|
|
|
const [triggers, setTriggers] = useState<TriggerSchema[]>([]);
|
|
|
|
|
const [selectedTrigger, setSelectedTrigger] = useState<TriggerSchema | undefined>();
|
|
|
|
|
const [activeOption, setActiveOption] = useState("onComplete");
|
|
|
|
|
const [activeOption, setActiveOption] = useState<"onComplete" | "onStart" | "onStop" | "delay" | "onError">("onComplete");
|
|
|
|
|
const triggersContainerRef = useRef<HTMLDivElement>(null);
|
|
|
|
|
|
|
|
|
|
const email = localStorage.getItem('email')
|
|
|
|
|
const organization = (email!.split("@")[1]).split(".")[0];
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (!selectedPointData) return;
|
|
|
|
|
if (!selectedPointData || !selectedProduct) return;
|
|
|
|
|
|
|
|
|
|
let actionUuid: string | undefined;
|
|
|
|
|
|
|
|
|
|
if (type === 'Conveyor' || type === 'Vehicle' || type === 'Machine' || type === 'StorageUnit') {
|
|
|
|
|
setCurrentAction((selectedPointData as ConveyorPointSchema).action.actionUuid);
|
|
|
|
|
actionUuid = (selectedPointData as ConveyorPointSchema | VehiclePointSchema | MachinePointSchema | StoragePointSchema).action?.actionUuid;
|
|
|
|
|
} else if (type === 'RoboticArm') {
|
|
|
|
|
actionUuid = (selectedPointData as RoboticArmPointSchema).actions[0]?.actionUuid;
|
|
|
|
|
}
|
|
|
|
|
}, [selectedPointData]);
|
|
|
|
|
|
|
|
|
|
setCurrentAction(actionUuid);
|
|
|
|
|
}, [selectedPointData, selectedProduct, type]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const updateBackend = (
|
|
|
|
|
productName: string,
|
|
|
|
|
productId: string,
|
|
|
|
|
organization: string,
|
|
|
|
|
eventData: EventsSchema
|
|
|
|
|
) => {
|
|
|
|
|
upsertProductOrEventApi({
|
|
|
|
|
productName: productName,
|
|
|
|
|
productId: productId,
|
|
|
|
|
organization: organization,
|
|
|
|
|
eventDatas: eventData
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (!currentAction || !selectedProduct) return;
|
|
|
|
|
const action = getActionByUuid(selectedProduct.productId, currentAction);
|
|
|
|
|
setTriggers(action?.triggers || []);
|
|
|
|
|
setSelectedTrigger(action?.triggers[0] || undefined);
|
|
|
|
|
const actionTriggers = action?.triggers || [];
|
|
|
|
|
setTriggers(actionTriggers);
|
|
|
|
|
setSelectedTrigger(actionTriggers[0]);
|
|
|
|
|
}, [currentAction, selectedProduct]);
|
|
|
|
|
|
|
|
|
|
const addTrigger = (): void => {
|
|
|
|
|
const handleAddTrigger = () => {
|
|
|
|
|
if (!selectedProduct || !currentAction) return;
|
|
|
|
|
|
|
|
|
|
const newTrigger: TriggerSchema = {
|
|
|
|
|
triggerUuid: THREE.MathUtils.generateUUID(),
|
|
|
|
|
triggerName: `New Trigger ${triggers.length + 1}`,
|
|
|
|
|
triggerType: activeOption,
|
|
|
|
|
delay: 0,
|
|
|
|
|
triggeredAsset: null
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
addTrigger(selectedProduct.productId, currentAction, newTrigger);
|
|
|
|
|
setSelectedTrigger(newTrigger);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const removeTrigger = (triggerUuid: string): void => {
|
|
|
|
|
const handleRemoveTrigger = (triggerUuid: string) => {
|
|
|
|
|
if (!selectedProduct) return;
|
|
|
|
|
removeTrigger(selectedProduct.productId, triggerUuid);
|
|
|
|
|
if (selectedTrigger?.triggerUuid === triggerUuid) {
|
|
|
|
|
const remainingTriggers = triggers.filter(t => t.triggerUuid !== triggerUuid);
|
|
|
|
|
setSelectedTrigger(remainingTriggers[0]);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleTriggerRename = (triggerUuid: string, newName: string) => {
|
|
|
|
|
if (!selectedProduct) return;
|
|
|
|
|
renameTrigger(selectedProduct.productId, triggerUuid, newName);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleTriggerTypeChange = (option: string) => {
|
|
|
|
|
if (!selectedTrigger || !selectedProduct) return;
|
|
|
|
|
|
|
|
|
|
const validTypes: Array<TriggerSchema['triggerType']> = ["onComplete", "onStart", "onStop", "delay", "onError"];
|
|
|
|
|
if (!validTypes.includes(option as TriggerSchema['triggerType'])) return;
|
|
|
|
|
|
|
|
|
|
setActiveOption(option as TriggerSchema['triggerType']);
|
|
|
|
|
updateTrigger(selectedProduct.productId, selectedTrigger.triggerUuid, {
|
|
|
|
|
triggerType: option as TriggerSchema['triggerType']
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const triggeredModel = selectedTrigger?.triggeredAsset?.triggeredModel || { modelName: "Select Model", modelUuid: "" };
|
|
|
|
|
const triggeredPoint = selectedTrigger?.triggeredAsset?.triggeredPoint || { pointName: "Select Point", pointUuid: "" };
|
|
|
|
|
const triggeredAction = selectedTrigger?.triggeredAsset?.triggeredAction || { actionName: "Select Action", actionUuid: "" };
|
|
|
|
|
console.log('selectedTrigger: ', selectedTrigger);
|
|
|
|
|
console.log('triggeredAction: ', triggeredAction);
|
|
|
|
|
|
|
|
|
|
const modelOptions = getProductById(selectedProduct.productId)?.eventDatas || [];
|
|
|
|
|
|
|
|
|
|
const pointOptions: PointsScheme[] = useMemo(() => {
|
|
|
|
|
if (!triggeredModel.modelUuid) return [];
|
|
|
|
|
|
|
|
|
|
const model = modelOptions.find(m => m.modelUuid === triggeredModel.modelUuid);
|
|
|
|
|
if (!model) return [];
|
|
|
|
|
|
|
|
|
|
if ('points' in model) {
|
|
|
|
|
return (model as ConveyorEventSchema).points;
|
|
|
|
|
} else if ('point' in model) {
|
|
|
|
|
return [(model as VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema).point];
|
|
|
|
|
}
|
|
|
|
|
return [];
|
|
|
|
|
}, [triggeredModel.modelUuid, modelOptions]);
|
|
|
|
|
|
|
|
|
|
const actionOptions: any = useMemo(() => {
|
|
|
|
|
if (!triggeredPoint.pointUuid) return [];
|
|
|
|
|
const point = pointOptions.find((p) => p.uuid === triggeredPoint.pointUuid);
|
|
|
|
|
if (!point) return [];
|
|
|
|
|
|
|
|
|
|
if ('action' in point) {
|
|
|
|
|
const typedPoint = point as ConveyorPointSchema | VehiclePointSchema | MachinePointSchema | StoragePointSchema;
|
|
|
|
|
return typedPoint.action ? [typedPoint.action] : [];
|
|
|
|
|
} else if ('actions' in point) {
|
|
|
|
|
const typedPoint = point as RoboticArmPointSchema;
|
|
|
|
|
return typedPoint.actions;
|
|
|
|
|
}
|
|
|
|
|
return [];
|
|
|
|
|
}, [triggeredPoint.pointUuid, pointOptions]);
|
|
|
|
|
|
|
|
|
|
const handleModelSelect = (option: string, triggerUuid: string) => {
|
|
|
|
|
if (!selectedProduct) return;
|
|
|
|
|
|
|
|
|
|
const selectedModel = modelOptions.find(m => m.modelName === option);
|
|
|
|
|
if (!selectedModel) return;
|
|
|
|
|
|
|
|
|
|
const event = updateTrigger(selectedProduct.productId, triggerUuid, {
|
|
|
|
|
triggeredAsset: {
|
|
|
|
|
triggeredModel: {
|
|
|
|
|
modelName: selectedModel.modelName,
|
|
|
|
|
modelUuid: selectedModel.modelUuid
|
|
|
|
|
},
|
|
|
|
|
triggeredPoint: null,
|
|
|
|
|
triggeredAction: null
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (event) {
|
|
|
|
|
updateBackend(
|
|
|
|
|
selectedProduct.productName,
|
|
|
|
|
selectedProduct.productId,
|
|
|
|
|
organization,
|
|
|
|
|
event
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handlePointSelect = (option: string, triggerUuid: string) => {
|
|
|
|
|
if (!selectedProduct || !selectedTrigger) return;
|
|
|
|
|
|
|
|
|
|
const pointUuid = pointOptions.find(p => `Point ${p.uuid.slice(0, 5)}` === option)?.uuid;
|
|
|
|
|
|
|
|
|
|
if (!pointUuid) return;
|
|
|
|
|
|
|
|
|
|
if (selectedTrigger.triggeredAsset?.triggeredModel) {
|
|
|
|
|
const event = updateTrigger(selectedProduct.productId, triggerUuid, {
|
|
|
|
|
triggeredAsset: {
|
|
|
|
|
...selectedTrigger.triggeredAsset,
|
|
|
|
|
triggeredPoint: {
|
|
|
|
|
pointName: option,
|
|
|
|
|
pointUuid: pointUuid
|
|
|
|
|
},
|
|
|
|
|
triggeredAction: null
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (event) {
|
|
|
|
|
updateBackend(
|
|
|
|
|
selectedProduct.productName,
|
|
|
|
|
selectedProduct.productId,
|
|
|
|
|
organization,
|
|
|
|
|
event
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleActionSelect = (option: string, triggerUuid: string) => {
|
|
|
|
|
if (!selectedProduct || !selectedTrigger) return;
|
|
|
|
|
|
|
|
|
|
const selectedAction = actionOptions.find((a: any) => a.actionName === option);
|
|
|
|
|
|
|
|
|
|
if (!selectedAction) return;
|
|
|
|
|
|
|
|
|
|
if (selectedTrigger.triggeredAsset?.triggeredPoint) {
|
|
|
|
|
const event = updateTrigger(selectedProduct.productId, triggerUuid, {
|
|
|
|
|
triggeredAsset: {
|
|
|
|
|
...selectedTrigger.triggeredAsset,
|
|
|
|
|
triggeredAction: {
|
|
|
|
|
actionName: option,
|
|
|
|
|
actionUuid: selectedAction.actionUuid
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (event) {
|
|
|
|
|
updateBackend(
|
|
|
|
|
selectedProduct.productName,
|
|
|
|
|
selectedProduct.productId,
|
|
|
|
|
organization,
|
|
|
|
|
event
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="trigger-wrapper">
|
|
|
|
|
@@ -54,8 +236,9 @@ const Trigger = ({ selectedPointData, type }: TriggerProps) => {
|
|
|
|
|
<div className="title">Trigger</div>
|
|
|
|
|
<button
|
|
|
|
|
className="add-button"
|
|
|
|
|
onClick={addTrigger}
|
|
|
|
|
onClick={handleAddTrigger}
|
|
|
|
|
style={{ cursor: "pointer" }}
|
|
|
|
|
disabled={!currentAction}
|
|
|
|
|
>
|
|
|
|
|
<AddIcon /> Add
|
|
|
|
|
</button>
|
|
|
|
|
@@ -73,13 +256,19 @@ const Trigger = ({ selectedPointData, type }: TriggerProps) => {
|
|
|
|
|
className={`list-item ${selectedTrigger?.triggerUuid === trigger.triggerUuid ? "active" : ""}`}
|
|
|
|
|
onClick={() => setSelectedTrigger(trigger)}
|
|
|
|
|
>
|
|
|
|
|
<button className="value" onClick={() => { }}>
|
|
|
|
|
<RenameInput value={trigger.triggerName} onRename={() => { }} />
|
|
|
|
|
<button className="value">
|
|
|
|
|
<RenameInput
|
|
|
|
|
value={trigger.triggerName}
|
|
|
|
|
onRename={(newName) => handleTriggerRename(trigger.triggerUuid, newName)}
|
|
|
|
|
/>
|
|
|
|
|
</button>
|
|
|
|
|
{triggers.length > 1 && (
|
|
|
|
|
<button
|
|
|
|
|
className="remove-button"
|
|
|
|
|
onClick={() => removeTrigger(trigger.triggerUuid)}
|
|
|
|
|
onClick={(e) => {
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
handleRemoveTrigger(trigger.triggerUuid);
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<RemoveIcon />
|
|
|
|
|
</button>
|
|
|
|
|
@@ -95,35 +284,39 @@ const Trigger = ({ selectedPointData, type }: TriggerProps) => {
|
|
|
|
|
<ResizeHeightIcon />
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="trigger-item">
|
|
|
|
|
<div className="trigger-name">{selectedTrigger?.triggerName}</div>
|
|
|
|
|
<LabledDropdown
|
|
|
|
|
label="Trigger Type"
|
|
|
|
|
defaultOption={activeOption}
|
|
|
|
|
options={["onComplete", "onStart", "onStop", "delay"]}
|
|
|
|
|
onSelect={(option) => setActiveOption(option)}
|
|
|
|
|
/>
|
|
|
|
|
<div className="trigger-options">
|
|
|
|
|
|
|
|
|
|
{selectedTrigger && (
|
|
|
|
|
<div className="trigger-item">
|
|
|
|
|
<div className="trigger-name">{selectedTrigger.triggerName}</div>
|
|
|
|
|
<LabledDropdown
|
|
|
|
|
label="Triggered Object"
|
|
|
|
|
defaultOption={triggeredModel.modelName}
|
|
|
|
|
options={[]}
|
|
|
|
|
onSelect={(option) => { }}
|
|
|
|
|
/>
|
|
|
|
|
<LabledDropdown
|
|
|
|
|
label="Triggered Point"
|
|
|
|
|
defaultOption={triggeredPoint.pointName}
|
|
|
|
|
options={[]}
|
|
|
|
|
onSelect={(option) => { }}
|
|
|
|
|
/>
|
|
|
|
|
<LabledDropdown
|
|
|
|
|
label="Triggered Action"
|
|
|
|
|
defaultOption={triggeredAction.actionName}
|
|
|
|
|
options={[]}
|
|
|
|
|
onSelect={(option) => { }}
|
|
|
|
|
label="Trigger Type"
|
|
|
|
|
defaultOption={selectedTrigger.triggerType}
|
|
|
|
|
options={["onComplete", "onStart", "onStop", "delay", "onError"]}
|
|
|
|
|
onSelect={handleTriggerTypeChange}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<div className="trigger-options">
|
|
|
|
|
<LabledDropdown
|
|
|
|
|
label="Triggered Object"
|
|
|
|
|
defaultOption={triggeredModel.modelName}
|
|
|
|
|
options={[...modelOptions.map((option) => (option.modelName))]}
|
|
|
|
|
onSelect={(option) => { handleModelSelect(option, selectedTrigger.triggerUuid) }}
|
|
|
|
|
/>
|
|
|
|
|
<LabledDropdown
|
|
|
|
|
label="Triggered Point"
|
|
|
|
|
defaultOption={triggeredPoint.pointName}
|
|
|
|
|
options={[...pointOptions.map((option) => (`Point ${option.uuid.slice(0, 5)}`))]}
|
|
|
|
|
onSelect={(option) => { handlePointSelect(option, selectedTrigger.triggerUuid) }}
|
|
|
|
|
/>
|
|
|
|
|
<LabledDropdown
|
|
|
|
|
label="Triggered Action"
|
|
|
|
|
defaultOption={triggeredAction.actionName}
|
|
|
|
|
options={[...actionOptions.map((option: any) => (option.actionName))]}
|
|
|
|
|
onSelect={(option) => { handleActionSelect(option, selectedTrigger.triggerUuid) }}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
|