Merge remote-tracking branch 'origin/v2' into v2-ui

This commit is contained in:
Vishnu 2025-05-02 18:52:30 +05:30
commit fb0da32504
32 changed files with 1165 additions and 647 deletions

View File

@ -35,7 +35,7 @@ const ActionsList: React.FC<ActionsListProps> = ({
const handleRenameAction = (newName: string) => {
if (!selectedAction.actionId) return;
const event = renameAction(selectedAction.actionId, newName);
const event = renameAction(selectedProduct.productId, selectedAction.actionId, newName);
if (event) {
upsertProductOrEventApi({

View File

@ -72,7 +72,7 @@ function ConveyorMechanics() {
const validOption = option as | "default" | "spawn" | "swap" | "delay" | "despawn";
setActiveOption(validOption);
const event = updateAction(selectedPointData.action.actionUuid, {
const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, {
actionType: validOption,
});
@ -88,7 +88,7 @@ function ConveyorMechanics() {
const handleRenameAction = (newName: string) => {
if (!selectedEventData || !selectedPointData) return;
const event = updateAction(selectedPointData.action.actionUuid, { actionName: newName });
const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, { actionName: newName });
if (event) {
updateBackend(
@ -102,7 +102,7 @@ function ConveyorMechanics() {
const handleSpawnCountChange = (value: string) => {
if (!selectedEventData || !selectedPointData) return;
const event = updateAction(selectedPointData.action.actionUuid, {
const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, {
spawnCount: value === "inherit" ? "inherit" : parseFloat(value),
});
@ -118,7 +118,7 @@ function ConveyorMechanics() {
const handleSpawnIntervalChange = (value: string) => {
if (!selectedEventData || !selectedPointData) return;
const event = updateAction(selectedPointData.action.actionUuid, {
const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, {
spawnInterval: value === "inherit" ? "inherit" : parseFloat(value),
});
@ -134,7 +134,7 @@ function ConveyorMechanics() {
const handleMaterialSelect = (material: string) => {
if (!selectedEventData || !selectedPointData) return;
const event = updateAction(selectedPointData.action.actionUuid, { material });
const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, { material });
if (event) {
updateBackend(
@ -148,7 +148,7 @@ function ConveyorMechanics() {
const handleDelayChange = (value: string) => {
if (!selectedEventData || !selectedPointData) return;
const event = updateAction(selectedPointData.action.actionUuid, {
const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, {
delay: value === "inherit" ? "inherit" : parseFloat(value),
});
@ -271,7 +271,7 @@ function ConveyorMechanics() {
</div>
</div>
<div className="tirgger">
<Trigger />
<Trigger selectedPointData={selectedPointData as any} type= {'Conveyor'}/>
</div>
</section>
</>

View File

@ -6,6 +6,7 @@ import { useSelectedEventData, useSelectedProduct } from "../../../../../../stor
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import ProcessAction from "../actions/ProcessAction";
import ActionsList from "../components/ActionsList";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/UpsertProductOrEventApi";
function MachineMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "process">("default");
@ -14,6 +15,9 @@ function MachineMechanics() {
const { getPointByUuid, updateAction } = useProductStore();
const { selectedProduct } = useSelectedProduct();
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
useEffect(() => {
if (selectedEventData) {
const point = getPointByUuid(
@ -28,31 +32,54 @@ function MachineMechanics() {
}
}, [selectedProduct, selectedEventData, getPointByUuid]);
const updateBackend = (
productName: string,
productId: string,
organization: string,
eventData: EventsSchema
) => {
upsertProductOrEventApi({
productName: productName,
productId: productId,
organization: organization,
eventDatas: eventData
})
}
const handleActionTypeChange = (option: string) => {
if (!selectedEventData || !selectedPointData) return;
const validOption = option as "process";
setActiveOption(validOption);
updateAction(selectedPointData.action.actionUuid, {
const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, {
actionType: validOption,
});
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
};
const handleRenameAction = (newName: string) => {
if (!selectedPointData) return;
updateAction(selectedPointData.action.actionUuid, { actionName: newName });
const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, { actionName: newName });
};
const handleProcessTimeChange = (value: string) => {
if (!selectedPointData) return;
updateAction(selectedPointData.action.actionUuid, {
const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, {
processTime: parseFloat(value),
});
};
const handleMaterialSelect = (material: string) => {
if (!selectedPointData) return;
updateAction(selectedPointData.action.actionUuid, {
const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, {
swapMaterial: material,
});
};

View File

@ -59,7 +59,7 @@ function RoboticArmMechanics() {
const handleRenameAction = (newName: string) => {
if (!selectedAction.actionId) return;
const event = updateAction(selectedAction.actionId, { actionName: newName });
const event = updateAction(selectedProduct.productId, selectedAction.actionId, { actionName: newName });
if (selectedPointData) {
const updatedActions = selectedPointData.actions.map((action) =>
@ -101,7 +101,7 @@ function RoboticArmMechanics() {
if (!selectedAction.actionId || !selectedPointData) return;
const [x, y, z] = value.split(",").map(Number);
const event = updateAction(selectedAction.actionId, {
const event = updateAction(selectedProduct.productId, selectedAction.actionId, {
process: {
startPoint: [x, y, z] as [number, number, number],
endPoint: selectedPointData.actions.find((a) => a.actionUuid === selectedAction.actionId)?.process.endPoint || null,
@ -122,7 +122,7 @@ function RoboticArmMechanics() {
if (!selectedAction.actionId || !selectedPointData) return;
const [x, y, z] = value.split(",").map(Number);
const event = updateAction(selectedAction.actionId, {
const event = updateAction(selectedProduct.productId, selectedAction.actionId, {
process: {
startPoint: selectedPointData.actions.find((a) => a.actionUuid === selectedAction.actionId)?.process.startPoint || null,
endPoint: [x, y, z] as [number, number, number],
@ -181,7 +181,7 @@ function RoboticArmMechanics() {
const handleDeleteAction = (actionUuid: string) => {
if (!selectedPointData) return;
const event = removeAction(actionUuid);
const event = removeAction(selectedProduct.productId, actionUuid);
if (event) {
updateBackend(

View File

@ -6,6 +6,7 @@ import { useSelectedEventData, useSelectedProduct } from "../../../../../../stor
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import StorageAction from "../actions/StorageAction";
import ActionsList from "../components/ActionsList";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/UpsertProductOrEventApi";
function StorageMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "store" | "spawn">("default");
@ -14,6 +15,9 @@ function StorageMechanics() {
const { getPointByUuid, updateAction } = useProductStore();
const { selectedProduct } = useSelectedProduct();
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
useEffect(() => {
if (selectedEventData) {
const point = getPointByUuid(
@ -28,26 +32,67 @@ function StorageMechanics() {
}
}, [selectedProduct, selectedEventData, getPointByUuid]);
const updateBackend = (
productName: string,
productId: string,
organization: string,
eventData: EventsSchema
) => {
upsertProductOrEventApi({
productName: productName,
productId: productId,
organization: organization,
eventDatas: eventData
})
}
const handleActionTypeChange = (option: string) => {
if (!selectedEventData || !selectedPointData) return;
const validOption = option as "store" | "spawn";
setActiveOption(validOption);
updateAction(selectedPointData.action.actionUuid, {
const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, {
actionType: validOption,
});
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
};
const handleRenameAction = (newName: string) => {
if (!selectedPointData) return;
updateAction(selectedPointData.action.actionUuid, { actionName: newName });
const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, { actionName: newName });
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
};
const handleCapacityChange = (value: string) => {
if (!selectedPointData) return;
updateAction(selectedPointData.action.actionUuid, {
const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, {
storageCapacity: parseInt(value),
});
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
};
// Get current values from store

View File

@ -10,6 +10,7 @@ import {
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import TravelAction from "../actions/TravelAction";
import ActionsList from "../components/ActionsList";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/UpsertProductOrEventApi";
function VehicleMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "travel">("default");
@ -18,8 +19,11 @@ function VehicleMechanics() {
const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction } = useProductStore();
const { selectedProduct } = useSelectedProduct();
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
useEffect(() => {
if (selectedEventData) {
if (selectedEventData && selectedEventData.data.type === 'vehicle') {
const point = getPointByUuid(
selectedProduct.productId,
selectedEventData.data.modelUuid,
@ -33,11 +37,34 @@ function VehicleMechanics() {
}
}, [selectedProduct, selectedEventData, getPointByUuid]);
const updateBackend = (
productName: string,
productId: string,
organization: string,
eventData: EventsSchema
) => {
upsertProductOrEventApi({
productName: productName,
productId: productId,
organization: organization,
eventDatas: eventData
})
}
const handleSpeedChange = (value: string) => {
if (!selectedEventData) return;
updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, {
const event = updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, {
speed: parseFloat(value),
});
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
};
const handleActionTypeChange = (option: string) => {
@ -45,28 +72,64 @@ function VehicleMechanics() {
const validOption = option as "travel";
setActiveOption(validOption);
updateAction(selectedPointData.action.actionUuid, {
const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, {
actionType: validOption,
});
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
};
const handleRenameAction = (newName: string) => {
if (!selectedPointData) return;
updateAction(selectedPointData.action.actionUuid, { actionName: newName });
const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, { actionName: newName });
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
};
const handleLoadCapacityChange = (value: string) => {
if (!selectedPointData) return;
updateAction(selectedPointData.action.actionUuid, {
const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, {
loadCapacity: parseFloat(value),
});
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
};
const handleUnloadDurationChange = (value: string) => {
if (!selectedPointData) return;
updateAction(selectedPointData.action.actionUuid, {
const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, {
unLoadDuration: parseFloat(value),
});
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
};
const handlePickPointChange = (value: string) => {

View File

@ -1,4 +1,4 @@
import React, { useRef, useState } from "react";
import React, { useEffect, useRef, useState } from "react";
import {
AddIcon,
RemoveIcon,
@ -7,38 +7,47 @@ import {
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
import RenameInput from "../../../../../ui/inputs/RenameInput";
import { handleResize } from "../../../../../../functions/handleResizePannel";
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import { useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore";
const Trigger: React.FC = () => {
// State to hold the list of triggers
const [triggers, setTriggers] = useState<string[]>(["Trigger 1"]);
const [selectedTrigger, setSelectedTrigger] = useState<string>("Trigger 1");
type TriggerProps = {
selectedPointData?: PointsScheme | undefined;
type?: 'Conveyor' | 'Vehicle' | 'RoboticArm' | 'Machine' | 'StorageUnit';
};
const Trigger = ({ selectedPointData, type }: TriggerProps) => {
const [currentAction, setCurrentAction] = useState<string | undefined>();
const { selectedProduct } = useSelectedProduct();
const { getActionByUuid } = useProductStore();
const [triggers, setTriggers] = useState<TriggerSchema[]>([]);
const [selectedTrigger, setSelectedTrigger] = useState<TriggerSchema | undefined>();
const [activeOption, setActiveOption] = useState("onComplete");
const triggersContainerRef = useRef<HTMLDivElement>(null);
// States for dropdowns
const [triggeredModel, setTriggeredModel] = useState<string[]>([]);
const [triggeredPoint, setTriggeredPoint] = useState<string[]>([]);
const [triggeredAction, setTriggeredAction] = useState<string[]>([]);
useEffect(() => {
if (!selectedPointData) return;
if (type === 'Conveyor' || type === 'Vehicle' || type === 'Machine' || type === 'StorageUnit') {
setCurrentAction((selectedPointData as ConveyorPointSchema).action.actionUuid);
}
}, [selectedPointData]);
useEffect(() => {
if (!currentAction || !selectedProduct) return;
const action = getActionByUuid(selectedProduct.productId, currentAction);
setTriggers(action?.triggers || []);
setSelectedTrigger(action?.triggers[0] || undefined);
}, [currentAction, selectedProduct]);
// Function to handle adding a new trigger
const addTrigger = (): void => {
const newTrigger = `Trigger ${triggers.length + 1}`;
setTriggers([...triggers, newTrigger]); // Add new trigger to the state
// Initialize the states for the new trigger
setTriggeredModel([...triggeredModel, ""]);
setTriggeredPoint([...triggeredPoint, ""]);
setTriggeredAction([...triggeredAction, ""]);
};
// Function to handle removing a trigger
const removeTrigger = (index: number): void => {
setTriggers(triggers.filter((_, i) => i !== index)); // Remove trigger by index
setTriggeredModel(triggeredModel.filter((_, i) => i !== index));
setTriggeredPoint(triggeredPoint.filter((_, i) => i !== index));
setTriggeredAction(triggeredAction.filter((_, i) => i !== index));
const removeTrigger = (triggerUuid: string): void => {
};
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: "" };
return (
<div className="trigger-wrapper">
<div className="header">
@ -58,21 +67,19 @@ const Trigger: React.FC = () => {
style={{ height: "120px" }}
>
<div className="list-container">
{triggers.map((trigger: any, index: number) => (
{triggers.map((trigger) => (
<div
key={index}
className={`list-item ${
selectedTrigger === trigger ? "active" : ""
}`}
key={trigger.triggerUuid}
className={`list-item ${selectedTrigger?.triggerUuid === trigger.triggerUuid ? "active" : ""}`}
onClick={() => setSelectedTrigger(trigger)}
>
<button className="value" onClick={() => { }}>
<RenameInput value={trigger} onRename={() => {}} />
<RenameInput value={trigger.triggerName} onRename={() => { }} />
</button>
{triggers.length > 1 && (
<button
className="remove-button"
onClick={() => removeTrigger(index)}
onClick={() => removeTrigger(trigger.triggerUuid)}
>
<RemoveIcon />
</button>
@ -89,9 +96,9 @@ const Trigger: React.FC = () => {
</button>
</div>
<div className="trigger-item">
<div className="trigger-name">{selectedTrigger}</div>
<div className="trigger-name">{selectedTrigger?.triggerName}</div>
<LabledDropdown
label="Trigger on"
label="Trigger Type"
defaultOption={activeOption}
options={["onComplete", "onStart", "onStop", "delay"]}
onSelect={(option) => setActiveOption(option)}
@ -99,33 +106,21 @@ const Trigger: React.FC = () => {
<div className="trigger-options">
<LabledDropdown
label="Triggered Object"
defaultOption={triggeredModel[0] || "Select Model"}
options={["Model 1", "Model 2", "Model 3"]}
onSelect={(option) => {
const newModel = [...triggeredModel];
newModel[0] = option;
setTriggeredModel(newModel);
}}
defaultOption={triggeredModel.modelName}
options={[]}
onSelect={(option) => { }}
/>
<LabledDropdown
label="Triggered Point"
defaultOption={triggeredPoint[0] || "Select Point"}
options={["Point 1", "Point 2", "Point 3"]}
onSelect={(option) => {
const newPoint = [...triggeredPoint];
newPoint[0] = option;
setTriggeredPoint(newPoint);
}}
defaultOption={triggeredPoint.pointName}
options={[]}
onSelect={(option) => { }}
/>
<LabledDropdown
label="Triggered Action"
defaultOption={triggeredAction[0] || "Select Action"}
options={["Action 1", "Action 2", "Action 3"]}
onSelect={(option) => {
const newAction = [...triggeredAction];
newAction[0] = option;
setTriggeredAction(newAction);
}}
defaultOption={triggeredAction.actionName}
options={[]}
onSelect={(option) => { }}
/>
</div>
</div>

View File

@ -187,7 +187,7 @@ function processLoadedModel(
},
]);
if (item.eventData.type === "vehicle") {
if (item.eventData.type === "Vehicle") {
const vehicleEvent: VehicleEventSchema = {
modelUuid: item.modelUuid,
modelName: item.modelName,
@ -202,7 +202,7 @@ function processLoadedModel(
rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0],
action: {
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Vehicle Action",
actionName: "Action 1",
actionType: "travel",
unLoadDuration: 5,
loadCapacity: 10,
@ -254,7 +254,7 @@ function processLoadedModel(
rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0],
action: {
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Process Action",
actionName: "Action 1",
actionType: "process",
processTime: 10,
swapMaterial: "material-id",
@ -279,7 +279,7 @@ function processLoadedModel(
actions: [
{
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Pick and Place",
actionName: "Action 1",
actionType: "pickAndPlace",
process: {
startPoint: [0, 0, 0],

View File

@ -186,22 +186,59 @@ async function handleModelLoad(
state: "idle",
type: 'transfer',
speed: 1,
points: data.points.map((point: THREE.Vector3, index: number) => ({
points: data.points.map((point: THREE.Vector3, index: number) => {
const triggers: TriggerSchema[] = [];
if (data.points && index < data.points.length - 1) {
triggers.push({
triggerUuid: THREE.MathUtils.generateUUID(),
triggerName: `Trigger 1`,
triggerType: "onComplete",
delay: 0,
triggeredAsset: {
triggeredModel: {
modelName: newFloorItem.modelName,
modelUuid: newFloorItem.modelUuid
},
triggeredPoint: {
pointName: `Point`,
pointUuid: ""
},
triggeredAction: {
actionName: `Action 1`,
actionUuid: ""
}
}
});
}
return {
uuid: THREE.MathUtils.generateUUID(),
position: [point.x, point.y, point.z],
rotation: [0, 0, 0],
action: {
actionUuid: THREE.MathUtils.generateUUID(),
actionName: `Action ${index}`,
actionName: `Action 1`,
actionType: 'default',
material: 'Default Material',
delay: 0,
spawnInterval: 5,
spawnCount: 1,
triggers: []
triggers: triggers
}
}))
};
})
};
for (let i = 0; i < ConveyorEvent.points.length - 1; i++) {
const currentPoint = ConveyorEvent.points[i];
const nextPoint = ConveyorEvent.points[i + 1];
if (currentPoint.action.triggers.length > 0) {
currentPoint.action.triggers[0].triggeredAsset!.triggeredPoint.pointUuid = nextPoint.uuid;
currentPoint.action.triggers[0].triggeredAsset!.triggeredAction!.actionUuid = nextPoint.action.actionUuid;
}
}
addEvent(ConveyorEvent);
eventData.points = ConveyorEvent.points.map(point => ({
uuid: point.uuid,

View File

@ -9,6 +9,7 @@ import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifie
import { useEventsStore } from "../../../../store/simulation/useEventsStore";
import { useProductStore } from "../../../../store/simulation/useProductStore";
import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore";
import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi";
function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, duplicatedObjects, setDuplicatedObjects, selectionGroup, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) {
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
@ -16,10 +17,28 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
const { toggleView } = useToggleView();
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
const { selectedProduct } = useSelectedProduct();
const { floorItems, setFloorItems } = useFloorItems();
const { socket } = useSocketStore();
const itemsData = useRef<Types.FloorItems>([]);
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
const updateBackend = (
productName: string,
productId: string,
organization: string,
eventData: EventsSchema
) => {
upsertProductOrEventApi({
productName: productName,
productId: productId,
organization: organization,
eventDatas: eventData
})
}
useEffect(() => {
if (!camera || !scene || toggleView || !itemsGroupRef.current) return;
@ -190,10 +209,19 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
})
}
if (productData) {
useProductStore.getState().updateEvent(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid, {
const event = useProductStore.getState().updateEvent(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid, {
position: [worldPosition.x, worldPosition.y, worldPosition.z],
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
})
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
}
}
@ -203,9 +231,6 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
return updatedItems;
});
const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "default";
//REST
// await setFloorItemApi(

View File

@ -8,6 +8,7 @@ import * as Types from "../../../../types/world/worldTypes";
import { useEventsStore } from "../../../../store/simulation/useEventsStore";
import { useProductStore } from "../../../../store/simulation/useProductStore";
import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore";
import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi";
function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMovedObjects, itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, duplicatedObjects, setDuplicatedObjects, selectionGroup, boundingBoxRef }: any) {
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
@ -15,10 +16,28 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
const { toggleView } = useToggleView();
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
const { selectedProduct } = useSelectedProduct();
const { floorItems, setFloorItems } = useFloorItems();
const { socket } = useSocketStore();
const itemsData = useRef<Types.FloorItems>([]);
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
const updateBackend = (
productName: string,
productId: string,
organization: string,
eventData: EventsSchema
) => {
upsertProductOrEventApi({
productName: productName,
productId: productId,
organization: organization,
eventDatas: eventData
})
}
const prevPointerPosition = useRef<THREE.Vector2 | null>(null);
useEffect(() => {
@ -190,10 +209,19 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
})
}
if (productData) {
useProductStore.getState().updateEvent(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid, {
const event = useProductStore.getState().updateEvent(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid, {
position: [worldPosition.x, worldPosition.y, worldPosition.z],
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
})
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
}
}
@ -203,9 +231,6 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
return updatedItems;
});
const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "default";
//REST
// await setFloorItemApi(

View File

@ -1,22 +1,29 @@
import React, { useEffect, useRef, useState } from "react";
import * as THREE from "three";
import { useEventsStore } from "../../../../../store/simulation/useEventsStore";
import useModuleStore from "../../../../../store/useModuleStore";
import useModuleStore, { useSubModuleStore } from "../../../../../store/useModuleStore";
import { TransformControls } from "@react-three/drei";
import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys";
import {
useSelectedEventSphere,
useSelectedEventData,
useIsDragging,
useIsRotating,
} from "../../../../../store/simulation/useSimulationStore";
import { useThree } from "@react-three/fiber";
function PointsCreator() {
const { gl, raycaster, scene, pointer, camera } = useThree();
const { subModule } = useSubModuleStore();
const { events, updatePoint, getPointByUuid, getEventByModelUuid } = useEventsStore();
const { activeModule } = useModuleStore();
const transformRef = useRef<any>(null);
const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null);
const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({});
const { selectedEventSphere, setSelectedEventSphere, clearSelectedEventSphere, } = useSelectedEventSphere();
const { selectedEventData, setSelectedEventData, clearSelectedEventData } = useSelectedEventData();
const { setSelectedEventData, clearSelectedEventData } = useSelectedEventData();
const { isDragging } = useIsDragging();
const { isRotating } = useIsRotating();
useEffect(() => {
if (selectedEventSphere) {
@ -72,6 +79,53 @@ function PointsCreator() {
}
};
useEffect(() => {
const canvasElement = gl.domElement;
let drag = false;
let isMouseDown = false;
const onMouseDown = () => {
isMouseDown = true;
drag = false;
};
const onMouseUp = () => {
if (selectedEventSphere && !drag) {
raycaster.setFromCamera(pointer, camera);
const intersects = raycaster
.intersectObjects(scene.children, true)
.filter(
(intersect) =>
intersect.object.name === ('Event-Sphere')
);
if (intersects.length === 0) {
clearSelectedEventSphere();
setTransformMode(null);
}
}
}
const onMouseMove = () => {
if (isMouseDown) {
drag = true;
}
};
if (subModule === 'mechanics') {
canvasElement.addEventListener("mousedown", onMouseDown);
canvasElement.addEventListener("mouseup", onMouseUp);
canvasElement.addEventListener("mousemove", onMouseMove);
}
return () => {
canvasElement.removeEventListener("mousedown", onMouseDown);
canvasElement.removeEventListener("mouseup", onMouseUp);
canvasElement.removeEventListener("mousemove", onMouseMove);
};
}, [gl, subModule, selectedEventSphere]);
return (
<>
{activeModule === "simulation" && (
@ -92,12 +146,6 @@ function PointsCreator() {
sphereRefs.current[point.uuid]
);
}}
onPointerMissed={() => {
if (selectedEventData?.data.type !== 'vehicle') {
clearSelectedEventSphere();
}
setTransformMode(null);
}}
key={`${i}-${j}`}
position={new THREE.Vector3(...point.position)}
// rotation={new THREE.Euler(...point.rotation)}
@ -122,10 +170,6 @@ function PointsCreator() {
sphereRefs.current[event.point.uuid]
);
}}
onPointerMissed={() => {
clearSelectedEventSphere();
setTransformMode(null);
}}
position={new THREE.Vector3(...event.point.position)}
// rotation={new THREE.Euler(...event.point.rotation)}
userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }}
@ -148,10 +192,6 @@ function PointsCreator() {
sphereRefs.current[event.point.uuid]
);
}}
onPointerMissed={() => {
clearSelectedEventSphere();
setTransformMode(null);
}}
position={new THREE.Vector3(...event.point.position)}
// rotation={new THREE.Euler(...event.point.rotation)}
userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }}
@ -174,10 +214,6 @@ function PointsCreator() {
sphereRefs.current[event.point.uuid]
);
}}
onPointerMissed={() => {
clearSelectedEventSphere();
setTransformMode(null);
}}
position={new THREE.Vector3(...event.point.position)}
// rotation={new THREE.Euler(...event.point.rotation)}
userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }}

View File

@ -1,7 +1,43 @@
import React from 'react'
import React, { useEffect } from 'react'
import MachineInstances from './instances/machineInstances'
import { useMachineStore } from '../../../store/simulation/useMachineStore'
import { useSelectedProduct } from '../../../store/simulation/useSimulationStore';
function Machine() {
const { addMachine, addCurrentAction, removeMachine } = useMachineStore();
const { selectedProduct } = useSelectedProduct();
const machineSample: MachineEventSchema[] = [
{
modelUuid: "machine-1234-5678-9012",
modelName: "CNC Milling Machine",
position: [10, 0, 5],
rotation: [0, 0, 0],
state: "idle",
type: "machine",
point: {
uuid: "machine-point-9876-5432-1098",
position: [10, 0.5, 5.2],
rotation: [0, 0, 0],
action: {
actionUuid: "machine-action-2468-1357-8024",
actionName: "Metal Processing",
actionType: "process",
processTime: 10,
swapMaterial: "steel",
triggers: []
}
}
}
];
useEffect(() => {
removeMachine(machineSample[0].modelUuid);
addMachine(selectedProduct.productId, machineSample[0]);
// addCurrentAction(machineSample[0].modelUuid, machineSample[0].point.action.actionUuid);
}, [])
return (
<>

View File

@ -53,7 +53,17 @@ function AddOrRemoveEventsInProducts() {
const canvasElement = gl.domElement;
if (!canvasElement) return;
let intersects = raycaster.intersectObjects(scene.children, true);
const intersects = raycaster
.intersectObjects(scene.children, true)
.filter(
(intersect) =>
!intersect.object.name.includes("Roof") &&
!intersect.object.name.includes("MeasurementReference") &&
!intersect.object.name.includes("agv-collider") &&
!(intersect.object.type === "GridHelper") &&
!(intersect.object?.parent?.name.includes('zones')) &&
!(intersect.object?.parent?.name.includes('Zone'))
);
if (intersects.length > 0 && intersects[0]?.object?.parent?.parent?.position && intersects[0]?.object?.parent?.parent?.scale && intersects[0]?.object?.parent?.parent?.rotation) {
let currentObject = intersects[0].object;
@ -116,6 +126,7 @@ function AddOrRemoveEventsInProducts() {
};
}, [gl, subModule, selectedProduct, selectedAsset]);
return (
<></>
)

View File

@ -7,7 +7,7 @@ import { upsertProductOrEventApi } from '../../../services/simulation/UpsertProd
import { getAllProductsApi } from '../../../services/simulation/getallProductsApi';
function Products() {
const { products, addProduct, setProducts } = useProductStore();
const { addProduct, setProducts } = useProductStore();
const { setSelectedProduct } = useSelectedProduct();
useEffect(() => {
@ -27,9 +27,6 @@ function Products() {
})
}, [])
useEffect(() => {
}, [])
return (
<>

View File

@ -170,8 +170,8 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) {
}
}
const logStatus = (id: string, status: string) => {
// console.log(id + "," + status);
console.log( status);
//
}
return (

View File

@ -23,7 +23,7 @@ function Simulation() {
}, [events])
useEffect(() => {
// console.log('products: ', products);
console.log('products: ', products);
}, [products])
return (

View File

@ -1,5 +1,5 @@
import { useEffect, useRef, useState } from "react";
import { useThree } from "@react-three/fiber";
import { useFrame, useThree } from "@react-three/fiber";
import * as THREE from "three";
import { useSubModuleStore } from "../../../../store/useModuleStore";
import { useSelectedAsset } from "../../../../store/simulation/useSimulationStore";
@ -7,21 +7,28 @@ import { useProductStore } from "../../../../store/simulation/useProductStore";
import { useEventsStore } from "../../../../store/simulation/useEventsStore";
import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore";
import { handleAddEventToProduct } from "../../events/points/functions/handleAddEventToProduct";
import { QuadraticBezierLine } from "@react-three/drei";
import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi";
import { useDeleteTool } from "../../../../store/store";
interface ConnectionLine {
id: string;
start: THREE.Vector3;
end: THREE.Vector3;
mid: THREE.Vector3;
startPointUuid: string;
endPointUuid: string;
trigger: TriggerSchema;
}
function TriggerConnector() {
const { gl, raycaster, scene } = useThree();
const { gl, raycaster, scene, pointer, camera } = useThree();
const { subModule } = useSubModuleStore();
const { products, getPointByUuid, getIsEventInProduct, getActionByUuid, addTrigger, addEvent, getEventByModelUuid } = useProductStore();
const { products, getPointByUuid, getIsEventInProduct, getActionByUuid, addTrigger, removeTrigger, addEvent, getEventByModelUuid, getProductById } = useProductStore();
const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
const { selectedProduct } = useSelectedProduct();
const [hoveredLineKey, setHoveredLineKey] = useState<string | null>(null);
const groupRefs = useRef<Record<string, any>>({});
const [helperlineColor, setHelperLineColor] = useState<string>("red");
const [currentLine, setCurrentLine] = useState<{ start: THREE.Vector3; end: THREE.Vector3; mid: THREE.Vector3; } | null>(null);
const { deleteTool } = useDeleteTool();
const [firstSelectedPoint, setFirstSelectedPoint] = useState<{
productId: string;
@ -32,52 +39,99 @@ function TriggerConnector() {
const [connections, setConnections] = useState<ConnectionLine[]>([]);
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
const updateBackend = (
productName: string,
productId: string,
organization: string,
eventData: EventsSchema
) => {
upsertProductOrEventApi({
productName: productName,
productId: productId,
organization: organization,
eventDatas: eventData
})
}
useEffect(() => {
const newConnections: ConnectionLine[] = [];
products.forEach(product => {
const product = getProductById(selectedProduct.productId);
if (!product || products.length === 0) return;
product.eventDatas.forEach(event => {
if ('points' in event) {
// Handle Conveyor points
if (event.type === "transfer" && 'points' in event) {
event.points.forEach(point => {
if ('action' in point && point.action?.triggers) {
if (point.action?.triggers) {
point.action.triggers.forEach(trigger => {
if (trigger.triggeredAsset) {
const targetPoint = getPointByUuid(
product.productId,
trigger.triggeredAsset.triggeredModel.modelUuid,
trigger.triggeredAsset.triggeredPoint.pointUuid
);
if (targetPoint) {
const startPos = new THREE.Vector3(...point.position);
const endPos = new THREE.Vector3(...targetPoint.position);
const midPos = new THREE.Vector3()
.addVectors(startPos, endPos)
.multiplyScalar(0.5)
.add(new THREE.Vector3(0, 2, 0));
newConnections.push({
id: `${point.uuid}-${targetPoint.uuid}-${trigger.triggerUuid}`,
start: startPos,
end: endPos,
mid: midPos,
id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`,
startPointUuid: point.uuid,
endPointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
trigger
});
}
}
});
}
});
}
// Handle Vehicle point
else if (event.type === "vehicle" && 'point' in event) {
const point = event.point;
if (point.action?.triggers) {
point.action.triggers.forEach(trigger => {
if (trigger.triggeredAsset) {
newConnections.push({
id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`,
startPointUuid: point.uuid,
endPointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
trigger
});
}
});
}
}
// Handle Robotic Arm points
else if (event.type === "roboticArm" && 'point' in event) {
const point = event.point;
point.actions?.forEach(action => {
action.triggers?.forEach(trigger => {
if (trigger.triggeredAsset) {
newConnections.push({
id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`,
startPointUuid: point.uuid,
endPointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
trigger
});
}
});
});
}
// Handle Machine point
else if (event.type === "machine" && 'point' in event) {
const point = event.point;
if (point.action?.triggers) {
point.action.triggers.forEach(trigger => {
if (trigger.triggeredAsset) {
newConnections.push({
id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`,
startPointUuid: point.uuid,
endPointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
trigger
});
}
});
}
}
});
setConnections(newConnections);
}, [products]);
useEffect(() => {
console.log('connections: ', connections);
}, connections)
}, [products, selectedProduct.productId]);
useEffect(() => {
const canvasElement = gl.domElement;
@ -111,15 +165,31 @@ function TriggerConnector() {
if (drag) return;
evt.preventDefault();
const intersects = raycaster.intersectObjects(scene.children, true);
if (intersects.length === 0) return;
const intersects = raycaster
.intersectObjects(scene.children, true)
.filter(
(intersect) =>
intersect.object.name === ('Event-Sphere')
);
if (intersects.length === 0) {
setFirstSelectedPoint(null);
return;
};
const currentObject = intersects[0].object;
if (!currentObject || currentObject.name !== 'Event-Sphere') return;
if (!currentObject || currentObject.name !== 'Event-Sphere') {
setFirstSelectedPoint(null);
return;
};
const modelUuid = currentObject.userData.modelUuid;
const pointUuid = currentObject.userData.pointUuid;
if (firstSelectedPoint && firstSelectedPoint.pointUuid === pointUuid) {
setFirstSelectedPoint(null);
return;
}
if (selectedProduct && getIsEventInProduct(selectedProduct.productId, modelUuid)) {
const point = getPointByUuid(
@ -128,7 +198,12 @@ function TriggerConnector() {
pointUuid
);
if (!point) return;
const event = getEventByModelUuid(selectedProduct.productId, modelUuid);
if (!point || !event) {
setFirstSelectedPoint(null);
return;
};
let actionUuid: string | undefined;
if ('action' in point && point.action) {
@ -152,12 +227,12 @@ function TriggerConnector() {
delay: 0,
triggeredAsset: {
triggeredModel: {
modelName: currentObject.parent?.parent?.name || 'Unknown',
modelName: event.modelName || 'Unknown',
modelUuid: modelUuid
},
triggeredPoint: {
pointName: currentObject.name,
pointUuid: pointUuid
pointName: 'Point',
pointUuid: point.uuid
},
triggeredAction: actionUuid ? {
actionName: getActionByUuid(selectedProduct.productId, actionUuid)?.actionName || 'Action',
@ -167,7 +242,16 @@ function TriggerConnector() {
};
if (firstSelectedPoint.actionUuid) {
addTrigger(firstSelectedPoint.actionUuid, trigger);
const event = addTrigger(selectedProduct.productId, firstSelectedPoint.actionUuid, trigger);
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
}
setFirstSelectedPoint(null);
}
@ -184,7 +268,12 @@ function TriggerConnector() {
pointUuid
);
if (!point) return;
const event = getEventByModelUuid(selectedProduct.productId, modelUuid);
if (!point || !event) {
setFirstSelectedPoint(null);
return;
};
let actionUuid: string | undefined;
if ('action' in point && point.action) {
@ -200,12 +289,12 @@ function TriggerConnector() {
delay: 0,
triggeredAsset: {
triggeredModel: {
modelName: currentObject.parent?.parent?.name || 'Unknown',
modelName: event.modelName || 'Unknown',
modelUuid: modelUuid
},
triggeredPoint: {
pointName: currentObject.name,
pointUuid: pointUuid
pointName: 'Point',
pointUuid: point.uuid
},
triggeredAction: actionUuid ? {
actionName: getActionByUuid(selectedProduct.productId, actionUuid)?.actionName || 'Action',
@ -215,13 +304,24 @@ function TriggerConnector() {
};
if (firstSelectedPoint.actionUuid) {
addTrigger(firstSelectedPoint.actionUuid, trigger);
const event = addTrigger(selectedProduct.productId, firstSelectedPoint.actionUuid, trigger);
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
}
setFirstSelectedPoint(null);
} else if (firstSelectedPoint) {
setFirstSelectedPoint(null);
}
};
if (subModule === 'simulations') {
if (subModule === 'simulations' && !deleteTool) {
canvasElement.addEventListener("mousedown", onMouseDown);
canvasElement.addEventListener("mouseup", onMouseUp);
canvasElement.addEventListener("mousemove", onMouseMove);
@ -235,11 +335,149 @@ function TriggerConnector() {
canvasElement.removeEventListener('contextmenu', handleRightClick);
};
}, [gl, subModule, selectedProduct, firstSelectedPoint]);
}, [gl, subModule, selectedProduct, firstSelectedPoint, deleteTool]);
useFrame(() => {
if (firstSelectedPoint) {
raycaster.setFromCamera(pointer, camera);
const intersects = raycaster.intersectObjects(scene.children, true).filter(
(intersect) =>
!intersect.object.name.includes("Roof") &&
!intersect.object.name.includes("agv-collider") &&
!intersect.object.name.includes("MeasurementReference") &&
!intersect.object.parent?.name.includes("Zone") &&
!(intersect.object.type === "GridHelper") &&
!(intersect.object.type === "Line2")
);
let point: THREE.Vector3 | null = null;
if (intersects.length > 0) {
point = intersects[0].point;
if (point.y < 0.05) {
point = new THREE.Vector3(point.x, 0.05, point.z);
}
}
const sphereIntersects = raycaster.intersectObjects(scene.children, true).filter((intersect) => intersect.object.name === ('Event-Sphere'));
if (sphereIntersects.length > 0 && sphereIntersects[0].object.uuid === firstSelectedPoint.pointUuid) {
setHelperLineColor('red');
setCurrentLine(null);
return;
}
const startPoint = getWorldPositionFromScene(firstSelectedPoint.pointUuid);
if (point && startPoint) {
if (sphereIntersects.length > 0) {
point = sphereIntersects[0].object.getWorldPosition(new THREE.Vector3());
}
const distance = startPoint.distanceTo(point);
const heightFactor = Math.max(0.5, distance * 0.2);
const midPoint = new THREE.Vector3(
(startPoint.x + point.x) / 2,
Math.max(startPoint.y, point.y) + heightFactor,
(startPoint.z + point.z) / 2
);
const endPoint = point;
setCurrentLine({
start: startPoint,
mid: midPoint,
end: endPoint,
});
setHelperLineColor(sphereIntersects.length > 0 ? "#6cf542" : "red");
} else {
setCurrentLine(null);
}
} else {
setCurrentLine(null);
}
})
const getWorldPositionFromScene = (pointUuid: string): THREE.Vector3 | null => {
const pointObj = scene.getObjectByProperty("uuid", pointUuid);
if (!pointObj) return null;
const worldPosition = new THREE.Vector3();
pointObj.getWorldPosition(worldPosition);
return worldPosition;
};
const removeConnection = (connection: ConnectionLine) => {
if (connection.trigger.triggerUuid) {
const event = removeTrigger(selectedProduct.productId, connection.trigger.triggerUuid);
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
}
};
return (
<>
</>
<group name="simulationConnectionGroup" >
{connections.map((connection) => {
const startPoint = getWorldPositionFromScene(connection.startPointUuid);
const endPoint = getWorldPositionFromScene(connection.endPointUuid);
if (!startPoint || !endPoint) return null;
const distance = startPoint.distanceTo(endPoint);
const heightFactor = Math.max(0.5, distance * 0.2);
const midPoint = new THREE.Vector3(
(startPoint.x + endPoint.x) / 2,
Math.max(startPoint.y, endPoint.y) + heightFactor,
(startPoint.z + endPoint.z) / 2
);
return (
<QuadraticBezierLine
key={connection.id}
ref={(el) => (groupRefs.current[connection.id] = el!)}
start={startPoint.toArray()}
end={endPoint.toArray()}
mid={midPoint.toArray()}
color={deleteTool && hoveredLineKey === connection.id ? "red" : "#42a5f5"}
lineWidth={4}
dashed={deleteTool && hoveredLineKey === connection.id ? false : true}
dashSize={0.75}
dashScale={20}
onPointerOver={() => setHoveredLineKey(connection.id)}
onPointerOut={() => setHoveredLineKey(null)}
onClick={() => {
if (deleteTool) {
setHoveredLineKey(null);
setCurrentLine(null);
removeConnection(connection);
}
}}
userData={connection.trigger}
/>
);
})}
{currentLine && (
<QuadraticBezierLine
start={currentLine.start.toArray()}
end={currentLine.end.toArray()}
mid={currentLine.mid.toArray()}
color={helperlineColor}
lineWidth={4}
dashed
dashSize={1}
dashScale={20}
/>
)}
</group>
);
}

View File

@ -1,12 +1,16 @@
import React, { useEffect, useRef, useState } from 'react';
import * as Types from "../../../../types/world/worldTypes";
import startPoint from "../../../../assets/gltf-glb/arrow_green.glb";
import startEnd from "../../../../assets/gltf-glb/arrow_red.glb";
import * as THREE from "three";
import startEnd from "../../../../assets/gltf-glb/arrow_red.glb";
import { useGLTF } from '@react-three/drei';
import { useFrame, useThree } from '@react-three/fiber';
import { useSelectedEventSphere } from '../../../../store/simulation/useSimulationStore';
import { useSelectedEventSphere, useIsDragging, useIsRotating } from '../../../../store/simulation/useSimulationStore';
import { useVehicleStore } from '../../../../store/simulation/useVehicleStore';
import * as Types from "../../../../types/world/worldTypes";
import { useProductStore } from '../../../../store/simulation/useProductStore';
import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore';
import { upsertProductOrEventApi } from '../../../../services/simulation/UpsertProductOrEventApi';
const VehicleUI = () => {
const { scene: startScene } = useGLTF(startPoint) as any;
const { scene: endScene } = useGLTF(startEnd) as any;
@ -14,67 +18,60 @@ const VehicleUI = () => {
const endMarker = useRef<THREE.Group>(null);
const prevMousePos = useRef({ x: 0, y: 0 });
const { selectedEventSphere } = useSelectedEventSphere();
const { vehicles, updateVehicle } = useVehicleStore();
const { selectedProduct } = useSelectedProduct();
const { getVehicleById } = useVehicleStore();
const { updateEvent } = useProductStore();
const [startPosition, setStartPosition] = useState<[number, number, number]>([0, 0, 0]);
const [endPosition, setEndPosition] = useState<[number, number, number]>([0, 0, 0]);
const [startRotation, setStartRotation] = useState<[number, number, number]>([0, 0, 0]);
const [endRotation, setEndRotation] = useState<[number, number, number]>([0, 0, 0]);
const [isDragging, setIsDragging] = useState<"start" | "end" | null>(null);
const [isRotating, setIsRotating] = useState<"start" | "end" | null>(null);
const { isDragging, setIsDragging } = useIsDragging();
const { isRotating, setIsRotating } = useIsRotating();
const { raycaster } = useThree();
const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0));
const state: Types.ThreeState = useThree();
const controls: any = state.controls;
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
const updateBackend = (
productName: string,
productId: string,
organization: string,
eventData: EventsSchema
) => {
upsertProductOrEventApi({
productName: productName,
productId: productId,
organization: organization,
eventDatas: eventData
})
}
useEffect(() => {
if (!selectedEventSphere) return;
const selectedVehicle = vehicles.find(
(vehicle: any) => vehicle.modelUuid === selectedEventSphere.userData.modelUuid
);
const selectedVehicle = getVehicleById(selectedEventSphere.userData.modelUuid);
if (selectedVehicle?.point?.action) {
const { pickUpPoint, unLoadPoint } = selectedVehicle.point.action;
if (pickUpPoint) {
const pickupPosition = new THREE.Vector3(
pickUpPoint.position.x,
pickUpPoint.position.y,
pickUpPoint.position.z
);
const pickupRotation = new THREE.Vector3(
pickUpPoint.rotation.x,
pickUpPoint.rotation.y,
pickUpPoint.rotation.z
);
pickupPosition.y = 0;
setStartPosition([pickupPosition.x, 0, pickupPosition.z]);
setStartRotation([pickupRotation.x, pickupRotation.y, pickupRotation.z]);
setStartPosition([pickUpPoint.position.x, 0, pickUpPoint.position.z]);
setStartRotation([pickUpPoint.rotation.x, pickUpPoint.rotation.y, pickUpPoint.rotation.z]);
} else {
const defaultLocal = new THREE.Vector3(0, 0, 1.5);
const defaultWorld = selectedEventSphere.localToWorld(defaultLocal);
defaultWorld.y = 0;
setStartPosition([defaultWorld.x, 0, defaultWorld.z]);
setStartRotation([0, 0, 0]);
}
if (unLoadPoint) {
const unLoadPosition = new THREE.Vector3(
unLoadPoint.position.x,
unLoadPoint.position.y,
unLoadPoint.position.z
);
const unLoadRotation = new THREE.Vector3(
unLoadPoint.rotation.x,
unLoadPoint.rotation.y,
unLoadPoint.position.z
);
unLoadPosition.y = 0; // Force y to 0
setEndPosition([unLoadPosition.x, 0, unLoadPosition.z]);
setEndRotation([unLoadRotation.x, unLoadRotation.y, unLoadRotation.z]);
setEndPosition([unLoadPoint.position.x, 0, unLoadPoint.position.z]);
setEndRotation([unLoadPoint.rotation.x, unLoadPoint.rotation.y, unLoadPoint.rotation.z]);
} else {
const defaultLocal = new THREE.Vector3(0, 0, -1.5);
const defaultWorld = selectedEventSphere.localToWorld(defaultLocal);
defaultWorld.y = 0; // Force y to 0
setEndPosition([defaultWorld.x, 0, defaultWorld.z]);
setEndRotation([0, 0, 0]);
}
@ -87,7 +84,6 @@ const VehicleUI = () => {
const intersects = raycaster.ray.intersectPlane(plane.current, intersectPoint);
if (intersects) {
intersectPoint.y = 0; // Force y to 0
if (isDragging === "start") {
setStartPosition([intersectPoint.x, 0, intersectPoint.z]);
}
@ -108,12 +104,12 @@ const VehicleUI = () => {
if (marker) {
const rotationSpeed = 10;
marker.rotation.y += deltaX * rotationSpeed;
if (isRotating === 'start') {
setStartRotation([marker.rotation.x, marker.rotation.y, marker.rotation.z])
const y = startRotation[1] + deltaX * rotationSpeed;
setStartRotation([0, y, 0]);
} else {
setEndRotation([marker.rotation.x, marker.rotation.y, marker.rotation.z])
const y = endRotation[1] + deltaX * rotationSpeed;
setEndRotation([0, y, 0]);
}
}
});
@ -142,43 +138,34 @@ const VehicleUI = () => {
setIsRotating(null);
if (selectedEventSphere?.userData.modelUuid) {
const updatedVehicle = vehicles.find(
(vehicle) => vehicle.modelUuid === selectedEventSphere.userData.modelUuid
);
const updatedVehicle = getVehicleById(selectedEventSphere.userData.modelUuid);
if (updatedVehicle) {
updateVehicle(selectedEventSphere.userData.modelUuid, {
const event = updateEvent(selectedProduct.productId, selectedEventSphere.userData.modelUuid, {
point: {
...updatedVehicle.point,
action: {
...updatedVehicle.point?.action,
pickUpPoint: {
position: {
x: startPosition[0],
y: startPosition[1],
z: startPosition[2],
},
rotation: {
x: startRotation[0],
y: startRotation[1],
z: startRotation[2],
},
position: { x: startPosition[0], y: startPosition[1], z: startPosition[2], },
rotation: { x: 0, y: startRotation[1], z: 0, },
},
unLoadPoint: {
position: {
x: endPosition[0],
y: endPosition[1],
z: endPosition[2],
},
rotation: {
x: endRotation[0],
y: endRotation[1],
z: endRotation[2],
position: { x: endPosition[0], y: endPosition[1], z: endPosition[2], },
rotation: { x: 0, y: endRotation[1], z: 0, },
},
},
},
},
});
})
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productId,
organization,
event
);
}
}
}
};
@ -208,6 +195,7 @@ const VehicleUI = () => {
object={startScene}
ref={startMarker}
position={startPosition}
rotation={startRotation}
onPointerDown={(e: any) => {
e.stopPropagation();
handlePointerDown(e, "start", "start");
@ -224,6 +212,7 @@ const VehicleUI = () => {
object={endScene}
ref={endMarker}
position={endPosition}
rotation={endRotation}
onPointerDown={(e: any) => {
e.stopPropagation();
handlePointerDown(e, "end", "end");

View File

@ -11,7 +11,7 @@ interface VehicleAnimatorProps {
reset: () => void;
currentPhase: string;
agvUuid: number;
agvDetail: any;
agvDetail: VehicleStatus;
}
function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetail, reset }: VehicleAnimatorProps) {
@ -32,7 +32,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
let startTime: number;
let fixedInterval: number;
let coveredDistance = progressRef.current;
let objectRotation = (agvDetail.point?.action?.pickUpPoint?.rotation || { x: 0, y: 0, z: 0 }) as { x: number; y: number; z: number };
let objectRotation = (agvDetail.point?.action?.pickUpPoint?.rotation || { x: 0, y: 0, z: 0 }) as { x: number; y: number; z: number } | undefined;
useEffect(() => {
@ -67,10 +67,9 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
setRestingRotation(true);
decrementVehicleLoad(agvDetail.modelUuid, 0);
const object = scene.getObjectByProperty('uuid', agvUuid);
console.log('currentPhase: ', currentPhase);
if (object) {
object.position.set(agvDetail.position[0], agvDetail.position[1], agvDetail.position[2]);
object.rotation.set(objectRotation.x, objectRotation.y, objectRotation.z);
object.rotation.set(agvDetail.rotation[0], agvDetail.rotation[1], agvDetail.rotation[2]);
}
}
}, [isReset, isPlaying])
@ -132,7 +131,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
}
if (progressRef.current >= totalDistance) {
if (restRotation) {
if (restRotation && objectRotation) {
const targetQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(objectRotation.x, objectRotation.y, objectRotation.z));
object.quaternion.slerp(targetQuaternion, delta * 2);
const angleDiff = object.quaternion.angleTo(targetQuaternion);

View File

@ -30,7 +30,8 @@ function VehicleInstance({ agvDetail }: any) {
);
function vehicleStatus(modelId: string, status: string) {
// console.log(`${modelId} , ${status});
// console.log(`${modelId} , ${status}`);
}
// Function to reset everything
@ -44,7 +45,7 @@ function VehicleInstance({ agvDetail }: any) {
const increment = () => {
if (isIncrememtable.current) {
incrementVehicleLoad(agvDetail.modelUuid, 2);
incrementVehicleLoad(agvDetail.modelUuid, 10);
isIncrememtable.current = false;
}
}
@ -69,6 +70,7 @@ function VehicleInstance({ agvDetail }: any) {
increment();
}, 5000);
if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity) {
const toDrop = computePath(
agvDetail.point.action.pickUpPoint.position,

View File

@ -1,220 +1,48 @@
import React, { useEffect, useState } from "react";
import React, { useEffect } from "react";
import VehicleInstances from "./instances/vehicleInstances";
import { useVehicleStore } from "../../../store/simulation/useVehicleStore";
import { useFloorItems } from "../../../store/store";
import { useSelectedEventData, useSelectedEventSphere } from "../../../store/simulation/useSimulationStore";
import { useSelectedEventData, useSelectedEventSphere, useSelectedProduct } from "../../../store/simulation/useSimulationStore";
import VehicleUI from "../ui/vehicle/vehicleUI";
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
function Vehicles() {
import { useProductStore } from "../../../store/simulation/useProductStore";
const { vehicles, addVehicle } = useVehicleStore();
function Vehicles() {
const { products, getProductById } = useProductStore();
const { selectedProduct } = useSelectedProduct();
const { vehicles, addVehicle, clearvehicles } = useVehicleStore();
const { selectedEventSphere } = useSelectedEventSphere();
const { selectedEventData } = useSelectedEventData();
const { floorItems } = useFloorItems();
const { isPlaying } = usePlayButtonStore();
const [vehicleStatusSample, setVehicleStatusSample] = useState<
VehicleEventSchema[]
>([
{
modelUuid: "9356f710-4727-4b50-bdb2-9c1e747ecc74",
modelName: "AGV",
position: [97.9252965204558, 0, 37.96138815638661],
rotation: [0, 0, 0],
state: "idle",
type: "vehicle",
speed: 2.5,
point: {
uuid: "point-789",
position: [0, 1, 0],
rotation: [0, 0, 0],
action: {
actionUuid: "action-456",
actionName: "Deliver to Zone A",
actionType: "travel",
unLoadDuration: 10,
loadCapacity: 2,
steeringAngle:0,
pickUpPoint: { position: { x: 98.71483985219794, y: 0, z: 28.66321267938962 }, rotation: { x: 0, y: 0, z: 0 } },
unLoadPoint: { position: { x: 105.71483985219794, y: 0, z: 28.66321267938962 }, rotation: { x: 0, y: 0, z: 0 } },
triggers: [
{
triggerUuid: "trig-001",
triggerName: "Start Travel",
triggerType: "onComplete",
delay: 0,
triggeredAsset: {
triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" },
triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" },
triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" }
useEffect(() => {
if (selectedProduct.productId) {
const product = getProductById(selectedProduct.productId);
if (product) {
clearvehicles();
product.eventDatas.forEach(events => {
if (events.type === 'vehicle') {
addVehicle(selectedProduct.productId, events);
}
},
{
triggerUuid: "trig-002",
triggerName: "Complete Travel",
triggerType: "onComplete",
delay: 2,
triggeredAsset: null
}
]
});
}
}
},
{
modelUuid: "b06960bb-3d2e-41f7-a646-335f389c68b4",
modelName: "AGV",
position: [89.61609306554463, 0, 33.634136622267356],
rotation: [0, 0, 0],
state: "idle",
type: "vehicle",
speed: 2.5,
point: {
uuid: "point-789",
position: [0, 1, 0],
rotation: [0, 0, 0],
action: {
actionUuid: "action-456",
actionName: "Deliver to Zone A",
actionType: "travel",
unLoadDuration: 10,
loadCapacity: 2,
steeringAngle:0,
pickUpPoint: null,
unLoadPoint: null,
triggers: [
{
triggerUuid: "trig-001",
triggerName: "Start Travel",
triggerType: "onStart",
delay: 0,
triggeredAsset: {
triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" },
triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" },
triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" }
}
},
{
triggerUuid: "trig-002",
triggerName: "Complete Travel",
triggerType: "onComplete",
delay: 2,
triggeredAsset: null
}
]
}
}
},
// {
// modelUuid: "cd7d0584-0684-42b4-b051-9e882c1914aa",
// modelName: "AGV",
// position: [105.90938758014703, 0, 31.584209911095215],
// rotation: [0, 0, 0],
// state: "idle",
// type: "vehicle",
// speed: 2.5,
// point: {
// uuid: "point-789",
// position: [0, 1, 0],
// rotation: [0, 0, 0],
// action: {
// actionUuid: "action-456",
// actionName: "Deliver to Zone A",
// actionType: "travel",
// unLoadDuration: 10,
// loadCapacity: 2,
// steeringAngle:0,
// pickUpPoint: null,
// unLoadPoint: null,
// triggers: [
// {
// triggerUuid: "trig-001",
// triggerName: "Start Travel",
// triggerType: "onStart",
// delay: 0,
// triggeredAsset: {
// triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" },
// triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" },
// triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" }
// }
// },
// {
// triggerUuid: "trig-002",
// triggerName: "Complete Travel",
// triggerType: "onComplete",
// delay: 2,
// triggeredAsset: null
// }
// ]
// }
// }
// },
// {
// modelUuid: "e729a4f1-11d2-4778-8d6a-468f1b4f6b79",
// modelName: "forklift",
// position: [98.85729337188162, 0, 38.36616546567653],
// rotation: [0, 0, 0],
// state: "idle",
// type: "vehicle",
// speed: 2.5,
// point: {
// uuid: "point-789",
// position: [0, 1, 0],
// rotation: [0, 0, 0],
// action: {
// actionUuid: "action-456",
// actionName: "Deliver to Zone A",
// actionType: "travel",
// unLoadDuration: 15,
// loadCapacity: 5,
// steeringAngle:0,
// pickUpPoint: null,
// unLoadPoint: null,
// triggers: [
// {
// triggerUuid: "trig-001",
// triggerName: "Start Travel",
// triggerType: "onStart",
// delay: 0,
// triggeredAsset: {
// triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" },
// triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" },
// triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" }
// }
// },
// {
// triggerUuid: "trig-002",
// triggerName: "Complete Travel",
// triggerType: "onComplete",
// delay: 2,
// triggeredAsset: null
// }
// ]
// }
// }
// }
]);
}, [selectedProduct, products]);
useEffect(() => {
// console.log('vehicles: ', vehicles);
}, [vehicles])
useEffect(() => {
addVehicle("123", vehicleStatusSample[0]);
addVehicle('123', vehicleStatusSample[1]);
// addVehicle('123', vehicleStatusSample[2]);
}, []);
return (
<>
<VehicleInstances />
{selectedEventSphere && selectedEventData?.data.type === "vehicle" && !isPlaying &&
< VehicleUI />
}
</>
);
}
export default Vehicles;

View File

@ -66,8 +66,7 @@ const RealTimeVisulization: React.FC = () => {
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
const { setRightSelect } = useRightSelected();
const { editWidgetOptions, setEditWidgetOptions } =
useEditWidgetOptionsStore();
const { editWidgetOptions, setEditWidgetOptions } = useEditWidgetOptionsStore();
const { rightClickSelected, setRightClickSelected } = useRightClickSelected();
const [openConfirmationPopup, setOpenConfirmationPopup] = useState(false);
const { setFloatingWidget } = useFloatingWidget();

View File

@ -10,6 +10,7 @@ interface ArmBotStore {
modelUuid: string,
updates: Partial<Omit<ArmBotStatus, 'modelUuid' | 'productId'>>
) => void;
clearArmBots: () => void;
addCurrentAction: (modelUuid: string, actionUuid: string) => void;
removeCurrentAction: (modelUuid: string) => void;
@ -39,6 +40,8 @@ export const useArmBotStore = create<ArmBotStore>()(
addArmBot: (productId, event) => {
set((state) => {
const exists = state.armBots.some(a => a.modelUuid === event.modelUuid);
if (!exists) {
state.armBots.push({
...event,
productId,
@ -47,6 +50,7 @@ export const useArmBotStore = create<ArmBotStore>()(
activeTime: 0,
state: 'idle',
});
}
});
},
@ -65,6 +69,12 @@ export const useArmBotStore = create<ArmBotStore>()(
});
},
clearArmBots: () => {
set((state) => {
state.armBots = [];
});
},
addCurrentAction: (modelUuid, actionUuid) => {
set((state) => {
const armBot = state.armBots.find(a => a.modelUuid === modelUuid);

View File

@ -10,6 +10,7 @@ interface ConveyorStore {
modelUuid: string,
updates: Partial<Omit<ConveyorStatus, 'modelUuid' | 'productId'>>
) => void;
clearConveyors: () => void;
setConveyorActive: (modelUuid: string, isActive: boolean) => void;
setConveyorState: (modelUuid: string, newState: ConveyorStatus['state']) => void;
@ -30,6 +31,8 @@ export const useConveyorStore = create<ConveyorStore>()(
addConveyor: (productId, event) => {
set((state) => {
const exists = state.conveyors.some(c => c.modelUuid === event.modelUuid);
if (!exists) {
state.conveyors.push({
...event,
productId,
@ -38,6 +41,7 @@ export const useConveyorStore = create<ConveyorStore>()(
activeTime: 0,
state: 'idle',
});
}
});
},
@ -56,6 +60,12 @@ export const useConveyorStore = create<ConveyorStore>()(
});
},
clearConveyors: () => {
set((state) => {
state.conveyors = [];
});
},
setConveyorActive: (modelUuid, isActive) => {
set((state) => {
const conveyor = state.conveyors.find(c => c.modelUuid === modelUuid);

View File

@ -7,7 +7,7 @@ type EventsStore = {
// Event-level actions
addEvent: (event: EventsSchema) => void;
removeEvent: (modelUuid: string) => void;
updateEvent: (modelUuid: string, updates: Partial<EventsSchema>) => void;
updateEvent: (modelUuid: string, updates: Partial<EventsSchema>) => EventsSchema | undefined;
// Point-level actions
addPoint: (modelUuid: string, point: ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema) => void;
@ -49,7 +49,9 @@ export const useEventsStore = create<EventsStore>()(
// Event-level actions
addEvent: (event) => {
set((state) => {
if (!state.events.some(e => 'modelUuid' in e && e.modelUuid === event.modelUuid)) {
state.events.push(event);
}
});
},
@ -60,12 +62,15 @@ export const useEventsStore = create<EventsStore>()(
},
updateEvent: (modelUuid, updates) => {
let updatedEvent: EventsSchema | undefined;
set((state) => {
const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
if (event) {
Object.assign(event, updates);
updatedEvent = JSON.parse(JSON.stringify(event));
}
});
return updatedEvent;
},
// Point-level actions
@ -73,10 +78,15 @@ export const useEventsStore = create<EventsStore>()(
set((state) => {
const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
if (event && 'points' in event) {
const existingPoint = (event as ConveyorEventSchema).points.find(p => p.uuid === point.uuid);
if (!existingPoint) {
(event as ConveyorEventSchema).points.push(point as ConveyorPointSchema);
}
} else if (event && 'point' in event) {
if (!(event as any).point || (event as any).point.uuid !== point.uuid) {
(event as VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema).point = point as any;
}
}
});
},
@ -110,14 +120,15 @@ export const useEventsStore = create<EventsStore>()(
const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
if (event && 'points' in event) {
const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
if (point) {
if (point && (!point.action || point.action.actionUuid !== action.actionUuid)) {
point.action = action as any;
}
} else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
if ('action' in (event as any).point) {
(event as any).point.action = action;
} else if ('actions' in (event as any).point) {
(event as any).point.actions.push(action);
const point = (event as any).point;
if ('action' in point && (!point.action || point.action.actionUuid !== action.actionUuid)) {
point.action = action;
} else if ('actions' in point && !point.actions.some((a: any) => a.actionUuid === action.actionUuid)) {
point.actions.push(action);
}
}
});
@ -180,18 +191,22 @@ export const useEventsStore = create<EventsStore>()(
if ('points' in event) {
for (const point of (event as ConveyorEventSchema).points) {
if (point.action && point.action.actionUuid === actionUuid) {
if (!point.action.triggers.some(t => t.triggerUuid === trigger.triggerUuid)) {
point.action.triggers.push(trigger);
}
return;
}
}
} else if ('point' in event) {
const point = (event as any).point;
const point: MachinePointSchema | VehiclePointSchema = (event as any).point;
if ('action' in point && point.action.actionUuid === actionUuid) {
if (!point.action.triggers.some(t => t.triggerUuid === trigger.triggerUuid)) {
point.action.triggers.push(trigger);
}
return;
} else if ('actions' in point) {
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
if (action) {
const action = (point as RoboticArmPointSchema).actions.find((a) => a.actionUuid === actionUuid);
if (action && !action.triggers.some(t => t.triggerUuid === trigger.triggerUuid)) {
action.triggers.push(trigger);
return;
}

View File

@ -4,23 +4,23 @@ import { immer } from 'zustand/middleware/immer';
interface MachineStore {
machines: MachineStatus[];
// Actions
addMachine: (productId: string, machine: MachineEventSchema) => void;
removeMachine: (modelUuid: string) => void;
updateMachine: (
modelUuid: string,
updates: Partial<Omit<MachineStatus, 'modelUuid' | 'productId'>>
) => void;
clearMachines: () => void;
addCurrentAction: (modelUuid: string, actionUuid: string) => void;
removeCurrentAction: (modelUuid: string) => void;
// Status updates
setMachineActive: (modelUuid: string, isActive: boolean) => void;
setMachineState: (modelUuid: string, newState: MachineStatus['state']) => void;
// Time tracking
incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
// Helpers
getMachineById: (modelUuid: string) => MachineStatus | undefined;
getMachinesByProduct: (productId: string) => MachineStatus[];
getMachinesBystate: (state: string) => MachineStatus[];
@ -32,9 +32,10 @@ export const useMachineStore = create<MachineStore>()(
immer((set, get) => ({
machines: [],
// Actions
addMachine: (productId, machine) => {
set((state) => {
const exists = state.machines.some(m => m.modelUuid === machine.modelUuid);
if (!exists) {
state.machines.push({
...machine,
productId,
@ -43,6 +44,7 @@ export const useMachineStore = create<MachineStore>()(
activeTime: 0,
state: 'idle',
});
}
});
},
@ -61,7 +63,36 @@ export const useMachineStore = create<MachineStore>()(
});
},
// Status updates
clearMachines: () => {
set((state) => {
state.machines = [];
});
},
addCurrentAction: (modelUuid) => {
set((state) => {
const armBot = state.machines.find(a => a.modelUuid === modelUuid);
if (armBot) {
const action = armBot.point.action;
if (action) {
armBot.currentAction = {
actionUuid: action.actionUuid,
actionName: action.actionName,
};
}
}
});
},
removeCurrentAction: (modelUuid) => {
set((state) => {
const armBot = state.machines.find(a => a.modelUuid === modelUuid);
if (armBot) {
armBot.currentAction = undefined;
}
});
},
setMachineActive: (modelUuid, isActive) => {
set((state) => {
const machine = state.machines.find(m => m.modelUuid === modelUuid);
@ -80,7 +111,6 @@ export const useMachineStore = create<MachineStore>()(
});
},
// Time tracking
incrementActiveTime: (modelUuid, incrementBy) => {
set((state) => {
const machine = state.machines.find(m => m.modelUuid === modelUuid);
@ -99,7 +129,6 @@ export const useMachineStore = create<MachineStore>()(
});
},
// Helpers
getMachineById: (modelUuid) => {
return get().machines.find(m => m.modelUuid === modelUuid);
},

View File

@ -33,27 +33,30 @@ type ProductsStore = {
pointUuid: string,
action: ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']
) => EventsSchema | undefined;
removeAction: (actionUuid: string) => EventsSchema | undefined;
removeAction: (productId: string, actionUuid: string) => EventsSchema | undefined;
updateAction: (
productId: string,
actionUuid: string,
updates: Partial<ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']>
) => EventsSchema | undefined;
// Trigger-level actions
addTrigger: (
productId: string,
actionUuid: string,
trigger: TriggerSchema
) => void;
removeTrigger: (triggerUuid: string) => void;
) => EventsSchema | undefined;
removeTrigger: (productId: string, triggerUuid: string) => EventsSchema | undefined;
updateTrigger: (
productId: string,
triggerUuid: string,
updates: Partial<TriggerSchema>
) => void;
// Renaming functions
renameProduct: (productId: string, newName: string) => void;
renameAction: (actionUuid: string, newName: string) => EventsSchema | undefined;
renameTrigger: (triggerUuid: string, newName: string) => void;
renameAction: (productId: string, actionUuid: string, newName: string) => EventsSchema | undefined;
renameTrigger: (productId: string, triggerUuid: string, newName: string) => void;
// Helper functions
getProductById: (productId: string) => { productName: string; productId: string; eventDatas: EventsSchema[] } | undefined;
@ -71,12 +74,15 @@ export const useProductStore = create<ProductsStore>()(
// Product-level actions
addProduct: (productName, productId) => {
set((state) => {
const existingProduct = state.products.find(p => p.productId === productId);
if (!existingProduct) {
const newProduct = {
productName,
productId: productId,
eventDatas: []
};
state.products.push(newProduct);
}
});
},
@ -106,8 +112,11 @@ export const useProductStore = create<ProductsStore>()(
set((state) => {
const product = state.products.find(p => p.productId === productId);
if (product) {
const existingEvent = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === event.modelUuid);
if (!existingEvent) {
product.eventDatas.push(event);
}
}
});
},
@ -120,7 +129,7 @@ export const useProductStore = create<ProductsStore>()(
});
},
deleteEvent: (modelUuid: string) => {
deleteEvent: (modelUuid) => {
set((state) => {
for (const product of state.products) {
product.eventDatas = product.eventDatas.filter(e => 'modelUuid' in e && e.modelUuid !== modelUuid);
@ -150,11 +159,17 @@ export const useProductStore = create<ProductsStore>()(
if (product) {
const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
if (event && 'points' in event) {
const existingPoint = (event as ConveyorEventSchema).points.find(p => p.uuid === point.uuid);
if (!existingPoint) {
(event as ConveyorEventSchema).points.push(point as ConveyorPointSchema);
}
} else if (event && 'point' in event) {
const existingPoint = (event as any).point?.uuid === point.uuid;
if (!existingPoint) {
(event as VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema).point = point as any;
}
}
}
});
},
@ -198,28 +213,34 @@ export const useProductStore = create<ProductsStore>()(
const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
if (event && 'points' in event) {
const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
if (point) {
if (point && (!point.action || point.action.actionUuid !== action.actionUuid)) {
point.action = action as any;
updatedEvent = JSON.parse(JSON.stringify(event));
}
} else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
if ('action' in (event as any).point) {
if (!(event as any).point.action || (event as any).point.action.actionUuid !== action.actionUuid) {
(event as any).point.action = action;
updatedEvent = JSON.parse(JSON.stringify(event));
}
} else if ('actions' in (event as any).point) {
const existingAction = (event as any).point.actions.find((a: any) => a.actionUuid === action.actionUuid);
if (!existingAction) {
(event as any).point.actions.push(action);
updatedEvent = JSON.parse(JSON.stringify(event));
}
}
}
}
});
return updatedEvent;
},
removeAction: (actionUuid: string) => {
removeAction: (productId, actionUuid) => {
let updatedEvent: EventsSchema | undefined;
set((state) => {
for (const product of state.products) {
const product = state.products.find(p => p.productId === productId);
if (product) {
for (const event of product.eventDatas) {
if ('points' in event) {
// Handle ConveyorEventSchema
@ -248,10 +269,11 @@ export const useProductStore = create<ProductsStore>()(
return updatedEvent;
},
updateAction: (actionUuid, updates) => {
updateAction: (productId, actionUuid, updates) => {
let updatedEvent: EventsSchema | undefined;
set((state) => {
for (const product of state.products) {
const product = state.products.find(p => p.productId === productId);
if (product) {
for (const event of product.eventDatas) {
if ('points' in event) {
for (const point of (event as ConveyorEventSchema).points) {
@ -283,26 +305,40 @@ export const useProductStore = create<ProductsStore>()(
},
// Trigger-level actions
addTrigger: (actionUuid, trigger) => {
addTrigger: (productId, actionUuid, trigger) => {
let updatedEvent: EventsSchema | undefined;
set((state) => {
for (const product of state.products) {
const product = state.products.find(p => p.productId === productId);
if (product) {
for (const event of product.eventDatas) {
if ('points' in event) {
for (const point of (event as ConveyorEventSchema).points) {
if (point.action && point.action.actionUuid === actionUuid) {
const existingTrigger = point.action.triggers.find(t => t.triggerUuid === trigger.triggerUuid);
if (!existingTrigger) {
point.action.triggers.push(trigger);
updatedEvent = JSON.parse(JSON.stringify(event));
}
return;
}
}
} else if ('point' in event) {
const point = (event as any).point;
if ('action' in point && point.action.actionUuid === actionUuid) {
const existingTrigger = point.action.triggers.find((t: any) => t.triggerUuid === trigger.triggerUuid);
if (!existingTrigger) {
point.action.triggers.push(trigger);
updatedEvent = JSON.parse(JSON.stringify(event));
}
return;
} else if ('actions' in point) {
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
if (action) {
const existingTrigger = action.triggers.find((t: any) => t.triggerUuid === trigger.triggerUuid);
if (!existingTrigger) {
action.triggers.push(trigger);
updatedEvent = JSON.parse(JSON.stringify(event));
}
return;
}
}
@ -310,26 +346,41 @@ export const useProductStore = create<ProductsStore>()(
}
}
});
return updatedEvent;
},
removeTrigger: (triggerUuid) => {
removeTrigger: (productId, triggerUuid) => {
let updatedEvent: EventsSchema | undefined;
set((state) => {
for (const product of state.products) {
const product = state.products.find(p => p.productId === productId);
if (product) {
for (const event of product.eventDatas) {
if ('points' in event) {
for (const point of (event as ConveyorEventSchema).points) {
if (point.action && 'triggers' in point.action) {
const Trigger = point.action.triggers.find(t => t.triggerUuid === triggerUuid);
if (Trigger) {
point.action.triggers = point.action.triggers.filter(t => t.triggerUuid !== triggerUuid);
updatedEvent = JSON.parse(JSON.stringify(event));
}
}
}
} else if ('point' in event) {
const point = (event as any).point;
if ('action' in point && 'triggers' in point.action) {
const Trigger = point.action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
if (Trigger) {
point.action.triggers = point.action.triggers.filter((t: any) => t.triggerUuid !== triggerUuid);
updatedEvent = JSON.parse(JSON.stringify(event));
}
} else if ('actions' in point) {
for (const action of point.actions) {
if ('triggers' in action) {
const Trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
if (Trigger) {
action.triggers = action.triggers.filter((t: any) => t.triggerUuid !== triggerUuid);
updatedEvent = JSON.parse(JSON.stringify(event));
}
}
}
}
@ -337,11 +388,13 @@ export const useProductStore = create<ProductsStore>()(
}
}
});
return updatedEvent;
},
updateTrigger: (triggerUuid, updates) => {
updateTrigger: (productId, triggerUuid, updates) => {
set((state) => {
for (const product of state.products) {
const product = state.products.find(p => p.productId === productId);
if (product) {
for (const event of product.eventDatas) {
if ('points' in event) {
for (const point of (event as ConveyorEventSchema).points) {
@ -388,10 +441,11 @@ export const useProductStore = create<ProductsStore>()(
});
},
renameAction: (actionUuid, newName) => {
renameAction: (productId, actionUuid, newName) => {
let updatedEvent: EventsSchema | undefined;
set((state) => {
for (const product of state.products) {
const product = state.products.find(p => p.productId === productId);
if (product) {
for (const event of product.eventDatas) {
if ('points' in event) {
for (const point of (event as ConveyorEventSchema).points) {
@ -422,9 +476,10 @@ export const useProductStore = create<ProductsStore>()(
return updatedEvent;
},
renameTrigger: (triggerUuid, newName) => {
renameTrigger: (productId, triggerUuid, newName) => {
set((state) => {
for (const product of state.products) {
const product = state.products.find(p => p.productId === productId);
if (product) {
for (const event of product.eventDatas) {
if ('points' in event) {
for (const point of (event as ConveyorEventSchema).points) {

View File

@ -115,3 +115,35 @@ export const useSelectedAction = create<SelectedActionState>()(
},
}))
);
interface IsDraggingState {
isDragging: "start" | "end" | null;
setIsDragging: (state: "start" | "end" | null) => void;
}
export const useIsDragging = create<IsDraggingState>()(
immer((set) => ({
isDragging: null,
setIsDragging: (state) => {
set((s) => {
s.isDragging = state;
});
},
}))
);
interface IsRotatingState {
isRotating: "start" | "end" | null;
setIsRotating: (state: "start" | "end" | null) => void;
}
export const useIsRotating = create<IsRotatingState>()(
immer((set) => ({
isRotating: null,
setIsRotating: (state) => {
set((s) => {
s.isRotating = state;
});
},
}))
);

View File

@ -4,26 +4,22 @@ import { immer } from 'zustand/middleware/immer';
interface StorageUnitStore {
storageUnits: StorageUnitStatus[];
// Actions
addStorageUnit: (productId: string, storageUnit: StorageEventSchema) => void;
removeStorageUnit: (modelUuid: string) => void;
updateStorageUnit: (
modelUuid: string,
updates: Partial<Omit<StorageUnitStatus, 'modelUuid' | 'productId'>>
) => void;
clearStorageUnits: () => void;
// Status updates
setStorageUnitActive: (modelUuid: string, isActive: boolean) => void;
setStorageUnitState: (modelUuid: string, newState: StorageUnitStatus['state']) => void;
// Load updates
updateStorageUnitLoad: (modelUuid: string, incrementBy: number) => void;
// Time tracking
incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
// Helpers
getStorageUnitById: (modelUuid: string) => StorageUnitStatus | undefined;
getStorageUnitsByProduct: (productId: string) => StorageUnitStatus[];
getStorageUnitsBystate: (state: string) => StorageUnitStatus[];
@ -37,9 +33,10 @@ export const useStorageUnitStore = create<StorageUnitStore>()(
immer((set, get) => ({
storageUnits: [],
// Actions
addStorageUnit: (productId, storageUnit) => {
set((state) => {
const exists = state.storageUnits.some(s => s.modelUuid === storageUnit.modelUuid);
if (!exists) {
state.storageUnits.push({
...storageUnit,
productId,
@ -49,6 +46,7 @@ export const useStorageUnitStore = create<StorageUnitStore>()(
currentLoad: 0,
state: 'idle',
});
}
});
},
@ -67,7 +65,12 @@ export const useStorageUnitStore = create<StorageUnitStore>()(
});
},
// Status updates
clearStorageUnits: () => {
set(() => ({
storageUnits: [],
}));
},
setStorageUnitActive: (modelUuid, isActive) => {
set((state) => {
const unit = state.storageUnits.find(s => s.modelUuid === modelUuid);
@ -86,7 +89,6 @@ export const useStorageUnitStore = create<StorageUnitStore>()(
});
},
// Load updates
updateStorageUnitLoad: (modelUuid, incrementBy) => {
set((state) => {
const unit = state.storageUnits.find(s => s.modelUuid === modelUuid);
@ -96,7 +98,6 @@ export const useStorageUnitStore = create<StorageUnitStore>()(
});
},
// Time tracking
incrementActiveTime: (modelUuid, incrementBy) => {
set((state) => {
const unit = state.storageUnits.find(s => s.modelUuid === modelUuid);
@ -115,7 +116,6 @@ export const useStorageUnitStore = create<StorageUnitStore>()(
});
},
// Helpers
getStorageUnitById: (modelUuid) => {
return get().storageUnits.find(s => s.modelUuid === modelUuid);
},

View File

@ -20,6 +20,7 @@ interface VehiclesStore {
modelUuid: string,
updates: Partial<Omit<VehicleStatus, 'modelUuid' | 'productId'>>
) => void;
clearvehicles: () => void;
setVehicleActive: (modelUuid: string, isActive: boolean) => void;
updateSteeringAngle: (modelUuid: string, steeringAngle: number) => void;
@ -41,6 +42,8 @@ export const useVehicleStore = create<VehiclesStore>()(
addVehicle: (productId, event) => {
set((state) => {
const exists = state.vehicles.some(v => v.modelUuid === event.modelUuid);
if (!exists) {
state.vehicles.push({
...event,
productId,
@ -50,6 +53,7 @@ export const useVehicleStore = create<VehiclesStore>()(
currentLoad: 0,
distanceTraveled: 0,
});
}
});
},
@ -68,6 +72,12 @@ export const useVehicleStore = create<VehiclesStore>()(
});
},
clearvehicles: () => {
set((state) => {
state.vehicles = [];
});
},
setVehicleActive: (modelUuid, isActive) => {
set((state) => {
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);

View File

@ -88,6 +88,7 @@ interface StoragePointSchema {
actionType: "store";
materials: { materialName: string; materialId: string; }[];
storageCapacity: number;
triggers: TriggerSchema[];
};
}
@ -143,6 +144,10 @@ interface MachineStatus extends MachineEventSchema {
isActive: boolean;
idleTime: number;
activeTime: number;
currentAction?: {
actionUuid: string;
actionName: string;
};
}
interface ArmBotStatus extends RoboticArmEventSchema {