From cd737ed74cfa87c3bb7b28570aec3f874c243136 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Tue, 22 Apr 2025 19:02:44 +0530 Subject: [PATCH 01/22] feat: Implement Points management with PointsCreator component; enhance event handling and transform controls for simulation points --- .../geomentries/assets/addAssetModel.ts | 97 ++++++++++-- .../events/points/creator/pointsCreator.tsx | 148 ++++++++++++++++++ .../simulation/events/points/points.tsx | 12 ++ app/src/modules/simulation/simulation.tsx | 7 +- .../modules/simulation/vehicle/vehicles.tsx | 2 +- app/src/types/simulationTypes.d.ts | 2 +- 6 files changed, 248 insertions(+), 20 deletions(-) create mode 100644 app/src/modules/simulation/events/points/creator/pointsCreator.tsx create mode 100644 app/src/modules/simulation/events/points/points.tsx diff --git a/app/src/modules/builder/geomentries/assets/addAssetModel.ts b/app/src/modules/builder/geomentries/assets/addAssetModel.ts index 5837958..5bdb558 100644 --- a/app/src/modules/builder/geomentries/assets/addAssetModel.ts +++ b/app/src/modules/builder/geomentries/assets/addAssetModel.ts @@ -184,24 +184,9 @@ async function handleModelLoad( ); if (!data || !data.points) return; - console.log('data: ', data); - - const createMarker = (point: THREE.Vector3) => { - const sphere = new THREE.SphereGeometry(0.1, 15); - const material = new THREE.MeshStandardMaterial(); - const mesh = new THREE.Mesh(sphere, material); - mesh.position.copy(point); - return mesh; - }; - - if (data.points && data.points.length > 0) { - data.points.forEach((Point) => { - model.add(createMarker(Point)); - }); - } if (selectedItem.type === "Conveyor") { - const event: ConveyorEventSchema = { + const ConveyorEvent: ConveyorEventSchema = { modelUuid: newFloorItem.modeluuid, modelName: newFloorItem.modelname, position: newFloorItem.position, @@ -225,7 +210,85 @@ async function handleModelLoad( } })) } - addEvent(event); + addEvent(ConveyorEvent); + } else if (selectedItem.type === "Vehicle") { + const vehicleEvent: VehicleEventSchema = { + modelUuid: newFloorItem.modeluuid, + modelName: newFloorItem.modelname, + position: newFloorItem.position, + rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], + state: "idle", + type: "vehicle", + speed: 1, + point: { + uuid: THREE.MathUtils.generateUUID(), + position: [data.points[0].x, data.points[0].y, data.points[0].z], + rotation: [0, 0, 0], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Vehicle Action", + actionType: "travel", + material: null, + unLoadDuration: 5, + loadCapacity: 10, + pickUpPoint: null, + unLoadPoint: null, + triggers: [] + } + } + }; + addEvent(vehicleEvent); + } else if (selectedItem.type === "ArmBot") { + const roboticArmEvent: RoboticArmEventSchema = { + modelUuid: newFloorItem.modeluuid, + modelName: newFloorItem.modelname, + position: newFloorItem.position, + rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], + state: "idle", + type: "roboticArm", + speed: 1, + point: { + uuid: THREE.MathUtils.generateUUID(), + position: [data.points[0].x, data.points[0].y, data.points[0].z], + rotation: [0, 0, 0], + actions: [ + { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Pick and Place", + actionType: "pickAndPlace", + process: { + startPoint: "start-point-uuid", + endPoint: "end-point-uuid" + }, + triggers: [] + } + ] + } + }; + addEvent(roboticArmEvent); + } else if (selectedItem.type === "Machine") { + const machineEvent: MachineEventSchema = { + modelUuid: newFloorItem.modeluuid, + modelName: newFloorItem.modelname, + position: newFloorItem.position, + rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], + state: "idle", + type: "machine", + point: { + uuid: THREE.MathUtils.generateUUID(), + position: [data.points[0].x, data.points[0].y, data.points[0].z], + rotation: [0, 0, 0], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Process Action", + actionType: "process", + processTime: 10, + swapMaterial: "material-id", + triggers: [] + } + } + }; + addEvent(machineEvent); } } diff --git a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx new file mode 100644 index 0000000..335f1f5 --- /dev/null +++ b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx @@ -0,0 +1,148 @@ +import React, { useEffect, useRef, useState } from 'react'; +import * as THREE from 'three'; +import { useEventsStore } from '../../../../../store/simulation/useEventsStore'; +import useModuleStore from '../../../../../store/useModuleStore'; +import { TransformControls } from '@react-three/drei'; +import { detectModifierKeys } from '../../../../../utils/shortcutkeys/detectModifierKeys'; + +function PointsCreator() { + const { events, updatePoint, getPointByUuid } = useEventsStore(); + const { activeModule } = useModuleStore(); + const transformRef = useRef(null); + const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null); + const [selectedPoint, setSelectedPoint] = useState(null); + const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({}); + + useEffect(() => { + setTransformMode(null); + const handleKeyDown = (e: KeyboardEvent) => { + const keyCombination = detectModifierKeys(e); + if (!selectedPoint) return; + if (keyCombination === "G") { + setTransformMode((prev) => (prev === "translate" ? null : "translate")); + } + if (keyCombination === "R") { + setTransformMode((prev) => (prev === "rotate" ? null : "rotate")); + } + }; + + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [selectedPoint]); + + const updatePointToState = (selectedPoint: THREE.Mesh) => { + let point = JSON.parse(JSON.stringify(getPointByUuid(selectedPoint.userData.modelUuid, selectedPoint.userData.pointUuid))); + if (point) { + point.position = [selectedPoint.position.x, selectedPoint.position.y, selectedPoint.position.z]; + updatePoint(selectedPoint.userData.modelUuid, selectedPoint.userData.pointUuid, point) + } + } + + return ( + <> + {activeModule === 'simulation' && + <> + + {events.map((event, i) => { + if (event.type === 'transfer') { + return ( + + {event.points.map((point, j) => ( + (sphereRefs.current[point.uuid] = el!)} + onClick={(e) => { + e.stopPropagation(); + setSelectedPoint(sphereRefs.current[point.uuid]); + }} + onPointerMissed={() => { + setSelectedPoint(null); + }} + key={`${i}-${j}`} + position={new THREE.Vector3(...point.position)} + userData={{ modelUuid: event.modelUuid, pointUuid: point.uuid }} + > + + + + ))} + + ); + } else if (event.type === 'vehicle') { + return ( + + (sphereRefs.current[event.point.uuid] = el!)} + onClick={(e) => { + e.stopPropagation(); + setSelectedPoint(sphereRefs.current[event.point.uuid]); + }} + onPointerMissed={() => { + setSelectedPoint(null); + }} + position={new THREE.Vector3(...event.point.position)} + userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} + > + + + + + ); + } else if (event.type === 'roboticArm') { + return ( + + (sphereRefs.current[event.point.uuid] = el!)} + onClick={(e) => { + e.stopPropagation(); + setSelectedPoint(sphereRefs.current[event.point.uuid]); + }} + onPointerMissed={() => { + setSelectedPoint(null); + }} + position={new THREE.Vector3(...event.point.position)} + userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} + > + + + + + ); + } else if (event.type === 'machine') { + return ( + + (sphereRefs.current[event.point.uuid] = el!)} + onClick={(e) => { + e.stopPropagation(); + setSelectedPoint(sphereRefs.current[event.point.uuid]); + }} + onPointerMissed={() => { + setSelectedPoint(null); + }} + position={new THREE.Vector3(...event.point.position)} + userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} + > + + + + + ); + } else { + return null; + } + })} + + {(selectedPoint && transformMode) && + { updatePointToState(selectedPoint) }} /> + } + + } + + ); +} + +export default PointsCreator; diff --git a/app/src/modules/simulation/events/points/points.tsx b/app/src/modules/simulation/events/points/points.tsx new file mode 100644 index 0000000..2a50f2d --- /dev/null +++ b/app/src/modules/simulation/events/points/points.tsx @@ -0,0 +1,12 @@ +import React from 'react' +import PointsCreator from './creator/pointsCreator' + +function Points() { + return ( + <> + + + ) +} + +export default Points \ No newline at end of file diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index 1f30e00..1be292e 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -2,6 +2,7 @@ import React, { useEffect } from 'react'; import { useEventsStore } from '../../store/simulation/useEventsStore'; import { useProductStore } from '../../store/simulation/useProductStore'; import Vehicles from './vehicle/vehicles'; +import Points from './events/points/points'; function Simulation() { const { events } = useEventsStore(); @@ -12,12 +13,16 @@ function Simulation() { }, [events]) useEffect(() => { - console.log('products: ', products); + // console.log('products: ', products); }, [products]) return ( <> + + + + ) } diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index 7a270d4..5d6681b 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -117,7 +117,7 @@ function Vehicles() { }, []) useEffect(() => { - console.log('vehicles: ', vehicles); + // console.log('vehicles: ', vehicles); }, [vehicles]) diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index 3d75662..2b3fc1e 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -119,7 +119,7 @@ interface StorageEventSchema extends AssetEventSchema { point: StoragePointSchema; } -type EventsSchema = ConveyorEventSchema | VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema | []; +type EventsSchema = ConveyorEventSchema | VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema; type productsSchema = { productName: string; From 58b0e779fd326ebf319ea43abf97f242c20c961c Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 23 Apr 2025 12:27:02 +0530 Subject: [PATCH 02/22] Revert "Merge remote-tracking branch 'origin/simulation-agv-v2' into v2" This reverts commit 27c7072cc918b14f64cddd21501887cb11cdd040, reversing changes made to cd737ed74cfa87c3bb7b28570aec3f874c243136. --- .../builder/groups/floorItemsGroup.tsx | 4 +- .../instances/animator/vehicleAnimator.tsx | 36 +--------- .../instances/instance/vehicleInstance.tsx | 67 ++----------------- .../vehicle/instances/vehicleInstances.tsx | 6 +- .../modules/simulation/vehicle/vehicles.tsx | 64 ++---------------- 5 files changed, 20 insertions(+), 157 deletions(-) diff --git a/app/src/modules/builder/groups/floorItemsGroup.tsx b/app/src/modules/builder/groups/floorItemsGroup.tsx index 04376ce..23fa80d 100644 --- a/app/src/modules/builder/groups/floorItemsGroup.tsx +++ b/app/src/modules/builder/groups/floorItemsGroup.tsx @@ -16,11 +16,11 @@ import addAssetModel from "../geomentries/assets/addAssetModel"; import { getFloorAssets } from "../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi"; import useModuleStore from "../../../store/useModuleStore"; // import { retrieveGLTF } from "../../../utils/indexDB/idbUtils"; - -import { useEventsStore } from "../../../store/simulation/useEventsStore"; const assetManagerWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/assetManagerWorker.js", import.meta.url)); const gltfLoaderWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js", import.meta.url)); +import { useEventsStore } from "../../../store/simulation/useEventsStore"; + const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject, floorGroup, tempLoader, isTempLoader, plane, }: any) => { const state: Types.ThreeState = useThree(); const { raycaster, controls }: any = state; diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx index db6bedb..14cb6fa 100644 --- a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx +++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx @@ -1,38 +1,6 @@ -import { useFrame, useThree } from '@react-three/fiber'; -import React, { useEffect, useState } from 'react' +import React from 'react' -interface VehicleAnimatorProps { - path: [number, number, number][]; - handleCallBack: () => void; - currentPhase: string; - agvUuid: number -} - - -function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid }: VehicleAnimatorProps) { - - const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); - const { scene } = useThree(); - - useEffect(() => { - - if (currentPhase === 'stationed-pickup' && path.length > 0) { - - - setCurrentPath(path); - - } - - }, [currentPhase, path]) - - useFrame(() => { - if (currentPath.length === 0) return; - const object = scene.getObjectByProperty("uuid", agvUuid); - if (!object) return; - - - - }) +function VehicleAnimator() { return ( <> diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index e381311..0996b3c 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -1,67 +1,14 @@ -import React, { useCallback, useEffect, useState } from 'react' +import React from 'react' import VehicleAnimator from '../animator/vehicleAnimator' -import * as THREE from "three"; -import { NavMeshQuery } from '@recast-navigation/core'; -import { useNavMesh } from '../../../../../store/store'; -import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; -import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; -function VehicleInstance({ agvDetails }: any) { - const { navMesh } = useNavMesh(); - const { isPlaying } = usePlayButtonStore(); - const { setVehicleActive, setVehicleState } = useVehicleStore(); - const [currentPhase, setCurrentPhase] = useState<(string)>("stationed"); - const [path, setPath] = useState<[number, number, number][]>([]); +function VehicleInstance() { + return ( + <> - const computePath = useCallback((start: any, end: any) => { + - - try { - const navMeshQuery = new NavMeshQuery(navMesh); - const { path: segmentPath } = navMeshQuery.computePath(start, end); - return ( - segmentPath?.map( - ({ x, y, z }) => [x, y + 0.1, z] as [number, number, number] - ) || [] - ); - } catch { - return []; - } - }, [navMesh]); - - useEffect(() => { - // const pickupToDropPath = computePath(pickup, drop); - // const dropToPickupPath = computePath(drop, pickup); - - if (isPlaying) { - if (!agvDetails.isActive && agvDetails.state == "idle" && currentPhase == "stationed") { - const toPickupPath = computePath(new THREE.Vector3(agvDetails.position[0], agvDetails.position[1], agvDetails.position[2]), agvDetails.point.action.pickUpPoint); - setPath(toPickupPath) - setVehicleActive(agvDetails.modelUuid, true) - setVehicleState(agvDetails.modelUuid, "running") - setCurrentPhase("stationed-pickup") - // - } - } - }, [agvDetails, currentPhase, path, isPlaying]) - - function handleCallBack() { - if (currentPhase === "stationed-pickup") { - setVehicleActive(agvDetails.modelUuid, false) - setVehicleState(agvDetails.modelUuid, "idle") - setCurrentPhase("picking") - setPath([]) - } - } - - - return ( - <> - - - - - ) + + ) } export default VehicleInstance \ No newline at end of file diff --git a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx index f3f1435..13e15b7 100644 --- a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx +++ b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx @@ -1,13 +1,11 @@ import React from 'react' import VehicleInstance from './instance/vehicleInstance' -function VehicleInstances({ vehicles }: any) { +function VehicleInstances() { return ( <> - {vehicles.map((val: any, i: any) => - - )} + ) diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index 9fb8b90..5d6681b 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -9,8 +9,8 @@ function Vehicles() { const vehicleStatusSample: VehicleStatus[] = [ { - modelUuid: "2c01ed76-359a-485b-83d4-052cfcdb9d89", - modelName: "AGV", + modelUuid: "veh-123", + modelName: "Autonomous Truck A1", position: [10, 0, 5], rotation: [0, 0, 0], state: "idle", @@ -18,7 +18,7 @@ function Vehicles() { speed: 2.5, point: { uuid: "point-789", - position: [93.42159216649789, 0, 23.790878603572857], + position: [0, 1, 0], rotation: [0, 0, 0], action: { actionUuid: "action-456", @@ -59,58 +59,9 @@ function Vehicles() { distanceTraveled: 0 }, { - modelUuid: "311130b9-4f2e-425a-b3b5-5039cb348806", - modelName: "AGV", - position: [95.69567023145055, 0, 33.18042399595448], - 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", - material: "crate", - unLoadDuration: 15, - loadCapacity: 5, - pickUpPoint: { x: 5, y: 0, z: 3 }, - unLoadPoint: { x: 20, y: 0, z: 10 }, - 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 - } - ] - } - }, - productId: "prod-890", - isActive: false, - idleTime: 0, - activeTime: 0, - currentLoad: 0, - distanceTraveled: 0 - }, { - modelUuid: "fa54132c-8333-4832-becb-5281f5e11549", - modelName: "AGV", - position: [102.71483985219794, 0, 23.66321267938962], + modelUuid: "veh-123", + modelName: "Autonomous Truck A1", + position: [10, 0, 5], rotation: [0, 0, 0], state: "idle", type: "vehicle", @@ -163,7 +114,6 @@ function Vehicles() { useEffect(() => { addVehicle('123', vehicleStatusSample[0]); addVehicle('123', vehicleStatusSample[1]); - addVehicle('123', vehicleStatusSample[2]); }, []) useEffect(() => { @@ -174,7 +124,7 @@ function Vehicles() { return ( <> - + ) From a965a403eeede962d4b0914169c12b5232c273e2 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 23 Apr 2025 12:29:16 +0530 Subject: [PATCH 03/22] feat: Add robotic arm components and integrate IKInstance; refactor vehicle status sample type --- .../instances/animator/roboticArmAnimator.tsx | 9 +++++++++ .../armInstance/roboticArmInstance.tsx | 17 +++++++++++++++++ .../instances/ikInstance/ikInstance.tsx | 9 +++++++++ .../roboticArm/instances/ikInstances.tsx | 14 ++++++++++++++ .../instances/roboticArmInstances.tsx | 14 ++++++++++++++ .../simulation/roboticArm/roboticArm.tsx | 15 +++++++++++++++ .../modules/simulation/vehicle/vehicles.tsx | 18 +++--------------- 7 files changed, 81 insertions(+), 15 deletions(-) create mode 100644 app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx create mode 100644 app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx create mode 100644 app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx create mode 100644 app/src/modules/simulation/roboticArm/instances/ikInstances.tsx create mode 100644 app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx create mode 100644 app/src/modules/simulation/roboticArm/roboticArm.tsx diff --git a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx new file mode 100644 index 0000000..0cd4fe2 --- /dev/null +++ b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +function RoboticArmAnimator() { + return ( + <> + ) +} + +export default RoboticArmAnimator; \ No newline at end of file diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx new file mode 100644 index 0000000..2817906 --- /dev/null +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -0,0 +1,17 @@ +import React from 'react' +import IKInstance from '../ikInstance/ikInstance'; +import RoboticArmAnimator from '../animator/roboticArmAnimator'; + +function RoboticArmInstance() { + return ( + <> + + + + + + + ) +} + +export default RoboticArmInstance; \ No newline at end of file diff --git a/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx new file mode 100644 index 0000000..52a8610 --- /dev/null +++ b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +function IKInstance() { + return ( + <> + ) +} + +export default IKInstance; \ No newline at end of file diff --git a/app/src/modules/simulation/roboticArm/instances/ikInstances.tsx b/app/src/modules/simulation/roboticArm/instances/ikInstances.tsx new file mode 100644 index 0000000..d44ddd2 --- /dev/null +++ b/app/src/modules/simulation/roboticArm/instances/ikInstances.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import IKInstance from './ikInstance/ikInstance'; + +function IkInstances() { + return ( + <> + + + + + ) +} + +export default IkInstances; \ No newline at end of file diff --git a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx new file mode 100644 index 0000000..6e8a70a --- /dev/null +++ b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import RoboticArmInstance from './armInstance/roboticArmInstance'; + +function RoboticArmInstances() { + return ( + <> + + + + + ) +} + +export default RoboticArmInstances; \ No newline at end of file diff --git a/app/src/modules/simulation/roboticArm/roboticArm.tsx b/app/src/modules/simulation/roboticArm/roboticArm.tsx new file mode 100644 index 0000000..1270d93 --- /dev/null +++ b/app/src/modules/simulation/roboticArm/roboticArm.tsx @@ -0,0 +1,15 @@ +import React from 'react' +import RoboticArmInstances from './instances/roboticArmInstances'; +import IkInstances from './instances/ikInstances'; + +function RoboticArm() { + return ( + <> + + + + + ) +} + +export default RoboticArm; \ No newline at end of file diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index 5d6681b..3364717 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -7,7 +7,7 @@ function Vehicles() { const { vehicles, addVehicle } = useVehicleStore(); - const vehicleStatusSample: VehicleStatus[] = [ + const vehicleStatusSample: VehicleEventSchema[] = [ { modelUuid: "veh-123", modelName: "Autonomous Truck A1", @@ -50,13 +50,7 @@ function Vehicles() { } ] } - }, - productId: "prod-890", - isActive: false, - idleTime: 0, - activeTime: 0, - currentLoad: 0, - distanceTraveled: 0 + } }, { modelUuid: "veh-123", @@ -100,13 +94,7 @@ function Vehicles() { } ] } - }, - productId: "prod-890", - isActive: false, - idleTime: 0, - activeTime: 0, - currentLoad: 0, - distanceTraveled: 0 + } } ]; From f8a6021b4eaba9de78cc704126889e7d9e0d3dde Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 23 Apr 2025 12:35:34 +0530 Subject: [PATCH 04/22] feat: Refactor VehicleInstance component to include path computation and state management --- .../instances/instance/vehicleInstance.tsx | 98 ++++++++++--------- 1 file changed, 54 insertions(+), 44 deletions(-) diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index 6b6bd78..bf767ec 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -1,56 +1,66 @@ -import React, { useEffect } from 'react' +import React, { useCallback, useEffect, useState } from 'react' import VehicleAnimator from '../animator/vehicleAnimator' +import * as THREE from "three"; import { NavMeshQuery } from '@recast-navigation/core'; +import { useNavMesh } from '../../../../../store/store'; +import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; +import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; -function VehicleInstance() { +function VehicleInstance({ agvDetails }: any) { + const { navMesh } = useNavMesh(); + const { isPlaying } = usePlayButtonStore(); + const { setVehicleActive, setVehicleState } = useVehicleStore(); + const [currentPhase, setCurrentPhase] = useState<(string)>("stationed"); + const [path, setPath] = useState<[number, number, number][]>([]); - useEffect(() => { - try { - const navMeshQuery = new NavMeshQuery(navMesh); - const { path: segmentPath } = navMeshQuery.computePath(start, end); - return ( - segmentPath?.map( - ({ x, y, z }) => [x, y + 0.1, z] as [number, number, number] - ) || [] - ); - } catch { - return []; + const computePath = useCallback((start: any, end: any) => { + + + try { + const navMeshQuery = new NavMeshQuery(navMesh); + const { path: segmentPath } = navMeshQuery.computePath(start, end); + return ( + segmentPath?.map( + ({ x, y, z }) => [x, y + 0.1, z] as [number, number, number] + ) || [] + ); + } catch { + return []; + } + }, [navMesh]); + + useEffect(() => { + + + if (isPlaying) { + if (!agvDetails.isActive && agvDetails.state == "idle" && currentPhase == "stationed") { + const toPickupPath = computePath(new THREE.Vector3(agvDetails.position[0], agvDetails.position[1], agvDetails.position[2]), agvDetails.point.action.pickUpPoint); + setPath(toPickupPath) + setVehicleActive(agvDetails.modelUuid, true) + setVehicleState(agvDetails.modelUuid, "running") + setCurrentPhase("stationed-pickup") + // + } + } + }, [agvDetails, currentPhase, path, isPlaying]) + + function handleCallBack() { + if (currentPhase === "stationed-pickup") { + setVehicleActive(agvDetails.modelUuid, false) + setVehicleState(agvDetails.modelUuid, "idle") + setCurrentPhase("picking") + setPath([]) + } } - }, [navMesh]); - - useEffect(() => { - // const pickupToDropPath = computePath(pickup, drop); - // const dropToPickupPath = computePath(drop, pickup); - - if (isPlaying) { - if (!agvDetails.isActive && agvDetails.state == "idle" && currentPhase == "stationed") { - const toPickupPath = computePath(new THREE.Vector3(agvDetails.position[0], agvDetails.position[1], agvDetails.position[2]), agvDetails.point.action.pickUpPoint); - setPath(toPickupPath) - setVehicleActive(agvDetails.modelUuid, true) - setVehicleState(agvDetails.modelUuid, "running") - setCurrentPhase("stationed-pickup") - // - } - } - }, [agvDetails, currentPhase, path, isPlaying]) - - function handleCallBack() { - if (currentPhase === "stationed-pickup") { - setVehicleActive(agvDetails.modelUuid, false) - setVehicleState(agvDetails.modelUuid, "idle") - setCurrentPhase("picking") - setPath([]) - } - } - return ( - <> + return ( + <> - + - - ) + + ) } export default VehicleInstance \ No newline at end of file From faed625c2ae1656dda15794c40615d21f97cf8e5 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 23 Apr 2025 13:03:27 +0530 Subject: [PATCH 05/22] feat: Update VehicleAnimator and VehicleInstances components to enhance path handling and integrate vehicle data --- .../vehicle/instances/animator/vehicleAnimator.tsx | 1 + .../simulation/vehicle/instances/vehicleInstances.tsx | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx index f3a4ed5..cf5fd81 100644 --- a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx +++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx @@ -21,6 +21,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid }: Vehicl } }, [currentPhase, path]) + useFrame((_, delta) => { if (!path || path.length < 2) return; diff --git a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx index 13e15b7..0848883 100644 --- a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx +++ b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx @@ -1,11 +1,16 @@ import React from 'react' import VehicleInstance from './instance/vehicleInstance' +import { useVehicleStore } from '../../../../store/simulation/useVehicleStore'; function VehicleInstances() { + const { vehicles } = useVehicleStore(); + return ( <> - + {vehicles.map((val: any, i: any) => + + )} ) From 04f91585e65618ec95fc1a23a776124da1c291bf Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 23 Apr 2025 14:53:27 +0530 Subject: [PATCH 06/22] feat: Update simulation stores and types to enhance robotic arm and vehicle handling --- .../geomentries/assets/addAssetModel.ts | 4 +- .../builder/groups/floorItemsGroup.tsx | 4 +- app/src/store/simulation/useArmBotStore.ts | 39 +++++++++---------- app/src/store/simulation/useConveyorStore.ts | 7 ---- app/src/store/simulation/useMachineStore.ts | 7 ---- .../store/simulation/useStorageUnitStore.ts | 8 ---- app/src/store/simulation/useVehicleStore.ts | 16 ++++++-- app/src/types/simulationTypes.d.ts | 36 ++++++++++++++++- 8 files changed, 71 insertions(+), 50 deletions(-) diff --git a/app/src/modules/builder/geomentries/assets/addAssetModel.ts b/app/src/modules/builder/geomentries/assets/addAssetModel.ts index 5bdb558..193dd41 100644 --- a/app/src/modules/builder/geomentries/assets/addAssetModel.ts +++ b/app/src/modules/builder/geomentries/assets/addAssetModel.ts @@ -257,8 +257,8 @@ async function handleModelLoad( actionName: "Pick and Place", actionType: "pickAndPlace", process: { - startPoint: "start-point-uuid", - endPoint: "end-point-uuid" + startPoint: [0, 0, 0], + endPoint: [0, 0, 0] }, triggers: [] } diff --git a/app/src/modules/builder/groups/floorItemsGroup.tsx b/app/src/modules/builder/groups/floorItemsGroup.tsx index 23fa80d..2a3c2cc 100644 --- a/app/src/modules/builder/groups/floorItemsGroup.tsx +++ b/app/src/modules/builder/groups/floorItemsGroup.tsx @@ -16,11 +16,11 @@ import addAssetModel from "../geomentries/assets/addAssetModel"; import { getFloorAssets } from "../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi"; import useModuleStore from "../../../store/useModuleStore"; // import { retrieveGLTF } from "../../../utils/indexDB/idbUtils"; +import { useEventsStore } from "../../../store/simulation/useEventsStore"; + const assetManagerWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/assetManagerWorker.js", import.meta.url)); const gltfLoaderWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js", import.meta.url)); -import { useEventsStore } from "../../../store/simulation/useEventsStore"; - const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject, floorGroup, tempLoader, isTempLoader, plane, }: any) => { const state: Types.ThreeState = useThree(); const { raycaster, controls }: any = state; diff --git a/app/src/store/simulation/useArmBotStore.ts b/app/src/store/simulation/useArmBotStore.ts index 7dd4716..493a068 100644 --- a/app/src/store/simulation/useArmBotStore.ts +++ b/app/src/store/simulation/useArmBotStore.ts @@ -1,17 +1,6 @@ import { create } from 'zustand'; import { immer } from 'zustand/middleware/immer'; -interface ArmBotStatus extends RoboticArmEventSchema { - productId: string; - isActive: boolean; - idleTime: number; - activeTime: number; - currentAction?: { - actionUuid: string; - actionName: string; - }; -} - interface ArmBotStore { armBots: ArmBotStatus[]; @@ -22,9 +11,11 @@ interface ArmBotStore { updates: Partial> ) => void; - startAction: (modelUuid: string, actionUuid: string) => void; - completeAction: (modelUuid: string) => void; - cancelAction: (modelUuid: string) => void; + addCurrentAction: (modelUuid: string, actionUuid: string) => void; + removeCurrentAction: (modelUuid: string) => void; + + addAction: (modelUuid: string, action: RoboticArmPointSchema['actions'][number]) => void; + removeAction: (modelUuid: string, actionUuid: string) => void; setArmBotActive: (modelUuid: string, isActive: boolean) => void; @@ -71,7 +62,7 @@ export const useArmBotStore = create()( }); }, - startAction: (modelUuid, actionUuid) => { + addCurrentAction: (modelUuid, actionUuid) => { set((state) => { const armBot = state.armBots.find(a => a.modelUuid === modelUuid); if (armBot) { @@ -87,22 +78,30 @@ export const useArmBotStore = create()( }); }, - completeAction: (modelUuid) => { + removeCurrentAction: (modelUuid) => { set((state) => { const armBot = state.armBots.find(a => a.modelUuid === modelUuid); - if (armBot && armBot.currentAction) { + if (armBot) { armBot.currentAction = undefined; armBot.isActive = false; } }); }, - cancelAction: (modelUuid) => { + addAction: (modelUuid, action) => { set((state) => { const armBot = state.armBots.find(a => a.modelUuid === modelUuid); if (armBot) { - armBot.currentAction = undefined; - armBot.isActive = false; + armBot.point.actions.push(action); + } + }); + }, + + removeAction: (modelUuid, actionUuid) => { + set((state) => { + const armBot = state.armBots.find(a => a.modelUuid === modelUuid); + if (armBot) { + armBot.point.actions = armBot.point.actions.filter(a => a.actionUuid !== actionUuid); } }); }, diff --git a/app/src/store/simulation/useConveyorStore.ts b/app/src/store/simulation/useConveyorStore.ts index 059e76b..15dbf34 100644 --- a/app/src/store/simulation/useConveyorStore.ts +++ b/app/src/store/simulation/useConveyorStore.ts @@ -1,13 +1,6 @@ import { create } from 'zustand'; import { immer } from 'zustand/middleware/immer'; -interface ConveyorStatus extends ConveyorEventSchema { - productId: string; - isActive: boolean; - idleTime: number; - activeTime: number; -} - interface ConveyorStore { conveyors: ConveyorStatus[]; diff --git a/app/src/store/simulation/useMachineStore.ts b/app/src/store/simulation/useMachineStore.ts index 15997b9..cc927f7 100644 --- a/app/src/store/simulation/useMachineStore.ts +++ b/app/src/store/simulation/useMachineStore.ts @@ -1,13 +1,6 @@ import { create } from 'zustand'; import { immer } from 'zustand/middleware/immer'; -interface MachineStatus extends MachineEventSchema { - productId: string; - isActive: boolean; - idleTime: number; - activeTime: number; -} - interface MachineStore { machines: MachineStatus[]; diff --git a/app/src/store/simulation/useStorageUnitStore.ts b/app/src/store/simulation/useStorageUnitStore.ts index 04b4db0..d729708 100644 --- a/app/src/store/simulation/useStorageUnitStore.ts +++ b/app/src/store/simulation/useStorageUnitStore.ts @@ -1,14 +1,6 @@ import { create } from 'zustand'; import { immer } from 'zustand/middleware/immer'; -interface StorageUnitStatus extends StorageEventSchema { - productId: string; - isActive: boolean; - idleTime: number; - activeTime: number; - currentLoad: number; -} - interface StorageUnitStore { storageUnits: StorageUnitStatus[]; diff --git a/app/src/store/simulation/useVehicleStore.ts b/app/src/store/simulation/useVehicleStore.ts index 9f7ac50..ce28916 100644 --- a/app/src/store/simulation/useVehicleStore.ts +++ b/app/src/store/simulation/useVehicleStore.ts @@ -21,7 +21,8 @@ interface VehiclesStore { ) => void; setVehicleActive: (modelUuid: string, isActive: boolean) => void; - updateVehicleLoad: (modelUuid: string, load: number) => void; + incrementVehicleLoad: (modelUuid: string, incrementBy: number) => void; + decrementVehicleLoad: (modelUuid: string, decrementBy: number) => void; setVehicleState: (modelUuid: string, newState: VehicleStatus['state']) => void; incrementActiveTime: (modelUuid: string, incrementBy: number) => void; incrementIdleTime: (modelUuid: string, incrementBy: number) => void; @@ -74,11 +75,20 @@ export const useVehicleStore = create()( }); }, - updateVehicleLoad: (modelUuid, load) => { + incrementVehicleLoad: (modelUuid, incrementBy) => { set((state) => { const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid); if (vehicle) { - vehicle.currentLoad = load; + vehicle.currentLoad += incrementBy; + } + }); + }, + + decrementVehicleLoad: (modelUuid, decrementBy) => { + set((state) => { + const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid); + if (vehicle) { + vehicle.currentLoad = decrementBy; } }); }, diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index 2b3fc1e..7c2bd2c 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -59,7 +59,7 @@ interface RoboticArmPointSchema { actionUuid: string; actionName: string; actionType: "pickAndPlace"; - process: { startPoint: string; endPoint: string }; + process: { startPoint: [number, number, number]; endPoint: [number, number, number] }; triggers: TriggerSchema[]; }[]; } @@ -127,6 +127,32 @@ type productsSchema = { eventsData: EventsSchema[]; }[] + +interface ConveyorStatus extends ConveyorEventSchema { + productId: string; + isActive: boolean; + idleTime: number; + activeTime: number; +} + +interface MachineStatus extends MachineEventSchema { + productId: string; + isActive: boolean; + idleTime: number; + activeTime: number; +} + +interface ArmBotStatus extends RoboticArmEventSchema { + productId: string; + isActive: boolean; + idleTime: number; + activeTime: number; + currentAction?: { + actionUuid: string; + actionName: string; + }; +} + interface VehicleStatus extends VehicleEventSchema { productId: string; isActive: boolean; @@ -134,4 +160,12 @@ interface VehicleStatus extends VehicleEventSchema { activeTime: number; currentLoad: number; distanceTraveled: number; +} + +interface StorageUnitStatus extends StorageEventSchema { + productId: string; + isActive: boolean; + idleTime: number; + activeTime: number; + currentLoad: number; } \ No newline at end of file From 6f93fc36c27b0a576e4b222c09728e686d874dac Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 23 Apr 2025 15:29:51 +0530 Subject: [PATCH 07/22] feat: Add Conveyor and RoboticArm components to simulation and integrate MaterialInstances --- .../modules/simulation/conveyor/conveyor.tsx | 14 ++++++++++++++ .../conveyorInstance/conveyorInstance.tsx | 10 ++++++++++ .../conveyor/instances/conveyorInstances.tsx | 14 ++++++++++++++ .../instances/animator/materialAnimator.tsx | 9 +++++++++ .../instances/instance/materialInstance.tsx | 9 +++++++++ .../materials/instances/materialInstances.tsx | 17 +++++++++++++++++ .../modules/simulation/materials/materials.tsx | 14 ++++++++++++++ app/src/modules/simulation/simulation.tsx | 8 +++++++- 8 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 app/src/modules/simulation/conveyor/conveyor.tsx create mode 100644 app/src/modules/simulation/conveyor/instances/conveyorInstance/conveyorInstance.tsx create mode 100644 app/src/modules/simulation/conveyor/instances/conveyorInstances.tsx create mode 100644 app/src/modules/simulation/materials/instances/animator/materialAnimator.tsx create mode 100644 app/src/modules/simulation/materials/instances/instance/materialInstance.tsx create mode 100644 app/src/modules/simulation/materials/instances/materialInstances.tsx create mode 100644 app/src/modules/simulation/materials/materials.tsx diff --git a/app/src/modules/simulation/conveyor/conveyor.tsx b/app/src/modules/simulation/conveyor/conveyor.tsx new file mode 100644 index 0000000..bd21523 --- /dev/null +++ b/app/src/modules/simulation/conveyor/conveyor.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import ConveyorInstances from './instances/conveyorInstances' + +function Conveyor() { + return ( + <> + + + + + ) +} + +export default Conveyor \ No newline at end of file diff --git a/app/src/modules/simulation/conveyor/instances/conveyorInstance/conveyorInstance.tsx b/app/src/modules/simulation/conveyor/instances/conveyorInstance/conveyorInstance.tsx new file mode 100644 index 0000000..9c9d612 --- /dev/null +++ b/app/src/modules/simulation/conveyor/instances/conveyorInstance/conveyorInstance.tsx @@ -0,0 +1,10 @@ +import React from 'react' + +function ConveyorInstance() { + return ( + <> + + ) +} + +export default ConveyorInstance \ No newline at end of file diff --git a/app/src/modules/simulation/conveyor/instances/conveyorInstances.tsx b/app/src/modules/simulation/conveyor/instances/conveyorInstances.tsx new file mode 100644 index 0000000..3f53784 --- /dev/null +++ b/app/src/modules/simulation/conveyor/instances/conveyorInstances.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import ConveyorInstance from './conveyorInstance/conveyorInstance' + +function ConveyorInstances() { + return ( + <> + + + + + ) +} + +export default ConveyorInstances \ No newline at end of file diff --git a/app/src/modules/simulation/materials/instances/animator/materialAnimator.tsx b/app/src/modules/simulation/materials/instances/animator/materialAnimator.tsx new file mode 100644 index 0000000..1445e70 --- /dev/null +++ b/app/src/modules/simulation/materials/instances/animator/materialAnimator.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +function MaterialAnimator() { + return ( + <> + ) +} + +export default MaterialAnimator \ No newline at end of file diff --git a/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx b/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx new file mode 100644 index 0000000..466e235 --- /dev/null +++ b/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +function MaterialInstance() { + return ( + <> + ) +} + +export default MaterialInstance \ No newline at end of file diff --git a/app/src/modules/simulation/materials/instances/materialInstances.tsx b/app/src/modules/simulation/materials/instances/materialInstances.tsx new file mode 100644 index 0000000..519cba9 --- /dev/null +++ b/app/src/modules/simulation/materials/instances/materialInstances.tsx @@ -0,0 +1,17 @@ +import React from 'react' +import MaterialInstance from './instance/materialInstance' +import MaterialAnimator from './animator/materialAnimator' + +function MaterialInstances() { + return ( + <> + + + + + + + ) +} + +export default MaterialInstances \ No newline at end of file diff --git a/app/src/modules/simulation/materials/materials.tsx b/app/src/modules/simulation/materials/materials.tsx new file mode 100644 index 0000000..432d815 --- /dev/null +++ b/app/src/modules/simulation/materials/materials.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import MaterialInstances from './instances/materialInstances' + +function Materials() { + return ( + <> + + + + + ) +} + +export default Materials \ No newline at end of file diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index 1be292e..b7bf36d 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -3,13 +3,15 @@ import { useEventsStore } from '../../store/simulation/useEventsStore'; import { useProductStore } from '../../store/simulation/useProductStore'; import Vehicles from './vehicle/vehicles'; import Points from './events/points/points'; +import Conveyor from './conveyor/conveyor'; +import RoboticArm from './roboticArm/roboticArm'; function Simulation() { const { events } = useEventsStore(); const { products } = useProductStore(); useEffect(() => { - console.log('events: ', events); + // console.log('events: ', events); }, [events]) useEffect(() => { @@ -23,6 +25,10 @@ function Simulation() { + + + + ) } From cbb773b6232c57db9af60c2408d0432f5b8ea529 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Wed, 23 Apr 2025 17:15:07 +0530 Subject: [PATCH 08/22] feat: Implement event properties management with action handling and UI components --- .../components/layout/sidebarLeft/Assets.tsx | 23 +- .../layout/sidebarRight/SideBarRight.tsx | 64 +++++- .../eventProperties/EventProperties.tsx | 208 ++++++++++++++++++ .../eventProperties/actions/DefaultAction.tsx | 7 + .../eventProperties/actions/DespawnAction.tsx | 22 ++ .../actions/PickAndPlaceAction.tsx | 9 + .../eventProperties/actions/ProcessAction.tsx | 24 ++ .../eventProperties/actions/SpawnAction.tsx | 35 +++ .../eventProperties/actions/StorageAction.tsx | 20 ++ .../eventProperties/actions/SwapAction.tsx | 12 + .../eventProperties/actions/TravelAction.tsx | 36 +++ .../functions/handleActionToggle.ts | 6 + .../functions/handleDeleteAction.ts | 6 + .../eventProperties/trigger/Trigger.tsx | 9 + .../ui/inputs/InputWithDropDown.tsx | 3 + .../ui/inputs/PreviewSelectionWithUpload.tsx | 49 +++++ .../builder/groups/floorItemsGroup.tsx | 4 +- app/src/styles/components/input.scss | 66 +++++- app/src/styles/layout/sidebar.scss | 75 +++++-- 19 files changed, 642 insertions(+), 36 deletions(-) create mode 100644 app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx create mode 100644 app/src/components/layout/sidebarRight/properties/eventProperties/actions/DefaultAction.tsx create mode 100644 app/src/components/layout/sidebarRight/properties/eventProperties/actions/DespawnAction.tsx create mode 100644 app/src/components/layout/sidebarRight/properties/eventProperties/actions/PickAndPlaceAction.tsx create mode 100644 app/src/components/layout/sidebarRight/properties/eventProperties/actions/ProcessAction.tsx create mode 100644 app/src/components/layout/sidebarRight/properties/eventProperties/actions/SpawnAction.tsx create mode 100644 app/src/components/layout/sidebarRight/properties/eventProperties/actions/StorageAction.tsx create mode 100644 app/src/components/layout/sidebarRight/properties/eventProperties/actions/SwapAction.tsx create mode 100644 app/src/components/layout/sidebarRight/properties/eventProperties/actions/TravelAction.tsx create mode 100644 app/src/components/layout/sidebarRight/properties/eventProperties/functions/handleActionToggle.ts create mode 100644 app/src/components/layout/sidebarRight/properties/eventProperties/functions/handleDeleteAction.ts create mode 100644 app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx create mode 100644 app/src/components/ui/inputs/PreviewSelectionWithUpload.tsx diff --git a/app/src/components/layout/sidebarLeft/Assets.tsx b/app/src/components/layout/sidebarLeft/Assets.tsx index 17a4df3..66e185a 100644 --- a/app/src/components/layout/sidebarLeft/Assets.tsx +++ b/app/src/components/layout/sidebarLeft/Assets.tsx @@ -73,7 +73,7 @@ const Assets: React.FC = () => { try { const filt = await fetchAssets(); setFiltereredAssets(filt); - } catch { } + } catch {} }; filteredAssets(); }, [categoryAssets]); @@ -135,7 +135,7 @@ const Assets: React.FC = () => { const res = await getCategoryAsset(asset); setCategoryAssets(res); setFiltereredAssets(res); - } catch (error) { } + } catch (error) {} } }; return ( @@ -151,7 +151,12 @@ const Assets: React.FC = () => {
{categoryAssets && categoryAssets?.map((asset: any, index: number) => ( -
+
{asset.filename} {
{categoryAssets && categoryAssets?.map((asset: any, index: number) => ( -
+
{asset.filename} { setSelectedItem({ name: asset.filename, id: asset.AssetID, - type: asset.type === "undefined" ? undefined : asset.type - }) + type: + asset.type === "undefined" ? undefined : asset.type, + }); }} /> diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx index 125cef9..d68333b 100644 --- a/app/src/components/layout/sidebarRight/SideBarRight.tsx +++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx @@ -13,24 +13,61 @@ import useToggleStore from "../../../store/useUIToggleStore"; import Visualization from "./visualization/Visualization"; import Analysis from "./analysis/Analysis"; import Simulations from "./simulation/Simulations"; -import { - useSelectedFloorItem, -} from "../../../store/store"; +import { useSelectedFloorItem } from "../../../store/store"; import GlobalProperties from "./properties/GlobalProperties"; import AsstePropertiies from "./properties/AssetProperties"; import ZoneProperties from "./properties/ZoneProperties"; +import EventProperties from "./properties/eventProperties/EventProperties"; const SideBarRight: React.FC = () => { const { activeModule } = useModuleStore(); const { toggleUI } = useToggleStore(); const { subModule, setSubModule } = useSubModuleStore(); const { selectedFloorItem } = useSelectedFloorItem(); + // Reset activeList whenever activeModule changes useEffect(() => { if (activeModule !== "simulation") setSubModule("properties"); if (activeModule === "simulation") setSubModule("mechanics"); }, [activeModule]); + // romove late + const dummyData = { + assetType: "machine", + selectedPoint: { + name: "Point A", + uuid: "123e4567-e89b-12d3-a456-426614174000", + actions: [ + { + uuid: "action-1", + name: "Action One", + isUsed: true, + }, + { + uuid: "action-2", + name: "Action Two", + isUsed: true, + }, + { + uuid: "action-3", + name: "Action Three", + isUsed: true, + }, + ], + }, + selectedItem: { + item: { + uuid: "item-1", + name: "Item One", + isUsed: false, + }, + }, + setSelectedPoint: (value: string) => { + console.log(`Selected point updated to: ${value}`); + }, + selectedActionSphere: "Sphere A", + }; + return (
@@ -38,8 +75,9 @@ const SideBarRight: React.FC = () => {
{/* {activeModule === "builder" && ( */}
setSubModule("properties")} > @@ -48,22 +86,25 @@ const SideBarRight: React.FC = () => { {activeModule === "simulation" && ( <>
setSubModule("mechanics")} >
setSubModule("simulations")} >
setSubModule("analysis")} > @@ -109,6 +150,7 @@ const SideBarRight: React.FC = () => { {subModule === "mechanics" && (
+
)} diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx new file mode 100644 index 0000000..7fa98f1 --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx @@ -0,0 +1,208 @@ +import React, { useRef, useState } from "react"; +import InputWithDropDown from "../../../../ui/inputs/InputWithDropDown"; +import LabledDropdown from "../../../../ui/inputs/LabledDropdown"; +import { + AddIcon, + RemoveIcon, + ResizeHeightIcon, +} from "../../../../icons/ExportCommonIcons"; +import RenameInput from "../../../../ui/inputs/RenameInput"; +import { handleResize } from "../../../../../functions/handleResizePannel"; +import { handleActionToggle } from "./functions/handleActionToggle"; +import { handleDeleteAction } from "./functions/handleDeleteAction"; +import DefaultAction from "./actions/DefaultAction"; +import SpawnAction from "./actions/SpawnAction"; +import SwapAction from "./actions/SwapAction"; +import DespawnAction from "./actions/DespawnAction"; +import TravelAction from "./actions/TravelAction"; +import PickAndPlaceAction from "./actions/PickAndPlaceAction"; +import ProcessAction from "./actions/ProcessAction"; +import StorageAction from "./actions/StorageAction"; + +interface EventPropertiesProps { + assetType: string; + selectedPoint: { + name: string; + uuid: string; + actions: { + uuid: string; + name: string; + isUsed: boolean; + }[]; + }; + selectedItem: { + item: { + uuid: string; + name: string; + isUsed: boolean; + } | null; + }; + setSelectedPoint: (value: string) => void; + selectedActionSphere: string; +} + +const EventProperties: React.FC = ({ + assetType, + selectedPoint, + selectedItem, + setSelectedPoint, + selectedActionSphere, +}) => { + const actionsContainerRef = useRef(null); + + const [activeOption, setActiveOption] = useState("default"); + const [dummyactiveOption, setTypeOption] = useState("default"); + + const getAvailableActions = () => { + if (assetType === "conveyor") { + return { + defaultOption: "default", + options: ["default", "spawn", "swap", "despawn"], + }; + } + if (assetType === "vehicle") { + return { + defaultOption: "travel", + options: ["travel"], + }; + } + if (assetType === "roboticArm") { + return { + defaultOption: "pickAndPlace", + options: ["pickAndPlace"], + }; + } + if (assetType === "machine") { + return { + defaultOption: "process", + options: ["process"], + }; + } + if (assetType === "store") { + return { + defaultOption: "store", + options: ["store", "spawn"], + }; + } else { + return { + defaultOption: "default", + options: ["default"], + }; + } + }; + + return ( +
+
+
{selectedPoint.name}
+
+
+
+
+ setTypeOption(option)} + /> +
+
+ {}} + onChange={(value) => console.log(value)} + /> +
+
+ {}} + onChange={(value) => console.log(value)} + /> +
+
+
+
+
+
+
Actions
+
{}}> + Add +
+
+
+
+ {selectedPoint?.actions.map((action) => ( +
+
handleActionToggle(action.uuid)} + > + +
+ {selectedPoint?.actions.length > 1 && ( +
handleDeleteAction(action.uuid)} + > + +
+ )} +
+ ))} +
+
handleResize(e, actionsContainerRef)} + > + +
+
+
+
+
+
+ +
+
+ setActiveOption(option)} + /> + {activeOption === "default" && } {/* done */} + {activeOption === "spawn" && } {/* done */} + {activeOption === "swap" && } {/* done */} + {activeOption === "despawn" && } {/* done */} + {activeOption === "travel" && } {/* done */} + {activeOption === "pickAndPlace" && } + {activeOption === "process" && } {/* done */} + {activeOption === "store" && } {/* done */} +
+
+
+ ); +}; + +export default EventProperties; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DefaultAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DefaultAction.tsx new file mode 100644 index 0000000..88f515e --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DefaultAction.tsx @@ -0,0 +1,7 @@ +import React from "react"; + +const DefaultAction:React.FC = () => { + return <>; +}; + +export default DefaultAction; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DespawnAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DespawnAction.tsx new file mode 100644 index 0000000..a0f081f --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DespawnAction.tsx @@ -0,0 +1,22 @@ +import React from "react"; +import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; + +const DespawnAction: React.FC = () => { + return ( + <> + {}} + onChange={(value) => console.log(value)} + /> + + ); +}; + +export default DespawnAction; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/PickAndPlaceAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/PickAndPlaceAction.tsx new file mode 100644 index 0000000..0c3228f --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/PickAndPlaceAction.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +const PickAndPlaceAction:React.FC = () => { + return ( +
PickAndPlaceAction
+ ) +} + +export default PickAndPlaceAction \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/ProcessAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/ProcessAction.tsx new file mode 100644 index 0000000..a27894e --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/ProcessAction.tsx @@ -0,0 +1,24 @@ +import React from "react"; +import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; +import SwapAction from "./SwapAction"; + +const ProcessAction: React.FC = () => { + return ( + <> + {}} + onChange={(value) => console.log(value)} + /> + + + ); +}; + +export default ProcessAction; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SpawnAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SpawnAction.tsx new file mode 100644 index 0000000..23c0de1 --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SpawnAction.tsx @@ -0,0 +1,35 @@ +import React from "react"; +import PreviewSelectionWithUpload from "../../../../../ui/inputs/PreviewSelectionWithUpload"; +import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; + +const SpawnAction: React.FC = () => { + return ( + <> + {}} + onChange={(value) => console.log(value)} + /> + {}} + onChange={(value) => console.log(value)} + /> + + + ); +}; + +export default SpawnAction; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/StorageAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/StorageAction.tsx new file mode 100644 index 0000000..ab2109b --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/StorageAction.tsx @@ -0,0 +1,20 @@ +import React from "react"; +import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; + +const StorageAction: React.FC = () => { + return ( + {}} + onChange={(value) => console.log(value)} + /> + ); +}; + +export default StorageAction; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SwapAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SwapAction.tsx new file mode 100644 index 0000000..2e18d80 --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SwapAction.tsx @@ -0,0 +1,12 @@ +import React from "react"; +import PreviewSelectionWithUpload from "../../../../../ui/inputs/PreviewSelectionWithUpload"; + +const SwapAction: React.FC = () => { + return ( + <> + + + ); +}; + +export default SwapAction; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/TravelAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/TravelAction.tsx new file mode 100644 index 0000000..ee4bda0 --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/TravelAction.tsx @@ -0,0 +1,36 @@ +import React from "react"; +import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; +import EyeDropInput from "../../../../../ui/inputs/EyeDropInput"; + +const TravelAction: React.FC = () => { + return ( + <> + {}} + onChange={(value) => console.log(value)} + /> + {}} + onChange={(value) => console.log(value)} + /> + {}} /> + {}} /> + + ); +}; + +export default TravelAction; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/functions/handleActionToggle.ts b/app/src/components/layout/sidebarRight/properties/eventProperties/functions/handleActionToggle.ts new file mode 100644 index 0000000..96e986a --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/functions/handleActionToggle.ts @@ -0,0 +1,6 @@ +export function handleActionToggle(uuid: string) { + // This function handles the action toggle for the event properties. + // It updates the selected action and its properties based on the provided UUID. + // The function is currently empty and needs to be implemented. + // You can add your logic here to handle the action toggle. +} \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/functions/handleDeleteAction.ts b/app/src/components/layout/sidebarRight/properties/eventProperties/functions/handleDeleteAction.ts new file mode 100644 index 0000000..6a367d5 --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/functions/handleDeleteAction.ts @@ -0,0 +1,6 @@ +export function handleDeleteAction(uuid: string) { + // This function handles the action toggle for the event properties. + // It updates the selected action and its properties based on the provided UUID. + // The function is currently empty and needs to be implemented. + // You can add your logic here to handle the action toggle. +} \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx new file mode 100644 index 0000000..6812257 --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +const Trigger = () => { + return ( +
Trigger
+ ) +} + +export default Trigger \ No newline at end of file diff --git a/app/src/components/ui/inputs/InputWithDropDown.tsx b/app/src/components/ui/inputs/InputWithDropDown.tsx index b672313..3d42917 100644 --- a/app/src/components/ui/inputs/InputWithDropDown.tsx +++ b/app/src/components/ui/inputs/InputWithDropDown.tsx @@ -5,6 +5,7 @@ type InputWithDropDownProps = { label: string; value: string; min?: number; + max?: number; step?: number; defaultValue?: string; options?: string[]; // Array of dropdown options @@ -19,6 +20,7 @@ const InputWithDropDown: React.FC = ({ label, value, min, + max, step, defaultValue, options, @@ -47,6 +49,7 @@ const InputWithDropDown: React.FC = ({
{ + const [showPreview, setSetshowPreview] = useState(false); + return ( +
+
setSetshowPreview(!showPreview)} + > +
Preview
+
+ +
+
+ {showPreview && ( +
+
+
+ )} +
+
+
Upload Product
+ + +
+ console.log(option)} + /> +
+
+ ); +}; + +export default PreviewSelectionWithUpload; diff --git a/app/src/modules/builder/groups/floorItemsGroup.tsx b/app/src/modules/builder/groups/floorItemsGroup.tsx index 23fa80d..5ec3636 100644 --- a/app/src/modules/builder/groups/floorItemsGroup.tsx +++ b/app/src/modules/builder/groups/floorItemsGroup.tsx @@ -16,10 +16,12 @@ import addAssetModel from "../geomentries/assets/addAssetModel"; import { getFloorAssets } from "../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi"; import useModuleStore from "../../../store/useModuleStore"; // import { retrieveGLTF } from "../../../utils/indexDB/idbUtils"; +import { useEventsStore } from "../../../store/simulation/useEventsStore"; + + const assetManagerWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/assetManagerWorker.js", import.meta.url)); const gltfLoaderWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js", import.meta.url)); -import { useEventsStore } from "../../../store/simulation/useEventsStore"; const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject, floorGroup, tempLoader, isTempLoader, plane, }: any) => { const state: Types.ThreeState = useThree(); diff --git a/app/src/styles/components/input.scss b/app/src/styles/components/input.scss index 883f6c2..21554e8 100644 --- a/app/src/styles/components/input.scss +++ b/app/src/styles/components/input.scss @@ -7,8 +7,8 @@ input { width: 100%; padding: 2px 4px; border-radius: #{$border-radius-small}; - outline: 2px solid var(--border-color); - outline-offset: -2px; + outline: 1px solid var(--border-color); + outline-offset: -1px; border: none; background: transparent; color: var(--input-text-color); @@ -30,6 +30,24 @@ input { background-color: var(--background-color) !important; -webkit-box-shadow: 0 0 0px 1000px var(--background-color) inset !important; } + + // File input specific style adjustments + &::file-selector-button { + font-size: 14px; + color: var(--accent-color); + background-color: var(--background-color-secondary); + border: none; + outline: none; + border-radius: #{$border-radius-small}; + padding: 2px; + cursor: pointer; + + // Hover effect for the file button + &:hover { + color: var(--primary-color); + background-color: var(--accent-color); + } + } } .input-value { @@ -712,3 +730,47 @@ input { border: 1px solid var(--accent-color); } } + +.preview-selection-with-upload-wrapper { + .input-header-container { + padding: 6px 12px; + @include flex-space-between; + .arrow-container { + transition: all 0.2s; + @include flex-center; + } + } + .upload-custom-asset-button{ + padding: 6px 12px; + @include flex-space-between; + .title{ + white-space: nowrap; + width: 40%; + } + input{ + display: none; + } + .upload-button{ + width: 60%; + background: var(--highlight-accent-color); + color: var(--accent-color); + padding: 3px 6px; + border-radius: #{$border-radius-small}; + text-align: center; + } + } + .canvas-wrapper { + height: 150px; + width: 100%; + padding: 8px; + padding-right: 4px; + overflow: hidden; + position: relative; + .canvas-container { + width: 100%; + height: 100%; + border-radius: #{$border-radius-small}; + background-color: var(--background-color-gray); + } + } +} diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss index 305206a..cab078e 100644 --- a/app/src/styles/layout/sidebar.scss +++ b/app/src/styles/layout/sidebar.scss @@ -7,6 +7,7 @@ top: 32px; left: 8px; background-color: var(--background-color); + backdrop-filter: blur(150px); border-radius: #{$border-radius-extra-large}; box-shadow: #{$box-shadow-medium}; z-index: #{$z-index-tools}; @@ -131,15 +132,12 @@ } .widgets-wrapper { - min-height: 50vh; max-height: 60vh; overflow: auto; } .widget-left-sideBar { - - .widget2D { overflow: auto; @@ -246,6 +244,7 @@ top: 32px; right: 8px; background-color: var(--background-color); + backdrop-filter: blur(150px); border-radius: #{$border-radius-extra-large}; box-shadow: #{$box-shadow-medium}; z-index: #{$z-index-tools}; @@ -643,7 +642,7 @@ path { stroke: var(--accent-color); - strokewidth: 1.5px; + stroke-width: 1.5px; } &:hover { @@ -658,7 +657,8 @@ } .machine-mechanics-content-container, - .simulations-container { + .simulations-container, + .event-proprties-wrapper { max-height: calc(60vh - (47px - 35px)); overflow: auto; overflow-y: scroll; @@ -682,6 +682,52 @@ } } + .global-props { + .property-list-container { + .property-item { + .value-field-container { + margin: 0; + input { + padding: 5px 4px; + } + .dropdown { + top: 4px; + right: 4px; + } + } + } + } + } + + .selected-actions-details { + .selected-actions-header .input-value { + padding: 8px 12px; + color: var(--accent-color); + } + .selected-actions-list { + margin-bottom: 8px; + .eye-dropper-input-container{ + padding: 6px 12px; + .regularDropdown-container { + padding: 5px 8px; + outline: 2px solid var(--border-color); + outline-offset: -2px; + border: none; + } + } + .value-field-container { + margin: 0; + input { + padding: 5px 4px; + } + .dropdown { + top: 4px; + right: 4px; + } + } + } + } + .lists-main-container { margin: 2px 8px; width: calc(100% - 12px); @@ -712,6 +758,7 @@ input { width: fit-content; + outline: none; accent-color: var(--accent-color); } } @@ -1183,25 +1230,21 @@ z-index: 3; padding: 8px; width: 100%; + max-height: 38px; font-size: var(--font-size-regular); - background: color-mix(in srgb, - var(--background-color) 40%, - transparent); + background: color-mix( + in srgb, + var(--background-color) 40%, + transparent + ); backdrop-filter: blur(5px); opacity: 0; transition: opacity 0.3s ease; - - /* Added properties for ellipsis */ display: -webkit-box; - /* Necessary for multiline truncation */ -webkit-line-clamp: 2; - /* Number of lines to show */ -webkit-box-orient: vertical; - /* Box orientation for the ellipsis */ overflow: hidden; - /* Hide overflowing content */ text-overflow: ellipsis; - /* Add ellipsis for truncated content */ } .asset-image { @@ -1271,4 +1314,4 @@ .assets-wrapper { margin: 0; } -} \ No newline at end of file +} From 2f2ea93afe3ecaadf26c92ef8e8a56d32b60a86c Mon Sep 17 00:00:00 2001 From: Vishnu Date: Wed, 23 Apr 2025 17:55:35 +0530 Subject: [PATCH 09/22] feat: Update asset types and labels in event properties and spawn action components --- app/src/components/layout/sidebarRight/SideBarRight.tsx | 5 +---- .../properties/eventProperties/EventProperties.tsx | 8 +++----- .../properties/eventProperties/actions/SpawnAction.tsx | 4 ++-- app/src/types/simulationTypes.d.ts | 4 ++-- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx index d68333b..277637a 100644 --- a/app/src/components/layout/sidebarRight/SideBarRight.tsx +++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx @@ -33,7 +33,7 @@ const SideBarRight: React.FC = () => { // romove late const dummyData = { - assetType: "machine", + assetType: "store", selectedPoint: { name: "Point A", uuid: "123e4567-e89b-12d3-a456-426614174000", @@ -41,17 +41,14 @@ const SideBarRight: React.FC = () => { { uuid: "action-1", name: "Action One", - isUsed: true, }, { uuid: "action-2", name: "Action Two", - isUsed: true, }, { uuid: "action-3", name: "Action Three", - isUsed: true, }, ], }, diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx index 7fa98f1..e7444a0 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx @@ -27,14 +27,12 @@ interface EventPropertiesProps { actions: { uuid: string; name: string; - isUsed: boolean; }[]; }; selectedItem: { item: { uuid: string; name: string; - isUsed: boolean; } | null; }; setSelectedPoint: (value: string) => void; @@ -98,13 +96,13 @@ const EventProperties: React.FC = ({
-
+ {/*
setTypeOption(option)} /> -
+
*/}
{ return ( <> { onChange={(value) => console.log(value)} /> Date: Wed, 23 Apr 2025 18:13:32 +0530 Subject: [PATCH 10/22] feat: Enhance simulation event handling and material management with new components and state management --- .../IntialLoad/loadInitialFloorItems.ts | 183 +++++++++++++++++- .../geomentries/assets/addAssetModel.ts | 4 +- .../builder/groups/floorItemsGroup.tsx | 4 +- .../scene/postProcessing/postProcessing.tsx | 173 +++++++++-------- .../events/points/creator/pointsCreator.tsx | 40 ++-- .../{ => functions}/pointsCalculator.ts | 2 +- .../machineInstance/machineInstance.tsx | 10 + .../machine/instances/machineInstances.tsx | 14 ++ .../modules/simulation/machine/machine.tsx | 14 ++ app/src/modules/simulation/simulation.tsx | 11 +- .../storageUnitInstance.tsx | 10 + .../instances/storageUnitInstances.tsx | 14 ++ .../simulation/storageUnit/storageUnit.tsx | 14 ++ app/src/store/simulation/useMaterialStore.ts | 76 ++++++++ .../store/simulation/useSimulationStore.ts | 25 +++ app/src/types/simulationTypes.d.ts | 17 +- 16 files changed, 503 insertions(+), 108 deletions(-) rename app/src/modules/simulation/events/points/{ => functions}/pointsCalculator.ts (96%) create mode 100644 app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx create mode 100644 app/src/modules/simulation/machine/instances/machineInstances.tsx create mode 100644 app/src/modules/simulation/machine/machine.tsx create mode 100644 app/src/modules/simulation/storageUnit/instances/storageUnitInstance/storageUnitInstance.tsx create mode 100644 app/src/modules/simulation/storageUnit/instances/storageUnitInstances.tsx create mode 100644 app/src/modules/simulation/storageUnit/storageUnit.tsx create mode 100644 app/src/store/simulation/useMaterialStore.ts create mode 100644 app/src/store/simulation/useSimulationStore.ts diff --git a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts index e88dc3c..f5ee7d2 100644 --- a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts +++ b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts @@ -8,10 +8,12 @@ import * as Types from "../../../types/world/worldTypes"; import { initializeDB, retrieveGLTF, storeGLTF } from '../../../utils/indexDB/idbUtils'; import { getCamera } from '../../../services/factoryBuilder/camera/getCameraApi'; import { getFloorAssets } from '../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi'; +import PointsCalculator from '../../simulation/events/points/functions/pointsCalculator'; async function loadInitialFloorItems( itemsGroup: Types.RefGroup, setFloorItems: Types.setFloorItemSetState, + addEvent: (event: EventsSchema) => void, ): Promise { if (!itemsGroup.current) return; let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; @@ -70,7 +72,7 @@ async function loadInitialFloorItems( const cachedModel = THREE.Cache.get(item.modelfileID!); if (cachedModel) { // console.log(`[Cache] Fetching ${item.modelname}`); - processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems); + processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems, addEvent); modelsLoaded++; checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); return; @@ -85,7 +87,7 @@ async function loadInitialFloorItems( URL.revokeObjectURL(blobUrl); THREE.Cache.remove(blobUrl); THREE.Cache.add(item.modelfileID!, gltf); - processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems); + processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, addEvent); modelsLoaded++; checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); }, @@ -106,7 +108,7 @@ async function loadInitialFloorItems( const modelBlob = await fetch(modelUrl).then((res) => res.blob()); await storeGLTF(item.modelfileID!, modelBlob); THREE.Cache.add(item.modelfileID!, gltf); - processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems); + processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, addEvent); modelsLoaded++; checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); }, @@ -148,8 +150,9 @@ function processLoadedModel( item: Types.FloorItemType, itemsGroup: Types.RefGroup, setFloorItems: Types.setFloorItemSetState, + addEvent: (event: EventsSchema) => void, ) { - const model = gltf; + const model = gltf.clone(); model.uuid = item.modeluuid; model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); model.userData = { name: item.modelname, modelId: item.modelfileID, modeluuid: item.modeluuid }; @@ -182,6 +185,178 @@ function processLoadedModel( }, ]); + if (item.modelfileID === "a1ee92554935007b10b3eb05") { + const data = PointsCalculator( + 'Vehicle', + gltf.clone(), + new THREE.Vector3(...model.rotation) + ); + + if (!data || !data.points) return; + + const vehicleEvent: VehicleEventSchema = { + modelUuid: item.modeluuid, + modelName: item.modelname, + position: item.position, + rotation: [item.rotation.x, item.rotation.y, item.rotation.z], + state: "idle", + type: "vehicle", + speed: 1, + point: { + uuid: THREE.MathUtils.generateUUID(), + position: [data.points[0].x, data.points[0].y, data.points[0].z], + rotation: [0, 0, 0], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Vehicle Action", + actionType: "travel", + material: null, + unLoadDuration: 5, + loadCapacity: 10, + pickUpPoint: null, + unLoadPoint: null, + triggers: [] + } + } + }; + addEvent(vehicleEvent); + } else if (item.modelfileID === "7dc04e36882e4debbc1a8e3d") { + const data = PointsCalculator( + 'Conveyor', + gltf.clone(), + new THREE.Vector3(...model.rotation) + ); + + if (!data || !data.points) return; + + const ConveyorEvent: ConveyorEventSchema = { + modelUuid: item.modeluuid, + modelName: item.modelname, + position: item.position, + rotation: [item.rotation.x, item.rotation.y, item.rotation.z], + state: "idle", + type: "transfer", + speed: 1, + points: data.points.map((point: THREE.Vector3, index: number) => ({ + uuid: THREE.MathUtils.generateUUID(), + position: [point.x, point.y, point.z], + rotation: [0, 0, 0], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: `Action ${index}`, + actionType: 'default', + material: 'inherit', + delay: 0, + spawnInterval: 5, + spawnCount: 1, + triggers: [] + } + })) + }; + addEvent(ConveyorEvent); + } else if (item.modelfileID === "7dc04e36882e4debbc1a8e3d") { + const data = PointsCalculator( + 'Conveyor', + gltf.clone(), + new THREE.Vector3(...model.rotation) + ); + + if (!data || !data.points) return; + + const ConveyorEvent: ConveyorEventSchema = { + modelUuid: item.modeluuid, + modelName: item.modelname, + position: item.position, + rotation: [item.rotation.x, item.rotation.y, item.rotation.z], + state: "idle", + type: "transfer", + speed: 1, + points: data.points.map((point: THREE.Vector3, index: number) => ({ + uuid: THREE.MathUtils.generateUUID(), + position: [point.x, point.y, point.z], + rotation: [0, 0, 0], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: `Action ${index}`, + actionType: 'default', + material: 'inherit', + delay: 0, + spawnInterval: 5, + spawnCount: 1, + triggers: [] + } + })) + }; + addEvent(ConveyorEvent); + } else if (item.modelfileID === "29dee78715ad5b853f5c346d") { + const data = PointsCalculator( + 'StaticMachine', + gltf.clone(), + new THREE.Vector3(...model.rotation) + ); + + if (!data || !data.points) return; + + const machineEvent: MachineEventSchema = { + modelUuid: item.modeluuid, + modelName: item.modelname, + position: item.position, + rotation: [item.rotation.x, item.rotation.y, item.rotation.z], + state: "idle", + type: "machine", + point: { + uuid: THREE.MathUtils.generateUUID(), + position: [data.points[0].x, data.points[0].y, data.points[0].z], + rotation: [0, 0, 0], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Process Action", + actionType: "process", + processTime: 10, + swapMaterial: "material-id", + triggers: [] + } + } + }; + addEvent(machineEvent); + } else if (item.modelfileID === "52e6681fbb743a890d96c914") { + const data = PointsCalculator( + 'ArmBot', + gltf.clone(), + new THREE.Vector3(...model.rotation) + ); + + if (!data || !data.points) return; + + const roboticArmEvent: RoboticArmEventSchema = { + modelUuid: item.modeluuid, + modelName: item.modelname, + position: item.position, + rotation: [item.rotation.x, item.rotation.y, item.rotation.z], + state: "idle", + type: "roboticArm", + speed: 1, + point: { + uuid: THREE.MathUtils.generateUUID(), + position: [data.points[0].x, data.points[0].y, data.points[0].z], + rotation: [0, 0, 0], + actions: [ + { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Pick and Place", + actionType: "pickAndPlace", + process: { + startPoint: [0, 0, 0], + endPoint: [0, 0, 0] + }, + triggers: [] + } + ] + } + }; + addEvent(roboticArmEvent); + } + gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: 'power2.out' }); gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out' }); } diff --git a/app/src/modules/builder/geomentries/assets/addAssetModel.ts b/app/src/modules/builder/geomentries/assets/addAssetModel.ts index 193dd41..670c7b5 100644 --- a/app/src/modules/builder/geomentries/assets/addAssetModel.ts +++ b/app/src/modules/builder/geomentries/assets/addAssetModel.ts @@ -10,7 +10,7 @@ import { retrieveGLTF, storeGLTF } from '../../../../utils/indexDB/idbUtils'; import { Socket } from 'socket.io-client'; import * as CONSTANTS from '../../../../types/world/worldConstants'; import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; -import PointsCalculator from '../../../simulation/events/points/pointsCalculator'; +import PointsCalculator from '../../../simulation/events/points/functions/pointsCalculator'; async function addAssetModel( raycaster: THREE.Raycaster, @@ -266,7 +266,7 @@ async function handleModelLoad( } }; addEvent(roboticArmEvent); - } else if (selectedItem.type === "Machine") { + } else if (selectedItem.type === "StaticMachine") { const machineEvent: MachineEventSchema = { modelUuid: newFloorItem.modeluuid, modelName: newFloorItem.modelname, diff --git a/app/src/modules/builder/groups/floorItemsGroup.tsx b/app/src/modules/builder/groups/floorItemsGroup.tsx index 2a3c2cc..241f628 100644 --- a/app/src/modules/builder/groups/floorItemsGroup.tsx +++ b/app/src/modules/builder/groups/floorItemsGroup.tsx @@ -75,7 +75,7 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject gltfLoaderWorker.postMessage({ floorItems: data }); } else { gltfLoaderWorker.postMessage({ floorItems: [] }); - loadInitialFloorItems(itemsGroup, setFloorItems); + loadInitialFloorItems(itemsGroup, setFloorItems, addEvent); updateLoadingProgress(100); } }); @@ -94,7 +94,7 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject updateLoadingProgress(progress); if (loadedAssets === totalAssets) { - loadInitialFloorItems(itemsGroup, setFloorItems); + loadInitialFloorItems(itemsGroup, setFloorItems, addEvent); updateLoadingProgress(100); } }); diff --git a/app/src/modules/scene/postProcessing/postProcessing.tsx b/app/src/modules/scene/postProcessing/postProcessing.tsx index d3245fb..dd5607a 100644 --- a/app/src/modules/scene/postProcessing/postProcessing.tsx +++ b/app/src/modules/scene/postProcessing/postProcessing.tsx @@ -2,90 +2,107 @@ import * as THREE from "three"; import { EffectComposer, N8AO, Outline } from "@react-three/postprocessing"; import { BlendFunction } from "postprocessing"; import { - useDeletableFloorItem, - useSelectedWallItem, - useSelectedFloorItem, + useDeletableFloorItem, + useSelectedWallItem, + useSelectedFloorItem, } from "../../../store/store"; import * as Types from "../../../types/world/worldTypes"; import * as CONSTANTS from "../../../types/world/worldConstants"; import { useEffect } from "react"; +import { useSelectedEventSphere } from "../../../store/simulation/useSimulationStore"; export default function PostProcessing() { - const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem(); - const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem(); - const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem(); + const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem(); + const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem(); + const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem(); + const { selectedEventSphere } = useSelectedEventSphere(); - function flattenChildren(children: any[]) { - const allChildren: any[] = []; - children.forEach((child) => { - allChildren.push(child); - if (child.children && child.children.length > 0) { - allChildren.push(...flattenChildren(child.children)); - } - }); - return allChildren; - } + function flattenChildren(children: any[]) { + const allChildren: any[] = []; + children.forEach((child) => { + allChildren.push(child); + if (child.children && child.children.length > 0) { + allChildren.push(...flattenChildren(child.children)); + } + }); + return allChildren; + } - return ( - <> - - - {deletableFloorItem && ( - - )} - {selectedWallItem && ( - child.name !== "CSG_REF" - )} - selectionLayer={10} - width={3000} - blendFunction={BlendFunction.ALPHA} - edgeStrength={5} - resolutionScale={2} - pulseSpeed={0} - visibleEdgeColor={CONSTANTS.outlineConfig.assetSelectColor} - hiddenEdgeColor={CONSTANTS.outlineConfig.assetSelectColor} - blur={true} - xRay={true} - /> - )} - {selectedFloorItem && ( - - )} - - - ); + return ( + <> + + + {deletableFloorItem && ( + + )} + {selectedWallItem && ( + child.name !== "CSG_REF" + )} + selectionLayer={10} + width={3000} + blendFunction={BlendFunction.ALPHA} + edgeStrength={5} + resolutionScale={2} + pulseSpeed={0} + visibleEdgeColor={CONSTANTS.outlineConfig.assetSelectColor} + hiddenEdgeColor={CONSTANTS.outlineConfig.assetSelectColor} + blur={true} + xRay={true} + /> + )} + {selectedFloorItem && ( + + )} + {selectedEventSphere && ( + + )} + + + ); } diff --git a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx index 335f1f5..8baacd9 100644 --- a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx +++ b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx @@ -4,20 +4,20 @@ import { useEventsStore } from '../../../../../store/simulation/useEventsStore'; import useModuleStore from '../../../../../store/useModuleStore'; import { TransformControls } from '@react-three/drei'; import { detectModifierKeys } from '../../../../../utils/shortcutkeys/detectModifierKeys'; +import { useSelectedEventSphere } from '../../../../../store/simulation/useSimulationStore'; function PointsCreator() { const { events, updatePoint, getPointByUuid } = useEventsStore(); const { activeModule } = useModuleStore(); const transformRef = useRef(null); const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null); - const [selectedPoint, setSelectedPoint] = useState(null); const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({}); + const { selectedEventSphere, setSelectedEventSphere, clearSelectedEventSphere } = useSelectedEventSphere(); useEffect(() => { - setTransformMode(null); const handleKeyDown = (e: KeyboardEvent) => { const keyCombination = detectModifierKeys(e); - if (!selectedPoint) return; + if (!selectedEventSphere) return; if (keyCombination === "G") { setTransformMode((prev) => (prev === "translate" ? null : "translate")); } @@ -28,13 +28,13 @@ function PointsCreator() { window.addEventListener("keydown", handleKeyDown); return () => window.removeEventListener("keydown", handleKeyDown); - }, [selectedPoint]); + }, [selectedEventSphere]); - const updatePointToState = (selectedPoint: THREE.Mesh) => { - let point = JSON.parse(JSON.stringify(getPointByUuid(selectedPoint.userData.modelUuid, selectedPoint.userData.pointUuid))); + const updatePointToState = (selectedEventSphere: THREE.Mesh) => { + let point = JSON.parse(JSON.stringify(getPointByUuid(selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid))); if (point) { - point.position = [selectedPoint.position.x, selectedPoint.position.y, selectedPoint.position.z]; - updatePoint(selectedPoint.userData.modelUuid, selectedPoint.userData.pointUuid, point) + point.position = [selectedEventSphere.position.x, selectedEventSphere.position.y, selectedEventSphere.position.z]; + updatePoint(selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid, point) } } @@ -53,10 +53,11 @@ function PointsCreator() { ref={(el) => (sphereRefs.current[point.uuid] = el!)} onClick={(e) => { e.stopPropagation(); - setSelectedPoint(sphereRefs.current[point.uuid]); + setSelectedEventSphere(sphereRefs.current[point.uuid]); }} onPointerMissed={() => { - setSelectedPoint(null); + clearSelectedEventSphere(); + setTransformMode(null); }} key={`${i}-${j}`} position={new THREE.Vector3(...point.position)} @@ -76,10 +77,11 @@ function PointsCreator() { ref={(el) => (sphereRefs.current[event.point.uuid] = el!)} onClick={(e) => { e.stopPropagation(); - setSelectedPoint(sphereRefs.current[event.point.uuid]); + setSelectedEventSphere(sphereRefs.current[event.point.uuid]); }} onPointerMissed={() => { - setSelectedPoint(null); + clearSelectedEventSphere(); + setTransformMode(null); }} position={new THREE.Vector3(...event.point.position)} userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} @@ -97,10 +99,11 @@ function PointsCreator() { ref={(el) => (sphereRefs.current[event.point.uuid] = el!)} onClick={(e) => { e.stopPropagation(); - setSelectedPoint(sphereRefs.current[event.point.uuid]); + setSelectedEventSphere(sphereRefs.current[event.point.uuid]); }} onPointerMissed={() => { - setSelectedPoint(null); + clearSelectedEventSphere(); + setTransformMode(null); }} position={new THREE.Vector3(...event.point.position)} userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} @@ -118,10 +121,11 @@ function PointsCreator() { ref={(el) => (sphereRefs.current[event.point.uuid] = el!)} onClick={(e) => { e.stopPropagation(); - setSelectedPoint(sphereRefs.current[event.point.uuid]); + setSelectedEventSphere(sphereRefs.current[event.point.uuid]); }} onPointerMissed={() => { - setSelectedPoint(null); + clearSelectedEventSphere(); + setTransformMode(null); }} position={new THREE.Vector3(...event.point.position)} userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} @@ -136,8 +140,8 @@ function PointsCreator() { } })} - {(selectedPoint && transformMode) && - { updatePointToState(selectedPoint) }} /> + {(selectedEventSphere && transformMode) && + { updatePointToState(selectedEventSphere) }} /> } } diff --git a/app/src/modules/simulation/events/points/pointsCalculator.ts b/app/src/modules/simulation/events/points/functions/pointsCalculator.ts similarity index 96% rename from app/src/modules/simulation/events/points/pointsCalculator.ts rename to app/src/modules/simulation/events/points/functions/pointsCalculator.ts index 86d368e..ccc2dbb 100644 --- a/app/src/modules/simulation/events/points/pointsCalculator.ts +++ b/app/src/modules/simulation/events/points/functions/pointsCalculator.ts @@ -1,5 +1,5 @@ import * as THREE from 'three'; -import { Group } from '../../../../types/world/worldTypes'; +import { Group } from '../../../../../types/world/worldTypes'; function PointsCalculator( type: string, diff --git a/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx b/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx new file mode 100644 index 0000000..edb825f --- /dev/null +++ b/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx @@ -0,0 +1,10 @@ +import React from 'react' + +function MachineInstance() { + return ( + <> + + ) +} + +export default MachineInstance \ No newline at end of file diff --git a/app/src/modules/simulation/machine/instances/machineInstances.tsx b/app/src/modules/simulation/machine/instances/machineInstances.tsx new file mode 100644 index 0000000..b0c2c9f --- /dev/null +++ b/app/src/modules/simulation/machine/instances/machineInstances.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import MachineInstance from './machineInstance/machineInstance' + +function MachineInstances() { + return ( + <> + + + + + ) +} + +export default MachineInstances \ No newline at end of file diff --git a/app/src/modules/simulation/machine/machine.tsx b/app/src/modules/simulation/machine/machine.tsx new file mode 100644 index 0000000..32c3b8e --- /dev/null +++ b/app/src/modules/simulation/machine/machine.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import MachineInstances from './instances/machineInstances' + +function Machine() { + return ( + <> + + + + + ) +} + +export default Machine \ No newline at end of file diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index b7bf36d..71f9341 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -5,6 +5,9 @@ import Vehicles from './vehicle/vehicles'; import Points from './events/points/points'; import Conveyor from './conveyor/conveyor'; import RoboticArm from './roboticArm/roboticArm'; +import Materials from './materials/materials'; +import Machine from './machine/machine'; +import StorageUnit from './storageUnit/storageUnit'; function Simulation() { const { events } = useEventsStore(); @@ -23,11 +26,17 @@ function Simulation() { + + + + - + + + ) diff --git a/app/src/modules/simulation/storageUnit/instances/storageUnitInstance/storageUnitInstance.tsx b/app/src/modules/simulation/storageUnit/instances/storageUnitInstance/storageUnitInstance.tsx new file mode 100644 index 0000000..29d404e --- /dev/null +++ b/app/src/modules/simulation/storageUnit/instances/storageUnitInstance/storageUnitInstance.tsx @@ -0,0 +1,10 @@ +import React from 'react' + +function storageUnitInstance() { + return ( + <> + + ) +} + +export default storageUnitInstance \ No newline at end of file diff --git a/app/src/modules/simulation/storageUnit/instances/storageUnitInstances.tsx b/app/src/modules/simulation/storageUnit/instances/storageUnitInstances.tsx new file mode 100644 index 0000000..d79b5d8 --- /dev/null +++ b/app/src/modules/simulation/storageUnit/instances/storageUnitInstances.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import StorageUnitInstance from './storageUnitInstance/storageUnitInstance' + +function StorageUnitInstances() { + return ( + <> + + + + + ) +} + +export default StorageUnitInstances \ No newline at end of file diff --git a/app/src/modules/simulation/storageUnit/storageUnit.tsx b/app/src/modules/simulation/storageUnit/storageUnit.tsx new file mode 100644 index 0000000..eee0875 --- /dev/null +++ b/app/src/modules/simulation/storageUnit/storageUnit.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import StorageUnitInstances from './instances/storageUnitInstances' + +function StorageUnit() { + return ( + <> + + + + + ) +} + +export default StorageUnit \ No newline at end of file diff --git a/app/src/store/simulation/useMaterialStore.ts b/app/src/store/simulation/useMaterialStore.ts new file mode 100644 index 0000000..56a35a7 --- /dev/null +++ b/app/src/store/simulation/useMaterialStore.ts @@ -0,0 +1,76 @@ +import { create } from 'zustand'; +import { immer } from 'zustand/middleware/immer'; + +type MaterialsStore = { + materials: MaterialsSchema; + + addMaterial: (material: MaterialSchema) => void; + removeMaterial: (materialId: string) => void; + updateMaterial: (materialId: string, updates: Partial) => void; + + setStartTime: (materialId: string, startTime: string) => void; + setEndTime: (materialId: string, endTime: string) => void; + setCost: (materialId: string, cost: number) => void; + setWeight: (materialId: string, weight: number) => void; + + getMaterialById: (materialId: string) => MaterialSchema | undefined; +}; + +export const useMaterialStore = create()( + immer((set, get) => ({ + materials: [], + + addMaterial: (material) => { + set((state) => { + state.materials.push(material); + }); + }, + + removeMaterial: (materialId) => { + set((state) => { + state.materials = state.materials.filter(m => m.materialId !== materialId); + }); + }, + + updateMaterial: (materialId, updates) => { + set((state) => { + const material = state.materials.find(m => m.materialId === materialId); + if (material) { + Object.assign(material, updates); + } + }); + }, + + setStartTime: (materialId, startTime) => { + set((state) => { + const material = state.materials.find(m => m.materialId === materialId); + if (material) material.startTime = startTime; + }); + }, + + setEndTime: (materialId, endTime) => { + set((state) => { + const material = state.materials.find(m => m.materialId === materialId); + if (material) material.endTime = endTime; + }); + }, + + setCost: (materialId, cost) => { + set((state) => { + const material = state.materials.find(m => m.materialId === materialId); + if (material) material.cost = cost; + }); + }, + + setWeight: (materialId, weight) => { + set((state) => { + const material = state.materials.find(m => m.materialId === materialId); + if (material) material.weight = weight; + }); + }, + + getMaterialById: (materialId) => { + return get().materials.find(m => m.materialId === materialId); + }, + })) +); diff --git a/app/src/store/simulation/useSimulationStore.ts b/app/src/store/simulation/useSimulationStore.ts new file mode 100644 index 0000000..2d63802 --- /dev/null +++ b/app/src/store/simulation/useSimulationStore.ts @@ -0,0 +1,25 @@ +import { create } from 'zustand'; +import { immer } from 'zustand/middleware/immer'; +import * as THREE from 'three'; + +interface SelectedEventSphereState { + selectedEventSphere: THREE.Mesh | null; + setSelectedEventSphere: (mesh: THREE.Mesh | null) => void; + clearSelectedEventSphere: () => void; +} + +export const useSelectedEventSphere = create()( + immer((set) => ({ + selectedEventSphere: null, + setSelectedEventSphere: (mesh) => { + set((state) => { + state.selectedEventSphere = mesh; + }); + }, + clearSelectedEventSphere: () => { + set((state) => { + state.selectedEventSphere = null; + }); + }, + })) +); \ No newline at end of file diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index 7c2bd2c..fe24cda 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -59,7 +59,7 @@ interface RoboticArmPointSchema { actionUuid: string; actionName: string; actionType: "pickAndPlace"; - process: { startPoint: [number, number, number]; endPoint: [number, number, number] }; + process: { startPoint: [number, number, number] | null; endPoint: [number, number, number] | null }; triggers: TriggerSchema[]; }[]; } @@ -168,4 +168,17 @@ interface StorageUnitStatus extends StorageEventSchema { idleTime: number; activeTime: number; currentLoad: number; -} \ No newline at end of file +} + +interface MaterialSchema { + materialId: string; + materialName: string; + materialType: string; + isActive: boolean; + startTime?: string; + endTime?: string; + cost?: number; + weight?: number; +} + +type MaterialsSchema = MaterialSchema[]; \ No newline at end of file From 0f716d64a680cc5d4e9629fecbf4d1e2630e6c4b Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 23 Apr 2025 18:25:49 +0530 Subject: [PATCH 11/22] feat: Add Simulator component to simulation and enable event logging --- .../IntialLoad/loadInitialFloorItems.ts | 65 +++++++++++++++++++ app/src/modules/simulation/simulation.tsx | 5 +- .../simulation/simulator/simulator.tsx | 11 ++++ 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 app/src/modules/simulation/simulator/simulator.tsx diff --git a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts index f5ee7d2..2378bf3 100644 --- a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts +++ b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts @@ -254,6 +254,71 @@ function processLoadedModel( })) }; addEvent(ConveyorEvent); + } else if (item.modelfileID === "7dc04e36882e4debbc1a8e3d") { + // const data = PointsCalculator( + // 'Conveyor', + // gltf.clone(), + // new THREE.Vector3(...model.rotation) + // ); + + // if (!data || !data.points) return; + + // const points: ConveyorPointSchema[] = data.points.map((point: THREE.Vector3, index: number) => { + // const actionUuid = THREE.MathUtils.generateUUID(); + // return { + // uuid: THREE.MathUtils.generateUUID(), + // position: [point.x, point.y, point.z], + // rotation: [0, 0, 0], + // action: { + // actionUuid, + // actionName: `Action ${index}`, + // actionType: 'default', + // material: 'inherit', + // delay: 0, + // spawnInterval: 5, + // spawnCount: 1, + // triggers: [] + // } + // }; + // }); + + // points.forEach((point, index) => { + // if (index < points.length - 1) { + // const nextPoint = points[index + 1]; + // point.action.triggers.push({ + // triggerUuid: THREE.MathUtils.generateUUID(), + // triggerName: `Trigger 1`, + // triggerType: "onComplete", + // delay: 0, + // triggeredAsset: { + // triggeredModel: { + // modelName: item.modelname, + // modelUuid: item.modeluuid + // }, + // triggeredPoint: { + // pointName: `Point ${index + 1}`, + // pointUuid: nextPoint.uuid + // }, + // triggeredAction: { + // actionName: nextPoint.action.actionName, + // actionUuid: nextPoint.action.actionUuid + // } + // } + // }); + // } + // }); + + // const ConveyorEvent: ConveyorEventSchema = { + // modelUuid: item.modeluuid, + // modelName: item.modelname, + // position: item.position, + // rotation: [item.rotation.x, item.rotation.y, item.rotation.z], + // state: "idle", + // type: "transfer", + // speed: 1, + // points + // }; + // addEvent(ConveyorEvent); } else if (item.modelfileID === "7dc04e36882e4debbc1a8e3d") { const data = PointsCalculator( 'Conveyor', diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index 71f9341..572fc70 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -8,13 +8,14 @@ import RoboticArm from './roboticArm/roboticArm'; import Materials from './materials/materials'; import Machine from './machine/machine'; import StorageUnit from './storageUnit/storageUnit'; +import Simulator from './simulator/simulator'; function Simulation() { const { events } = useEventsStore(); const { products } = useProductStore(); useEffect(() => { - // console.log('events: ', events); + console.log('events: ', events); }, [events]) useEffect(() => { @@ -38,6 +39,8 @@ function Simulation() { + + ) } diff --git a/app/src/modules/simulation/simulator/simulator.tsx b/app/src/modules/simulation/simulator/simulator.tsx new file mode 100644 index 0000000..8cc22d6 --- /dev/null +++ b/app/src/modules/simulation/simulator/simulator.tsx @@ -0,0 +1,11 @@ +import React from 'react' + +function Simulator() { + return ( + <> + + + ) +} + +export default Simulator \ No newline at end of file From e43bfb6e982fc31d3c8c0465b490e7dfa45cfcd8 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Wed, 23 Apr 2025 18:25:55 +0530 Subject: [PATCH 12/22] feat: Add Trigger component and integrate it into EventProperties; refactor PickAndPlaceAction for improved structure --- .../eventProperties/EventProperties.tsx | 6 +- .../actions/PickAndPlaceAction.tsx | 16 ++- .../eventProperties/trigger/Trigger.tsx | 110 +++++++++++++++++- 3 files changed, 119 insertions(+), 13 deletions(-) diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx index e7444a0..c3ec6e7 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx @@ -18,6 +18,7 @@ import TravelAction from "./actions/TravelAction"; import PickAndPlaceAction from "./actions/PickAndPlaceAction"; import ProcessAction from "./actions/ProcessAction"; import StorageAction from "./actions/StorageAction"; +import Trigger from "./trigger/Trigger"; interface EventPropertiesProps { assetType: string; @@ -194,11 +195,14 @@ const EventProperties: React.FC = ({ {activeOption === "swap" && } {/* done */} {activeOption === "despawn" && } {/* done */} {activeOption === "travel" && } {/* done */} - {activeOption === "pickAndPlace" && } + {activeOption === "pickAndPlace" && } {/* done */} {activeOption === "process" && } {/* done */} {activeOption === "store" && } {/* done */}
+
+ +
); }; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/PickAndPlaceAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/PickAndPlaceAction.tsx index 0c3228f..9574669 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/PickAndPlaceAction.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/PickAndPlaceAction.tsx @@ -1,9 +1,13 @@ -import React from 'react' +import React from "react"; +import EyeDropInput from "../../../../../ui/inputs/EyeDropInput"; -const PickAndPlaceAction:React.FC = () => { +const PickAndPlaceAction: React.FC = () => { return ( -
PickAndPlaceAction
- ) -} + <> + {}} /> + {}} /> + + ); +}; -export default PickAndPlaceAction \ No newline at end of file +export default PickAndPlaceAction; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx index 6812257..f287b63 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx @@ -1,9 +1,107 @@ -import React from 'react' +import React, { useState } from "react"; +import { AddIcon, RemoveIcon } from "../../../../../icons/ExportCommonIcons"; +import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; + +const Trigger: React.FC = () => { + // State to hold the list of triggers + const [triggers, setTriggers] = useState([]); + const [activeOption, setActiveOption] = useState("onComplete"); + + // States for dropdowns + const [triggeredModel, setTriggeredModel] = useState([]); + const [triggeredPoint, setTriggeredPoint] = useState([]); + const [triggeredAction, setTriggeredAction] = useState([]); + + // 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 Trigger = () => { return ( -
Trigger
- ) -} +
+
+
Trigger
+
+ Add +
+
+
+ {/* Map over triggers and render them */} + {triggers.map((trigger, index) => ( +
+
+ {trigger} +
removeTrigger(index)} + style={{ cursor: "pointer" }} + > + +
+
+ setActiveOption(option)} + /> +
+
+ { + const newModel = [...triggeredModel]; + newModel[index] = option; + setTriggeredModel(newModel); + }} + /> +
+
+ { + const newPoint = [...triggeredPoint]; + newPoint[index] = option; + setTriggeredPoint(newPoint); + }} + /> +
+
+ { + const newAction = [...triggeredAction]; + newAction[index] = option; + setTriggeredAction(newAction); + }} + /> +
+
+
+ ))} +
+
+ ); +}; -export default Trigger \ No newline at end of file +export default Trigger; From d53ef429c819486d91bb89316acf9ed2281a437b Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 23 Apr 2025 18:52:27 +0530 Subject: [PATCH 13/22] feat: Remove unused IkInstances import from RoboticArm component --- app/src/modules/simulation/roboticArm/roboticArm.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/modules/simulation/roboticArm/roboticArm.tsx b/app/src/modules/simulation/roboticArm/roboticArm.tsx index 1270d93..02a1690 100644 --- a/app/src/modules/simulation/roboticArm/roboticArm.tsx +++ b/app/src/modules/simulation/roboticArm/roboticArm.tsx @@ -1,6 +1,5 @@ import React from 'react' import RoboticArmInstances from './instances/roboticArmInstances'; -import IkInstances from './instances/ikInstances'; function RoboticArm() { return ( From 4e652bb48e1dfcc3d1c98c15c049e90818771281 Mon Sep 17 00:00:00 2001 From: SreeNath14 <153710861+SreeNath14@users.noreply.github.com> Date: Thu, 24 Apr 2025 09:47:44 +0530 Subject: [PATCH 14/22] feat: Enhance Robotic Arm functionality with state management and action handling --- .../instances/animator/roboticArmAnimator.tsx | 2 +- .../armInstance/roboticArmInstance.tsx | 52 ++- .../instances/roboticArmInstances.tsx | 12 +- .../simulation/roboticArm/roboticArm.tsx | 98 +++++- app/src/modules/simulation/simulation.tsx | 24 +- app/src/store/simulation/useArmBotStore.ts | 298 +++++++++--------- 6 files changed, 319 insertions(+), 167 deletions(-) diff --git a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx index 0cd4fe2..6b35a43 100644 --- a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx +++ b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx @@ -1,6 +1,6 @@ import React from 'react' -function RoboticArmAnimator() { +function RoboticArmAnimator({ armUuid, HandleCallback, currentPhase }: any) { return ( <> ) diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index 2817906..42b775a 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -1,14 +1,58 @@ -import React from 'react' +import React, { useEffect, useState } from 'react' import IKInstance from '../ikInstance/ikInstance'; import RoboticArmAnimator from '../animator/roboticArmAnimator'; +import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; +import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore'; + +function RoboticArmInstance({ armBot }: any) { + const { isPlaying } = usePlayButtonStore(); + const [currentPhase, setCurrentPhase] = useState<(string)>("init"); + console.log('currentPhase: ', currentPhase); + const { armBots, addArmBot, addCurrentAction } = useArmBotStore(); + + useEffect(() => { + + console.log('isPlaying: ', isPlaying); + if (isPlaying) { + //Moving armBot from initial point to rest position. + + if (armBot?.isActive && armBot?.state == "idle" && currentPhase == "init") { + addCurrentAction(armBot.modelUuid, 'action-001'); + setCurrentPhase("moving-to-rest"); + + } + //Waiting for trigger. + if (!armBot?.isActive && armBot?.state == "idle" && currentPhase == "moving-to-rest") { + setCurrentPhase("rest"); + } + // Moving armBot from rest position to pick up point. + if (!armBot?.isActive && armBot?.state == "idle" && currentPhase == "rest") { + + } + //Moving arm from start point to end point. + if (armBot?.isActive && armBot?.state == "running " && currentPhase == "rest-to-start ") { + + } + //Moving arm from end point to idle. + if (armBot?.isActive && armBot?.state == "running" && currentPhase == "end-to-start") { + + } + + } + + }, [currentPhase, armBot, isPlaying]) + + const HandleCallback = () => { + if (armBot.isActive && armBot.state == "idle" && currentPhase == "init") { + addCurrentAction('armbot-xyz-001', 'action-001'); + } + } -function RoboticArmInstance() { return ( <> - - + ) diff --git a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx index 6e8a70a..1f963c8 100644 --- a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx +++ b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx @@ -1,11 +1,21 @@ import React from 'react' import RoboticArmInstance from './armInstance/roboticArmInstance'; +import { useArmBotStore } from '../../../../store/simulation/useArmBotStore'; function RoboticArmInstances() { + const { armBots } = useArmBotStore(); + + return ( <> + { + armBots?.map((robot: any) => ( - + + ) + ) + + } ) diff --git a/app/src/modules/simulation/roboticArm/roboticArm.tsx b/app/src/modules/simulation/roboticArm/roboticArm.tsx index 1270d93..7899f56 100644 --- a/app/src/modules/simulation/roboticArm/roboticArm.tsx +++ b/app/src/modules/simulation/roboticArm/roboticArm.tsx @@ -1,15 +1,103 @@ -import React from 'react' -import RoboticArmInstances from './instances/roboticArmInstances'; -import IkInstances from './instances/ikInstances'; +import React, { useEffect } from "react"; +import RoboticArmInstances from "./instances/roboticArmInstances"; +import IkInstances from "./instances/ikInstances"; +import { log } from "node:console"; +import { useArmBotStore } from "../../../store/simulation/useArmBotStore"; function RoboticArm() { + const { armBots, addArmBot, addCurrentAction } = useArmBotStore(); + + const armBotStatusSample: RoboticArmEventSchema[] = [ + { + state: "idle", + // currentAction: { + // actionUuid: "action-001", + // actionName: "Pick Component", + // }, + modelUuid: "armbot-xyz-001", + modelName: "ArmBot-X200", + position: [0, 0, 0], + rotation: [91.94347308985614, 0, 6.742905194869091], + type: "roboticArm", + speed: 1.5, + point: { + uuid: "point-123", + position: [0, 1.5, 0], + rotation: [0, 0, 0], + actions: [ + { + actionUuid: "action-001", + actionName: "Pick Component", + actionType: "pickAndPlace", + process: { + startPoint: [1.2, 0.3, 0.5], + endPoint: [-0.8, 1.1, 0.7], + }, + triggers: [ + { + triggerUuid: "trigger-001", + triggerName: "Start Trigger", + triggerType: "onStart", + delay: 0, + triggeredAsset: { + triggeredModel: { + modelName: "Conveyor A1", + modelUuid: "conveyor-01", + }, + triggeredPoint: { + pointName: "Start Point", + pointUuid: "conveyor-01-point-001", + }, + triggeredAction: { + actionName: "Move Forward", + actionUuid: "conveyor-action-01", + }, + }, + }, + { + triggerUuid: "trigger-002", + triggerName: "Complete Trigger", + triggerType: "onComplete", + delay: 0, + triggeredAsset: { + triggeredModel: { + modelName: "StaticMachine B2", + modelUuid: "machine-02", + }, + triggeredPoint: { + pointName: "Receive Point", + pointUuid: "machine-02-point-001", + }, + triggeredAction: { + actionName: "Process Part", + actionUuid: "machine-action-01", + }, + }, + }, + ], + }, + ], + }, + }, + ]; + + useEffect(() => { + addArmBot('123', armBotStatusSample[0]); + // addCurrentAction('armbot-xyz-001', 'action-001'); + }, []); + + + useEffect(() => { + console.log('armBots: ', armBots); + }, [armBots]); + return ( <> - ) + ); } -export default RoboticArm; \ No newline at end of file +export default RoboticArm; diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index 1be292e..556ed01 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -1,30 +1,30 @@ -import React, { useEffect } from 'react'; -import { useEventsStore } from '../../store/simulation/useEventsStore'; -import { useProductStore } from '../../store/simulation/useProductStore'; -import Vehicles from './vehicle/vehicles'; -import Points from './events/points/points'; +import React, { useEffect } from "react"; +import { useEventsStore } from "../../store/simulation/useEventsStore"; +import { useProductStore } from "../../store/simulation/useProductStore"; +import Vehicles from "./vehicle/vehicles"; +import Points from "./events/points/points"; +import RoboticArm from "./roboticArm/roboticArm"; function Simulation() { const { events } = useEventsStore(); const { products } = useProductStore(); useEffect(() => { - console.log('events: ', events); - }, [events]) + console.log("events: ", events); + }, [events]); useEffect(() => { // console.log('products: ', products); - }, [products]) + }, [products]); return ( <> - - + - ) + ); } -export default Simulation \ No newline at end of file +export default Simulation; diff --git a/app/src/store/simulation/useArmBotStore.ts b/app/src/store/simulation/useArmBotStore.ts index 493a068..84f0ec9 100644 --- a/app/src/store/simulation/useArmBotStore.ts +++ b/app/src/store/simulation/useArmBotStore.ts @@ -1,160 +1,170 @@ -import { create } from 'zustand'; -import { immer } from 'zustand/middleware/immer'; +import { create } from "zustand"; +import { immer } from "zustand/middleware/immer"; interface ArmBotStore { - armBots: ArmBotStatus[]; + armBots: ArmBotStatus[]; - addArmBot: (productId: string, event: RoboticArmEventSchema) => void; - removeArmBot: (modelUuid: string) => void; - updateArmBot: ( - modelUuid: string, - updates: Partial> - ) => void; + addArmBot: (productId: string, event: RoboticArmEventSchema) => void; + removeArmBot: (modelUuid: string) => void; - addCurrentAction: (modelUuid: string, actionUuid: string) => void; - removeCurrentAction: (modelUuid: string) => void; + updateArmBot: ( + modelUuid: string, + updates: Partial> + ) => void; - addAction: (modelUuid: string, action: RoboticArmPointSchema['actions'][number]) => void; - removeAction: (modelUuid: string, actionUuid: string) => void; + addCurrentAction: (modelUuid: string, actionUuid: string) => void; + removeCurrentAction: (modelUuid: string) => void; - setArmBotActive: (modelUuid: string, isActive: boolean) => void; + addAction: ( + modelUuid: string, + action: RoboticArmPointSchema["actions"][number] + ) => void; + removeAction: (modelUuid: string, actionUuid: string) => void; - incrementActiveTime: (modelUuid: string, incrementBy: number) => void; - incrementIdleTime: (modelUuid: string, incrementBy: number) => void; + setArmBotActive: (modelUuid: string, isActive: boolean) => void; - getArmBotById: (modelUuid: string) => ArmBotStatus | undefined; - getArmBotsByProduct: (productId: string) => ArmBotStatus[]; - getArmBotsByState: (state: string) => ArmBotStatus[]; - getActiveArmBots: () => ArmBotStatus[]; - getIdleArmBots: () => ArmBotStatus[]; - getArmBotsByCurrentAction: (actionUuid: string) => ArmBotStatus[]; + incrementActiveTime: (modelUuid: string, incrementBy: number) => void; + incrementIdleTime: (modelUuid: string, incrementBy: number) => void; + + getArmBotById: (modelUuid: string) => ArmBotStatus | undefined; + getArmBotsByProduct: (productId: string) => ArmBotStatus[]; + getArmBotsByState: (state: string) => ArmBotStatus[]; + getActiveArmBots: () => ArmBotStatus[]; + getIdleArmBots: () => ArmBotStatus[]; + getArmBotsByCurrentAction: (actionUuid: string) => ArmBotStatus[]; } export const useArmBotStore = create()( - immer((set, get) => ({ - armBots: [], + immer((set, get) => ({ + armBots: [], - addArmBot: (productId, event) => { - set((state) => { - state.armBots.push({ - ...event, - productId, - isActive: false, - idleTime: 0, - activeTime: 0, - state: 'idle', - }); - }); - }, + addArmBot: (productId, event) => { + set((state) => { + state.armBots.push({ + ...event, + productId, + isActive: false, + idleTime: 0, + activeTime: 0, + state: "idle", + }); + }); + }, - removeArmBot: (modelUuid) => { - set((state) => { - state.armBots = state.armBots.filter(a => a.modelUuid !== modelUuid); - }); - }, + removeArmBot: (modelUuid) => { + set((state) => { + state.armBots = state.armBots.filter((a) => a.modelUuid !== modelUuid); + }); + }, - updateArmBot: (modelUuid, updates) => { - set((state) => { - const armBot = state.armBots.find(a => a.modelUuid === modelUuid); - if (armBot) { - Object.assign(armBot, updates); - } - }); - }, - - addCurrentAction: (modelUuid, actionUuid) => { - set((state) => { - const armBot = state.armBots.find(a => a.modelUuid === modelUuid); - if (armBot) { - const action = armBot.point.actions.find(a => a.actionUuid === actionUuid); - if (action) { - armBot.currentAction = { - actionUuid: action.actionUuid, - actionName: action.actionName, - }; - armBot.isActive = true; - } - } - }); - }, - - removeCurrentAction: (modelUuid) => { - set((state) => { - const armBot = state.armBots.find(a => a.modelUuid === modelUuid); - if (armBot) { - armBot.currentAction = undefined; - armBot.isActive = false; - } - }); - }, - - addAction: (modelUuid, action) => { - set((state) => { - const armBot = state.armBots.find(a => a.modelUuid === modelUuid); - if (armBot) { - armBot.point.actions.push(action); - } - }); - }, - - removeAction: (modelUuid, actionUuid) => { - set((state) => { - const armBot = state.armBots.find(a => a.modelUuid === modelUuid); - if (armBot) { - armBot.point.actions = armBot.point.actions.filter(a => a.actionUuid !== actionUuid); - } - }); - }, - - setArmBotActive: (modelUuid, isActive) => { - set((state) => { - const armBot = state.armBots.find(a => a.modelUuid === modelUuid); - if (armBot) { - armBot.isActive = isActive; - } - }); - }, - - incrementActiveTime: (modelUuid, incrementBy) => { - set((state) => { - const armBot = state.armBots.find(a => a.modelUuid === modelUuid); - if (armBot) { - armBot.activeTime += incrementBy; - } - }); - }, - - incrementIdleTime: (modelUuid, incrementBy) => { - set((state) => { - const armBot = state.armBots.find(a => a.modelUuid === modelUuid); - if (armBot) { - armBot.idleTime += incrementBy; - } - }); - }, - - getArmBotById: (modelUuid) => { - return get().armBots.find(a => a.modelUuid === modelUuid); - }, - - getArmBotsByProduct: (productId) => { - return get().armBots.filter(a => a.productId === productId); - }, - - getArmBotsByState: (state) => { - return get().armBots.filter(a => a.state === state); - }, - - getActiveArmBots: () => { - return get().armBots.filter(a => a.isActive); - }, - - getIdleArmBots: () => { - return get().armBots.filter(a => !a.isActive && a.state === 'idle'); - }, - - getArmBotsByCurrentAction: (actionUuid) => { - return get().armBots.filter(a => a.currentAction?.actionUuid === actionUuid); + updateArmBot: (modelUuid, updates) => { + set((state) => { + const armBot = state.armBots.find((a) => a.modelUuid === modelUuid); + if (armBot) { + Object.assign(armBot, updates); } - })) + }); + }, + + addCurrentAction: (modelUuid, actionUuid) => { + set((state) => { + const armBot = state.armBots.find((a) => a.modelUuid === modelUuid); + if (armBot) { + const action = armBot.point.actions.find( + (a) => a.actionUuid === actionUuid + ); + if (action) { + armBot.currentAction = { + actionUuid: action.actionUuid, + actionName: action.actionName, + }; + armBot.isActive = true; + } + } + }); + }, + + removeCurrentAction: (modelUuid) => { + set((state) => { + const armBot = state.armBots.find((a) => a.modelUuid === modelUuid); + if (armBot) { + armBot.currentAction = undefined; + armBot.isActive = false; + } + }); + }, + + addAction: (modelUuid, action) => { + set((state) => { + const armBot = state.armBots.find((a) => a.modelUuid === modelUuid); + if (armBot) { + armBot.point.actions.push(action); + } + }); + }, + + removeAction: (modelUuid, actionUuid) => { + set((state) => { + const armBot = state.armBots.find((a) => a.modelUuid === modelUuid); + if (armBot) { + armBot.point.actions = armBot.point.actions.filter( + (a) => a.actionUuid !== actionUuid + ); + } + }); + }, + + setArmBotActive: (modelUuid, isActive) => { + set((state) => { + const armBot = state.armBots.find((a) => a.modelUuid === modelUuid); + if (armBot) { + armBot.isActive = isActive; + } + }); + }, + + incrementActiveTime: (modelUuid, incrementBy) => { + set((state) => { + const armBot = state.armBots.find((a) => a.modelUuid === modelUuid); + if (armBot) { + armBot.activeTime += incrementBy; + } + }); + }, + + incrementIdleTime: (modelUuid, incrementBy) => { + set((state) => { + const armBot = state.armBots.find((a) => a.modelUuid === modelUuid); + if (armBot) { + armBot.idleTime += incrementBy; + } + }); + }, + + getArmBotById: (modelUuid) => { + return get().armBots.find((a) => a.modelUuid === modelUuid); + }, + + getArmBotsByProduct: (productId) => { + return get().armBots.filter((a) => a.productId === productId); + }, + + getArmBotsByState: (state) => { + return get().armBots.filter((a) => a.state === state); + }, + + getActiveArmBots: () => { + return get().armBots.filter((a) => a.isActive); + }, + + getIdleArmBots: () => { + return get().armBots.filter((a) => !a.isActive && a.state === "idle"); + }, + + getArmBotsByCurrentAction: (actionUuid) => { + return get().armBots.filter( + (a) => a.currentAction?.actionUuid === actionUuid + ); + }, + })) ); From 85515c6cd319f60d975aff25b9df290afa57a6a9 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Thu, 24 Apr 2025 11:07:15 +0530 Subject: [PATCH 15/22] feat: Refactor simulation components and enhance product management with new features --- .../layout/sidebarRight/SideBarRight.tsx | 20 +- .../sidebarRight/simulation/Simulations.tsx | 271 ++++++++++-------- .../modules/simulation/products/products.tsx | 20 ++ app/src/modules/simulation/simulation.tsx | 3 + app/src/store/simulation/useArmBotStore.ts | 27 ++ app/src/store/simulation/useProductStore.ts | 83 ++++++ .../store/simulation/useSimulationStore.ts | 24 ++ 7 files changed, 313 insertions(+), 135 deletions(-) create mode 100644 app/src/modules/simulation/products/products.tsx diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx index 277637a..b13944c 100644 --- a/app/src/components/layout/sidebarRight/SideBarRight.tsx +++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx @@ -72,9 +72,8 @@ const SideBarRight: React.FC = () => {
{/* {activeModule === "builder" && ( */}
setSubModule("properties")} > @@ -83,25 +82,22 @@ const SideBarRight: React.FC = () => { {activeModule === "simulation" && ( <>
setSubModule("mechanics")} >
setSubModule("simulations")} >
setSubModule("analysis")} > diff --git a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx index 2a12734..cbb19fa 100644 --- a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx +++ b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx @@ -1,147 +1,172 @@ -import React, { useRef, useState } from "react"; +import React, { useEffect, useRef } from "react"; import { - AddIcon, - ArrowIcon, - RemoveIcon, - ResizeHeightIcon, + AddIcon, + ArrowIcon, + RemoveIcon, + ResizeHeightIcon, } from "../../../icons/ExportCommonIcons"; import RenameInput from "../../../ui/inputs/RenameInput"; import { handleResize } from "../../../../functions/handleResizePannel"; +import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; +import { useProductStore } from "../../../../store/simulation/useProductStore"; +import { generateUUID } from "three/src/math/MathUtils"; -interface Path { - pathName: string; // Represents the name of the path - Children: string[]; // Represents the list of child points +interface Event { + pathName: string; } -interface DropListProps { - val: Path; // Use the Path interface for the val prop +interface ListProps { + val: Event; } -const DropList: React.FC = ({ val }) => { - const [openDrop, setOpenDrop] = useState(false); - return ( -
-
{ - setOpenDrop(!openDrop); - }} - > - {val.pathName} -
- -
-
- {val.Children && openDrop && ( -
- {val.Children.map((child, index) => ( -
- {child} +const List: React.FC = ({ val }) => { + return ( +
+
+ {val.pathName}
- ))}
- )} -
- ); + ); }; const Simulations: React.FC = () => { - const productsContainerRef = useRef(null); - const [productsList, setProductsList] = useState([]); - const [selectedItem, setSelectedItem] = useState(); + const productsContainerRef = useRef(null); + const { products, addProduct, removeProduct, renameProduct } = useProductStore(); + const { selectedProduct, setSelectedProduct } = useSelectedProduct(); - const handleAddAction = () => { - setProductsList([...productsList, `Product ${productsList.length + 1}`]); - }; + useEffect(() => { + if (products.length > 0 && selectedProduct.productId === '' && selectedProduct.productName === '') { + setSelectedProduct(products[0].productId, products[0].productName); + } + }, [products, selectedProduct]); - const handleRemoveAction = (index: number) => { - setProductsList(productsList.filter((_, i) => i !== index)); - if (selectedItem === productsList[index]) { - setSelectedItem(""); - } - }; + const handleAddProduct = () => { + addProduct(`Product ${products.length + 1}`, generateUUID()); + }; - const Value = [ - { pathName: "Path 1", Children: ["Point 1", "Point 2"] }, - { pathName: "Path 2", Children: ["Point 1", "Point 2"] }, - { pathName: "Path 3", Children: ["Point 1", "Point 2"] }, - ]; + const handleRemoveProduct = (productId: string) => { + const currentIndex = products.findIndex(p => p.productId === productId); + const isSelected = selectedProduct.productId === productId; - return ( -
-
Simulations
-
-
-
-
Products
-
- Add -
-
-
-
- {productsList.map((action, index) => ( -
-
setSelectedItem(action)} - > - - -
-
handleRemoveAction(index)} - > - -
+ const updatedProducts = products.filter(p => p.productId !== productId); + + if (isSelected) { + if (updatedProducts.length > 0) { + let newSelectedIndex = currentIndex; + if (currentIndex >= updatedProducts.length) { + newSelectedIndex = updatedProducts.length - 1; + } + setSelectedProduct( + updatedProducts[newSelectedIndex].productId, + updatedProducts[newSelectedIndex].productName + ); + } else { + setSelectedProduct('', ''); + } + } + + removeProduct(productId); + }; + + const handleRenameProduct = (productId: string, newName: string) => { + renameProduct(productId, newName); + if (selectedProduct.productId === productId) { + setSelectedProduct(productId, newName); + } + }; + + const selectedProductData = products.find( + (product) => product.productId === selectedProduct.productId + ); + + const events: Event[] = selectedProductData?.eventsData.map((event, index) => ({ + pathName: `${event.modelName} - ${event.type} #${index + 1}`, + })) || []; + + return ( +
+
Simulations
+
+
+
+
Products
+
+ Add +
+
+
+
+ {products.map((product, index) => ( +
+
setSelectedProduct(product.productId, product.productName)} + > + + handleRenameProduct(product.productId, newName)} + /> +
+ {products.length > 1 && ( +
handleRemoveProduct(product.productId)} + > + +
+ )} +
+ ))} +
+
handleResize(e, productsContainerRef)} + > + +
+
+
+ +
+
+
Events
+
+ +
+
+ {events.map((event, index) => ( + + ))} +
+ +
+
+ Need to Compare Layout? +
+
+ Click 'Compare' to review and analyze the layout differences between them. +
+
+ +
- ))}
-
handleResize(e, productsContainerRef)} - > - -
-
-
-
-
Operations
-
- -
-
- {Value.map((val, index) => ( - - ))} -
-
-
- Need to Compare Layout? -
-
- Click 'Compare' to review and analyze the layout - differences between them. -
-
- -
-
-
-
- ); + ); }; export default Simulations; diff --git a/app/src/modules/simulation/products/products.tsx b/app/src/modules/simulation/products/products.tsx new file mode 100644 index 0000000..2e9a16e --- /dev/null +++ b/app/src/modules/simulation/products/products.tsx @@ -0,0 +1,20 @@ +import React, { useEffect } from 'react' +import { useProductStore } from '../../../store/simulation/useProductStore' +import * as THREE from 'three'; + +function Products() { + const { products, addProduct } = useProductStore(); + + useEffect(() => { + if (products.length === 0) { + addProduct('Product 1', THREE.MathUtils.generateUUID()); + } + }, [products]) + + return ( + <> + + ) +} + +export default Products \ No newline at end of file diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index 572fc70..f02b066 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -9,6 +9,7 @@ import Materials from './materials/materials'; import Machine from './machine/machine'; import StorageUnit from './storageUnit/storageUnit'; import Simulator from './simulator/simulator'; +import Products from './products/products'; function Simulation() { const { events } = useEventsStore(); @@ -27,6 +28,8 @@ function Simulation() { + + diff --git a/app/src/store/simulation/useArmBotStore.ts b/app/src/store/simulation/useArmBotStore.ts index 493a068..d907f21 100644 --- a/app/src/store/simulation/useArmBotStore.ts +++ b/app/src/store/simulation/useArmBotStore.ts @@ -17,6 +17,9 @@ interface ArmBotStore { addAction: (modelUuid: string, action: RoboticArmPointSchema['actions'][number]) => void; removeAction: (modelUuid: string, actionUuid: string) => void; + updateStartPoint: (modelUuid: string, actionUuid: string, startPoint: [number, number, number] | null) => void; + updateEndPoint: (modelUuid: string, actionUuid: string, endPoint: [number, number, number] | null) => void; + setArmBotActive: (modelUuid: string, isActive: boolean) => void; incrementActiveTime: (modelUuid: string, incrementBy: number) => void; @@ -106,6 +109,30 @@ export const useArmBotStore = create()( }); }, + updateStartPoint: (modelUuid, actionUuid, startPoint) => { + set((state) => { + const armBot = state.armBots.find(a => a.modelUuid === modelUuid); + if (armBot) { + const action = armBot.point.actions.find(a => a.actionUuid === actionUuid); + if (action) { + action.process.startPoint = startPoint; + } + } + }); + }, + + updateEndPoint: (modelUuid, actionUuid, endPoint) => { + set((state) => { + const armBot = state.armBots.find(a => a.modelUuid === modelUuid); + if (armBot) { + const action = armBot.point.actions.find(a => a.actionUuid === actionUuid); + if (action) { + action.process.endPoint = endPoint; + } + } + }); + }, + setArmBotActive: (modelUuid, isActive) => { set((state) => { const armBot = state.armBots.find(a => a.modelUuid === modelUuid); diff --git a/app/src/store/simulation/useProductStore.ts b/app/src/store/simulation/useProductStore.ts index 41a13f6..81feb7f 100644 --- a/app/src/store/simulation/useProductStore.ts +++ b/app/src/store/simulation/useProductStore.ts @@ -48,6 +48,11 @@ type ProductsStore = { updates: Partial ) => void; + // Renaming functions + renameProduct: (productId: string, newName: string) => void; + renameAction: (actionUuid: string, newName: string) => void; + renameTrigger: (triggerUuid: string, newName: string) => void; + // Helper functions getProductById: (productId: string) => { productName: string; productId: string; eventsData: EventsSchema[] } | undefined; }; @@ -331,6 +336,84 @@ export const useProductStore = create()( }); }, + // Renaming functions + renameProduct: (productId, newName) => { + set((state) => { + const product = state.products.find(p => p.productId === productId); + if (product) { + product.productName = newName; + } + }); + }, + + renameAction: (actionUuid, newName) => { + set((state) => { + for (const product of state.products) { + for (const event of product.eventsData) { + if ('points' in event) { + for (const point of (event as ConveyorEventSchema).points) { + if (point.action && point.action.actionUuid === actionUuid) { + point.action.actionName = newName; + return; + } + } + } else if ('point' in event) { + const point = (event as any).point; + if ('action' in point && point.action.actionUuid === actionUuid) { + point.action.actionName = newName; + return; + } else if ('actions' in point) { + const action = point.actions.find((a: any) => a.actionUuid === actionUuid); + if (action) { + action.actionName = newName; + return; + } + } + } + } + } + }); + }, + + renameTrigger: (triggerUuid, newName) => { + set((state) => { + for (const product of state.products) { + for (const event of product.eventsData) { + 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) { + trigger.triggerName = newName; + return; + } + } + } + } 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) { + trigger.triggerName = newName; + return; + } + } 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) { + trigger.triggerName = newName; + return; + } + } + } + } + } + } + } + }); + }, + // Helper functions getProductById: (productId) => { return get().products.find(p => p.productId === productId); diff --git a/app/src/store/simulation/useSimulationStore.ts b/app/src/store/simulation/useSimulationStore.ts index 2d63802..9c0fc00 100644 --- a/app/src/store/simulation/useSimulationStore.ts +++ b/app/src/store/simulation/useSimulationStore.ts @@ -22,4 +22,28 @@ export const useSelectedEventSphere = create()( }); }, })) +); + +interface SelectedProductState { + selectedProduct: { productId: string; productName: string }; + setSelectedProduct: (productId: string, productName: string) => void; + clearSelectedProduct: () => void; +} + +export const useSelectedProduct = create()( + immer((set) => ({ + selectedProduct: { productId: '', productName: '' }, + setSelectedProduct: (productId, productName) => { + set((state) => { + state.selectedProduct.productId = productId; + state.selectedProduct.productName = productName; + }); + }, + clearSelectedProduct: () => { + set((state) => { + state.selectedProduct.productId = ''; + state.selectedProduct.productName = ''; + }); + }, + })) ); \ No newline at end of file From a305c3c00635bdced28b15149e52bfdc81a94d1b Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Thu, 24 Apr 2025 16:38:42 +0530 Subject: [PATCH 16/22] Refactor EventProperties component to utilize new state management for selected event data and asset selection; implement action handling based on asset type and improve action rendering logic. Enhance Simulations component to support adding and removing events from products; integrate new asset selection store for better state management. Fix import paths in Design component and related files to ensure correct module resolution. Update Tools component to correct import paths for template saving functionality. Refactor EditWidgetOption component to simplify option handling and remove unnecessary state management. Add new mechanics components for various asset types (Conveyor, Machine, Robotic Arm, Storage, Vehicle) as placeholders for future implementation. Implement Trigger and TriggerConnector components to manage right-click interactions and asset selection in the simulation environment. Enhance product store with new helper functions for event and action retrieval based on UUIDs. Introduce new selected event data and asset state management in the simulation store for improved event handling. Update simulation types to include new action types and improve type definitions for better type safety. Remove obsolete temp markdown file from triggers directory. --- .../layout/sidebarLeft/SideBarLeft.tsx | 4 +- .../visualization/widgets/WidgetsFloating.tsx | 8 +- .../layout/sidebarRight/SideBarRight.tsx | 277 +++++------ .../eventProperties/EventProperties.tsx | 435 ++++++++++-------- .../mechanics/conveyorMechanics.tsx | 10 + .../mechanics/machineMechanics.tsx | 10 + .../mechanics/roboticArmMechanics.tsx | 10 + .../mechanics/storageMechanics.tsx | 10 + .../mechanics/vehicleMechanics.tsx | 10 + .../sidebarRight/simulation/Simulations.tsx | 46 +- .../visualization/design/Design.tsx | 4 +- app/src/components/ui/Tools.tsx | 2 +- .../components/ui/menu/EditWidgetOption.tsx | 12 +- app/src/modules/builder/builder.tsx | 2 +- .../events/points/creator/pointsCreator.tsx | 21 +- .../modules/simulation/products/products.tsx | 7 +- app/src/modules/simulation/simulation.tsx | 35 +- .../triggers/connector/triggerConnector.tsx | 126 +++++ app/src/modules/simulation/triggers/temp.md | 0 .../modules/simulation/triggers/trigger.tsx | 14 + .../visualization/RealTimeVisulization.tsx | 6 +- .../visulization/zone/getSelect2dZoneData.ts | 2 +- app/src/store/simulation/useProductStore.ts | 88 ++++ .../store/simulation/useSimulationStore.ts | 44 ++ app/src/store/useModuleStore.ts | 9 +- app/src/types/simulationTypes.d.ts | 4 +- 26 files changed, 813 insertions(+), 383 deletions(-) create mode 100644 app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx create mode 100644 app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx create mode 100644 app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx create mode 100644 app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx create mode 100644 app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx create mode 100644 app/src/modules/simulation/triggers/connector/triggerConnector.tsx delete mode 100644 app/src/modules/simulation/triggers/temp.md create mode 100644 app/src/modules/simulation/triggers/trigger.tsx diff --git a/app/src/components/layout/sidebarLeft/SideBarLeft.tsx b/app/src/components/layout/sidebarLeft/SideBarLeft.tsx index dc412f7..e0b56d4 100644 --- a/app/src/components/layout/sidebarLeft/SideBarLeft.tsx +++ b/app/src/components/layout/sidebarLeft/SideBarLeft.tsx @@ -5,8 +5,8 @@ import Header from "./Header"; import useToggleStore from "../../../store/useUIToggleStore"; import Assets from "./Assets"; import useModuleStore from "../../../store/useModuleStore"; -import Widgets from ".//visualization/widgets/Widgets"; -import Templates from "../../../modules//visualization/template/Templates"; +import Widgets from "./visualization/widgets/Widgets"; +import Templates from "../../../modules/visualization/template/Templates"; import Search from "../../ui/inputs/Search"; const SideBarLeft: React.FC = () => { diff --git a/app/src/components/layout/sidebarLeft/visualization/widgets/WidgetsFloating.tsx b/app/src/components/layout/sidebarLeft/visualization/widgets/WidgetsFloating.tsx index 50d9712..b5ae0bb 100644 --- a/app/src/components/layout/sidebarLeft/visualization/widgets/WidgetsFloating.tsx +++ b/app/src/components/layout/sidebarLeft/visualization/widgets/WidgetsFloating.tsx @@ -5,11 +5,11 @@ import { GlobeIcon, WalletIcon, } from "../../../../icons/3dChartIcons"; -import SimpleCard from "../../../../../modules//visualization/widgets/floating/cards/SimpleCard"; +import SimpleCard from "../../../../../modules/visualization/widgets/floating/cards/SimpleCard"; -import WarehouseThroughput from "../../../../../modules//visualization/widgets/floating/cards/WarehouseThroughput"; -import ProductivityDashboard from "../../../../../modules//visualization/widgets/floating/cards/ProductivityDashboard"; -import FleetEfficiency from "../../../../../modules//visualization/widgets/floating/cards/FleetEfficiency"; +import WarehouseThroughput from "../../../../../modules/visualization/widgets/floating/cards/WarehouseThroughput"; +import ProductivityDashboard from "../../../../../modules/visualization/widgets/floating/cards/ProductivityDashboard"; +import FleetEfficiency from "../../../../../modules/visualization/widgets/floating/cards/FleetEfficiency"; interface Widget { id: string; diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx index b13944c..f5668bf 100644 --- a/app/src/components/layout/sidebarRight/SideBarRight.tsx +++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx @@ -1,173 +1,148 @@ -import React, { useEffect, useState } from "react"; +import React, { useEffect } from "react"; import Header from "./Header"; import useModuleStore, { - useSubModuleStore, + useSubModuleStore, } from "../../../store/useModuleStore"; import { - AnalysisIcon, - MechanicsIcon, - PropertiesIcon, - SimulationIcon, + AnalysisIcon, + MechanicsIcon, + PropertiesIcon, + SimulationIcon, } from "../../icons/SimulationIcons"; import useToggleStore from "../../../store/useUIToggleStore"; import Visualization from "./visualization/Visualization"; import Analysis from "./analysis/Analysis"; import Simulations from "./simulation/Simulations"; import { useSelectedFloorItem } from "../../../store/store"; +import { useSelectedEventData, useSelectedEventSphere } from "../../../store/simulation/useSimulationStore"; import GlobalProperties from "./properties/GlobalProperties"; import AsstePropertiies from "./properties/AssetProperties"; import ZoneProperties from "./properties/ZoneProperties"; import EventProperties from "./properties/eventProperties/EventProperties"; const SideBarRight: React.FC = () => { - const { activeModule } = useModuleStore(); - const { toggleUI } = useToggleStore(); - const { subModule, setSubModule } = useSubModuleStore(); - const { selectedFloorItem } = useSelectedFloorItem(); + const { activeModule } = useModuleStore(); + const { toggleUI } = useToggleStore(); + const { subModule, setSubModule } = useSubModuleStore(); + const { selectedFloorItem } = useSelectedFloorItem(); + const { selectedEventData } = useSelectedEventData(); + const { selectedEventSphere } = useSelectedEventSphere(); - // Reset activeList whenever activeModule changes - useEffect(() => { - if (activeModule !== "simulation") setSubModule("properties"); - if (activeModule === "simulation") setSubModule("mechanics"); - }, [activeModule]); + // Reset activeList whenever activeModule changes + useEffect(() => { + if (activeModule !== "simulation") setSubModule("properties"); + if (activeModule === "simulation") setSubModule("simulations"); + }, [activeModule]); - // romove late - const dummyData = { - assetType: "store", - selectedPoint: { - name: "Point A", - uuid: "123e4567-e89b-12d3-a456-426614174000", - actions: [ - { - uuid: "action-1", - name: "Action One", - }, - { - uuid: "action-2", - name: "Action Two", - }, - { - uuid: "action-3", - name: "Action Three", - }, - ], - }, - selectedItem: { - item: { - uuid: "item-1", - name: "Item One", - isUsed: false, - }, - }, - setSelectedPoint: (value: string) => { - console.log(`Selected point updated to: ${value}`); - }, - selectedActionSphere: "Sphere A", - }; + useEffect(() => { + if (activeModule !== "mechanics" && selectedEventData && selectedEventSphere) { + setSubModule("mechanics"); + } else { + if (activeModule === 'simulation') { + setSubModule("simulations"); + } + }; + }, [activeModule, selectedEventData, selectedEventSphere]) - return ( -
-
- {toggleUI && ( -
- {/* {activeModule === "builder" && ( */} -
setSubModule("properties")} - > - -
- {/* )} */} - {activeModule === "simulation" && ( - <> -
setSubModule("mechanics")} - > - -
-
setSubModule("simulations")} - > - -
-
setSubModule("analysis")} - > - -
- - )} + return ( +
+
+ {toggleUI && ( +
+
setSubModule("properties")} + > + +
+ {activeModule === "simulation" && ( + <> +
setSubModule("mechanics")} + > + +
+
setSubModule("simulations")} + > + +
+
setSubModule("analysis")} + > + +
+ + )} +
+ )} + {/* process builder */} + {toggleUI && + subModule === "properties" && + activeModule !== "visualization" && + !selectedFloorItem && ( +
+
+ +
+
+ )} + {toggleUI && + subModule === "properties" && + activeModule !== "visualization" && + selectedFloorItem && ( +
+
+ +
+
+ )} + {toggleUI && + subModule === "zoneProperties" && + (activeModule === "builder" || activeModule === "simulation") && ( +
+
+ +
+
+ )} + {/* simulation */} + {toggleUI && activeModule === "simulation" && ( + <> + {subModule === "simulations" && ( +
+
+ +
+
+ )} + {subModule === "mechanics" && selectedEventData && selectedEventSphere && ( +
+
+ +
+
+ )} + {subModule === "analysis" && ( +
+
+ +
+
+ )} + + )} + {/* realtime visualization */} + {toggleUI && activeModule === "visualization" && }
- )} - {/* process builder */} - {toggleUI && - subModule === "properties" && - activeModule !== "visualization" && - !selectedFloorItem && ( -
-
- -
-
- )} - {toggleUI && - subModule === "properties" && - activeModule !== "visualization" && - selectedFloorItem && ( -
-
- -
-
- )} - {toggleUI && - subModule === "zoneProperties" && - (activeModule === "builder" || activeModule === "simulation") && ( -
-
- -
-
- )} - {/* simulation */} - - {toggleUI && activeModule === "simulation" && ( - <> - {subModule === "mechanics" && ( -
-
- -
-
- )} - {subModule === "analysis" && ( -
-
- -
-
- )} - {subModule === "simulations" && ( -
-
- -
-
- )} - - )} - - {/* realtime visualization */} - {toggleUI && activeModule === "visualization" && } -
- ); + ); }; -export default SideBarRight; +export default SideBarRight; \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx index c3ec6e7..6c44947 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx @@ -1,10 +1,10 @@ -import React, { useRef, useState } from "react"; +import React, { useEffect, useRef, useState } from "react"; import InputWithDropDown from "../../../../ui/inputs/InputWithDropDown"; import LabledDropdown from "../../../../ui/inputs/LabledDropdown"; import { - AddIcon, - RemoveIcon, - ResizeHeightIcon, + AddIcon, + RemoveIcon, + ResizeHeightIcon, } from "../../../../icons/ExportCommonIcons"; import RenameInput from "../../../../ui/inputs/RenameInput"; import { handleResize } from "../../../../../functions/handleResizePannel"; @@ -20,191 +20,260 @@ import ProcessAction from "./actions/ProcessAction"; import StorageAction from "./actions/StorageAction"; import Trigger from "./trigger/Trigger"; -interface EventPropertiesProps { - assetType: string; - selectedPoint: { - name: string; - uuid: string; - actions: { - uuid: string; - name: string; - }[]; - }; - selectedItem: { - item: { - uuid: string; - name: string; - } | null; - }; - setSelectedPoint: (value: string) => void; - selectedActionSphere: string; -} +import { useSelectedEventData, useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; +import { useProductStore } from "../../../../../store/simulation/useProductStore"; -const EventProperties: React.FC = ({ - assetType, - selectedPoint, - selectedItem, - setSelectedPoint, - selectedActionSphere, -}) => { - const actionsContainerRef = useRef(null); +const EventProperties: React.FC = () => { + const actionsContainerRef = useRef(null); - const [activeOption, setActiveOption] = useState("default"); - const [dummyactiveOption, setTypeOption] = useState("default"); + const [activeOption, setActiveOption] = useState("default"); + const [selectedItem, setSelectedItem] = useState<{ item: { uuid: string; name: string } | null; }>({ item: null }); + const { selectedEventData } = useSelectedEventData(); + const { getEventByModelUuid } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); - const getAvailableActions = () => { - if (assetType === "conveyor") { - return { - defaultOption: "default", - options: ["default", "spawn", "swap", "despawn"], - }; - } - if (assetType === "vehicle") { - return { - defaultOption: "travel", - options: ["travel"], - }; - } - if (assetType === "roboticArm") { - return { - defaultOption: "pickAndPlace", - options: ["pickAndPlace"], - }; - } - if (assetType === "machine") { - return { - defaultOption: "process", - options: ["process"], - }; - } - if (assetType === "store") { - return { - defaultOption: "store", - options: ["store", "spawn"], - }; - } else { - return { - defaultOption: "default", - options: ["default"], - }; - } - }; + useEffect(() => { + const actions = getActions(); + if (actions.length > 0 && !selectedItem.item) { + setSelectedItem({ item: actions[0] }); + } + }, [selectedEventData]); - return ( -
-
-
{selectedPoint.name}
-
-
-
- {/*
- setTypeOption(option)} - /> -
*/} -
- {}} - onChange={(value) => console.log(value)} - /> -
-
- {}} - onChange={(value) => console.log(value)} - /> -
-
-
-
-
-
-
Actions
-
{}}> - Add -
-
-
-
- {selectedPoint?.actions.map((action) => ( -
-
handleActionToggle(action.uuid)} - > - -
- {selectedPoint?.actions.length > 1 && ( -
handleDeleteAction(action.uuid)} - > - + const getCurrentEventData = () => { + if (!selectedEventData?.data || !selectedProduct) return null; + const event = getEventByModelUuid(selectedProduct.productId, selectedEventData.data.modelUuid); + return event || null; + }; + + const getAssetType = () => { + const event = getCurrentEventData(); + if (!event) return null; + + switch (event.type) { + case 'transfer': return 'conveyor'; + case 'vehicle': return 'vehicle'; + case 'roboticArm': return 'roboticArm'; + case 'machine': return 'machine'; + case 'storageUnit': return 'storageUnit'; + default: return null; + } + }; + + const getAvailableActions = () => { + switch (getAssetType()) { + case "conveyor": + return { + defaultOption: "default", + options: ["default", "spawn", "swap", "despawn"], + }; + case "vehicle": + return { + defaultOption: "travel", + options: ["travel"], + }; + case "roboticArm": + return { + defaultOption: "pickAndPlace", + options: ["pickAndPlace"], + }; + case "machine": + return { + defaultOption: "process", + options: ["process"], + }; + case "storageUnit": + return { + defaultOption: "store", + options: ["store", "spawn"], + }; + default: + return { + defaultOption: "default", + options: ["default"], + }; + } + }; + + // Get actions based on asset type + const getActions = () => { + if (!selectedEventData?.data) return []; + + const event = selectedEventData.data; + switch (getAssetType()) { + case "conveyor": + return (event as ConveyorEventSchema).points + .find((point) => point.uuid === selectedEventData?.selectedPoint) + ?.action?.triggers.map((trigger) => ({ + uuid: trigger.triggerUuid, + name: trigger.triggerName, + })) || []; + case "vehicle": + return (event as VehicleEventSchema).point.action.triggers.map( + (trigger) => ({ + uuid: trigger.triggerUuid, + name: trigger.triggerName, + }) + ) || []; + case "roboticArm": + return (event as RoboticArmEventSchema).point.actions.flatMap( + (action) => + action.triggers.map((trigger) => ({ + uuid: trigger.triggerUuid, + name: trigger.triggerName, + })) + ) || []; + case "machine": + return (event as MachineEventSchema).point.action.triggers.map( + (trigger) => ({ + uuid: trigger.triggerUuid, + name: trigger.triggerName, + }) + ) || []; + case "storageUnit": + return [ + { + uuid: (event as StorageEventSchema).point.action.actionUuid, + name: (event as StorageEventSchema).point.action.actionName, + }, + ]; + default: + return []; + } + }; + + const handleActionToggle = (actionUuid: string) => { + const actions = getActions(); + const selected = actions.find(action => action.uuid === actionUuid); + if (selected) { + setSelectedItem({ item: selected }); + } + }; + + const handleDeleteAction = (actionUuid: string) => { + + }; + + const actions = getActions(); + + const getSpeed = () => { + if (!selectedEventData) return "0.5"; + if ("speed" in selectedEventData.data) return selectedEventData.data.speed.toString(); + return "0.5"; + }; + + return ( + <> + {getCurrentEventData() && +
+
+
{selectedEventData?.data.modelName}
+
+
+
+
+ { }} + onChange={(value) => console.log(value)} + /> +
+ +
+ { }} + onChange={(value) => console.log(value)} + /> +
+
+
+ {getAssetType() === 'roboticArm' && +
+
+
+
Actions
+
{ }}> + Add +
+
+
+
+ {actions.map((action) => ( +
+
handleActionToggle(action.uuid)} + > + +
+ {actions.length > 1 && ( +
handleDeleteAction(action.uuid)} + > + +
+ )} +
+ ))} +
+
handleResize(e, actionsContainerRef)} + > + +
+
+
+
+ } +
+
+ +
+
+ setActiveOption(option)} + /> + {activeOption === "default" && } + {activeOption === "spawn" && } + {activeOption === "swap" && } + {activeOption === "despawn" && } + {activeOption === "travel" && } + {activeOption === "pickAndPlace" && } + {activeOption === "process" && } + {activeOption === "store" && } +
+
+
+
- )}
- ))} -
-
handleResize(e, actionsContainerRef)} - > - -
-
-
-
-
-
- -
-
- setActiveOption(option)} - /> - {activeOption === "default" && } {/* done */} - {activeOption === "spawn" && } {/* done */} - {activeOption === "swap" && } {/* done */} - {activeOption === "despawn" && } {/* done */} - {activeOption === "travel" && } {/* done */} - {activeOption === "pickAndPlace" && } {/* done */} - {activeOption === "process" && } {/* done */} - {activeOption === "store" && } {/* done */} -
-
-
- -
-
- ); + } + + ); }; export default EventProperties; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx new file mode 100644 index 0000000..000a9d7 --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx @@ -0,0 +1,10 @@ +import React from 'react' + +function ConveyorMechanics() { + return ( + <> + + ) +} + +export default ConveyorMechanics \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx new file mode 100644 index 0000000..b6e4fb9 --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx @@ -0,0 +1,10 @@ +import React from 'react' + +function MachineMechanics() { + return ( + <> + + ) +} + +export default MachineMechanics \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx new file mode 100644 index 0000000..56e4c27 --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx @@ -0,0 +1,10 @@ +import React from 'react' + +function RoboticArmMechanics() { + return ( + <> + + ) +} + +export default RoboticArmMechanics \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx new file mode 100644 index 0000000..0cda40e --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx @@ -0,0 +1,10 @@ +import React from 'react' + +function StorageMechanics() { + return ( + <> + + ) +} + +export default StorageMechanics \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx new file mode 100644 index 0000000..cdb32c4 --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx @@ -0,0 +1,10 @@ +import React from 'react' + +function VehicleMechanics() { + return ( + <> + + ) +} + +export default VehicleMechanics \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx index cbb19fa..12a424c 100644 --- a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx +++ b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx @@ -7,9 +7,11 @@ import { } from "../../../icons/ExportCommonIcons"; import RenameInput from "../../../ui/inputs/RenameInput"; import { handleResize } from "../../../../functions/handleResizePannel"; -import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; +import { useSelectedAsset, useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../store/simulation/useProductStore"; import { generateUUID } from "three/src/math/MathUtils"; +import RenderOverlay from "../../../templates/Overlay"; +import EditWidgetOption from "../../../ui/menu/EditWidgetOption"; interface Event { pathName: string; @@ -31,14 +33,9 @@ const List: React.FC = ({ val }) => { const Simulations: React.FC = () => { const productsContainerRef = useRef(null); - const { products, addProduct, removeProduct, renameProduct } = useProductStore(); + const { products, addProduct, removeProduct, renameProduct, addEvent, removeEvent } = useProductStore(); const { selectedProduct, setSelectedProduct } = useSelectedProduct(); - - useEffect(() => { - if (products.length > 0 && selectedProduct.productId === '' && selectedProduct.productName === '') { - setSelectedProduct(products[0].productId, products[0].productName); - } - }, [products, selectedProduct]); + const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); const handleAddProduct = () => { addProduct(`Product ${products.length + 1}`, generateUUID()); @@ -75,12 +72,26 @@ const Simulations: React.FC = () => { } }; + const handleAddEventToProduct = () => { + if (selectedAsset) { + addEvent(selectedProduct.productId, selectedAsset); + clearSelectedAsset(); + } + }; + + const handleRemoveEventFromProduct = () => { + if (selectedAsset) { + removeEvent(selectedProduct.productId, selectedAsset.modelUuid); + clearSelectedAsset(); + } + }; + const selectedProductData = products.find( (product) => product.productId === selectedProduct.productId ); - const events: Event[] = selectedProductData?.eventsData.map((event, index) => ({ - pathName: `${event.modelName} - ${event.type} #${index + 1}`, + const events: Event[] = selectedProductData?.eventsData.map((event) => ({ + pathName: event.modelName, })) || []; return ( @@ -165,6 +176,21 @@ const Simulations: React.FC = () => {
+ + {selectedAsset && + + { + if (option === 'Add to Product') { + handleAddEventToProduct(); + } else { + handleRemoveEventFromProduct(); + } + }} + /> + + }
); }; diff --git a/app/src/components/layout/sidebarRight/visualization/design/Design.tsx b/app/src/components/layout/sidebarRight/visualization/design/Design.tsx index 04a569a..234b936 100644 --- a/app/src/components/layout/sidebarRight/visualization/design/Design.tsx +++ b/app/src/components/layout/sidebarRight/visualization/design/Design.tsx @@ -1,9 +1,9 @@ import { useState, useEffect, useRef } from "react"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; -import ChartComponent from "../../../sidebarLeft//visualization/widgets/ChartComponent"; +import ChartComponent from "../../../sidebarLeft/visualization/widgets/ChartComponent"; import RegularDropDown from "../../../../ui/inputs/RegularDropDown"; import { WalletIcon } from "../../../../icons/3dChartIcons"; -import SimpleCard from "../../../../../modules//visualization/widgets/floating/cards/SimpleCard"; +import SimpleCard from "../../../../../modules/visualization/widgets/floating/cards/SimpleCard"; interface Widget { id: string; diff --git a/app/src/components/ui/Tools.tsx b/app/src/components/ui/Tools.tsx index 70b1461..21ea6a7 100644 --- a/app/src/components/ui/Tools.tsx +++ b/app/src/components/ui/Tools.tsx @@ -15,7 +15,7 @@ import { } from "../icons/ExportToolsIcons"; import { ArrowIcon, TickIcon } from "../icons/ExportCommonIcons"; import useModuleStore, { useThreeDStore } from "../../store/useModuleStore"; -import { handleSaveTemplate } from "../../modules//visualization/functions/handleSaveTemplate"; +import { handleSaveTemplate } from "../../modules/visualization/functions/handleSaveTemplate"; import { usePlayButtonStore } from "../../store/usePlayButtonStore"; import useTemplateStore from "../../store/useTemplateStore"; import { useSelectedZoneStore } from "../../store/visualization/useZoneStore"; diff --git a/app/src/components/ui/menu/EditWidgetOption.tsx b/app/src/components/ui/menu/EditWidgetOption.tsx index 6fd1e94..eb937c8 100644 --- a/app/src/components/ui/menu/EditWidgetOption.tsx +++ b/app/src/components/ui/menu/EditWidgetOption.tsx @@ -1,23 +1,20 @@ import React, { useEffect } from "react"; import { - useEditWidgetOptionsStore, useLeftData, - useRightClickSelected, - useRightSelected, useTopData, } from "../../../store/visualization/useZone3DWidgetStore"; interface EditWidgetOptionProps { options: string[]; + onClick: (option: string) => void; } const EditWidgetOption: React.FC = ({ options, + onClick }) => { const { top } = useTopData(); const { left } = useLeftData(); - const { setRightSelect } = useRightSelected(); - const { setEditWidgetOptions } = useEditWidgetOptionsStore(); useEffect(() => { @@ -38,10 +35,7 @@ const EditWidgetOption: React.FC = ({
{ - setRightSelect(option); - setEditWidgetOptions(false); - }} + onClick={() => onClick(option)} > {option}
diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx index e7f83e2..e5ff1c1 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -51,7 +51,7 @@ import Ground from "../scene/environment/ground"; // import ZoneGroup from "../groups/zoneGroup1"; import { findEnvironment } from "../../services/factoryBuilder/environment/findEnvironment"; import Layer2DVisibility from "./geomentries/layers/layer2DVisibility"; -import DrieHtmlTemp from "..//visualization/mqttTemp/drieHtmlTemp"; +import DrieHtmlTemp from "../visualization/mqttTemp/drieHtmlTemp"; import ZoneGroup from "./groups/zoneGroup"; import useModuleStore from "../../store/useModuleStore"; import MeasurementTool from "../scene/tools/measurementTool"; diff --git a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx index 8baacd9..1b3defa 100644 --- a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx +++ b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx @@ -4,15 +4,32 @@ import { useEventsStore } from '../../../../../store/simulation/useEventsStore'; import useModuleStore from '../../../../../store/useModuleStore'; import { TransformControls } from '@react-three/drei'; import { detectModifierKeys } from '../../../../../utils/shortcutkeys/detectModifierKeys'; -import { useSelectedEventSphere } from '../../../../../store/simulation/useSimulationStore'; +import { useSelectedEventSphere, useSelectedEventData } from '../../../../../store/simulation/useSimulationStore'; function PointsCreator() { - const { events, updatePoint, getPointByUuid } = useEventsStore(); + const { events, updatePoint, getPointByUuid, getEventByModelUuid } = useEventsStore(); const { activeModule } = useModuleStore(); const transformRef = useRef(null); const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null); const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({}); const { selectedEventSphere, setSelectedEventSphere, clearSelectedEventSphere } = useSelectedEventSphere(); + const { setSelectedEventData, clearSelectedEventData } = useSelectedEventData(); + + useEffect(() => { + if (selectedEventSphere) { + const eventData = getEventByModelUuid(selectedEventSphere.userData.modelUuid); + if (eventData) { + setSelectedEventData( + eventData, + selectedEventSphere.userData.pointUuid + ); + } else { + clearSelectedEventData(); + } + } else { + clearSelectedEventData(); + } + }, [selectedEventSphere]); useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { diff --git a/app/src/modules/simulation/products/products.tsx b/app/src/modules/simulation/products/products.tsx index 2e9a16e..2ddd7d1 100644 --- a/app/src/modules/simulation/products/products.tsx +++ b/app/src/modules/simulation/products/products.tsx @@ -1,13 +1,18 @@ import React, { useEffect } from 'react' import { useProductStore } from '../../../store/simulation/useProductStore' import * as THREE from 'three'; +import { useSelectedProduct } from '../../../store/simulation/useSimulationStore'; function Products() { const { products, addProduct } = useProductStore(); + const { setSelectedProduct } = useSelectedProduct(); useEffect(() => { if (products.length === 0) { - addProduct('Product 1', THREE.MathUtils.generateUUID()); + const id = THREE.MathUtils.generateUUID(); + const name = 'Product 1'; + addProduct(name, id); + setSelectedProduct(id, name); } }, [products]) diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index f02b066..4197716 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -10,39 +10,52 @@ import Machine from './machine/machine'; import StorageUnit from './storageUnit/storageUnit'; import Simulator from './simulator/simulator'; import Products from './products/products'; +import Trigger from './triggers/trigger'; +import useModuleStore from '../../store/useModuleStore'; function Simulation() { + const { activeModule } = useModuleStore(); const { events } = useEventsStore(); const { products } = useProductStore(); useEffect(() => { - console.log('events: ', events); + // console.log('events: ', events); }, [events]) useEffect(() => { - // console.log('products: ', products); + console.log('products: ', products); }, [products]) return ( <> - + {activeModule === 'simulation' && - + <> - + - + - + - + - + - + - + + + + + + + + + + + } ) diff --git a/app/src/modules/simulation/triggers/connector/triggerConnector.tsx b/app/src/modules/simulation/triggers/connector/triggerConnector.tsx new file mode 100644 index 0000000..b38e6dd --- /dev/null +++ b/app/src/modules/simulation/triggers/connector/triggerConnector.tsx @@ -0,0 +1,126 @@ +import { useThree } from '@react-three/fiber' +import React, { useEffect } from 'react' +import { Object3D } from 'three'; +import { useSubModuleStore } from '../../../../store/useModuleStore'; +import { useLeftData, useTopData } from '../../../../store/visualization/useZone3DWidgetStore'; +import { useEventsStore } from '../../../../store/simulation/useEventsStore'; +import { useProductStore } from '../../../../store/simulation/useProductStore'; +import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; +import { useSelectedAsset } from '../../../../store/simulation/useSimulationStore'; + +function TriggerConnector() { + const { gl, raycaster, scene } = useThree(); + const { subModule } = useSubModuleStore(); + const { setTop } = useTopData(); + const { setLeft } = useLeftData(); + const { getIsEventInProduct } = useProductStore(); + const { getEventByModelUuid } = useEventsStore(); + const { selectedProduct } = useSelectedProduct(); + const { selectedAsset, setSelectedAsset, clearSelectedAsset } = useSelectedAsset(); + + useEffect(() => { + + const canvasElement = gl.domElement; + + let drag = false; + let isRightMouseDown = false; + + const onMouseDown = (evt: MouseEvent) => { + if (selectedAsset) { + clearSelectedAsset(); + } + if (evt.button === 2) { + isRightMouseDown = true; + drag = false; + } + }; + + const onMouseUp = (evt: MouseEvent) => { + if (evt.button === 2) { + isRightMouseDown = false; + } + } + + const onMouseMove = () => { + if (isRightMouseDown) { + drag = true; + } + }; + + const handleRightClick = (evt: MouseEvent) => { + if (drag) return; + evt.preventDefault(); + const canvasElement = gl.domElement; + if (!canvasElement) return; + + let intersects = raycaster.intersectObjects(scene.children, true); + 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; + + while (currentObject) { + if (currentObject.name === "Scene") { + break; + } + currentObject = currentObject.parent as Object3D; + } + if (currentObject) { + const isInProduct = getIsEventInProduct(selectedProduct.productId, currentObject.uuid); + + if (isInProduct) { + const event = getEventByModelUuid(currentObject.uuid); + if (event) { + setSelectedAsset(event) + const canvasRect = canvasElement.getBoundingClientRect(); + const relativeX = evt.clientX - canvasRect.left; + const relativeY = evt.clientY - canvasRect.top; + + setTop(relativeY); + setLeft(relativeX); + } else { + clearSelectedAsset() + } + } else { + const event = getEventByModelUuid(currentObject.uuid); + if (event) { + setSelectedAsset(event) + const canvasRect = canvasElement.getBoundingClientRect(); + const relativeX = evt.clientX - canvasRect.left; + const relativeY = evt.clientY - canvasRect.top; + + setTop(relativeY); + setLeft(relativeX); + } else { + clearSelectedAsset() + } + } + + } + } else { + clearSelectedAsset() + } + + }; + + if (subModule === 'simulations') { + canvasElement.addEventListener("mousedown", onMouseDown); + canvasElement.addEventListener("mouseup", onMouseUp); + canvasElement.addEventListener("mousemove", onMouseMove); + canvasElement.addEventListener('contextmenu', handleRightClick); + } + + return () => { + canvasElement.removeEventListener("mousedown", onMouseDown); + canvasElement.removeEventListener("mouseup", onMouseUp); + canvasElement.removeEventListener("mousemove", onMouseMove); + canvasElement.removeEventListener('contextmenu', handleRightClick); + }; + + }, [gl, subModule, selectedProduct, selectedAsset]); + + return ( + <> + + ) +} + +export default TriggerConnector \ No newline at end of file diff --git a/app/src/modules/simulation/triggers/temp.md b/app/src/modules/simulation/triggers/temp.md deleted file mode 100644 index e69de29..0000000 diff --git a/app/src/modules/simulation/triggers/trigger.tsx b/app/src/modules/simulation/triggers/trigger.tsx new file mode 100644 index 0000000..110da2e --- /dev/null +++ b/app/src/modules/simulation/triggers/trigger.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import TriggerConnector from './connector/triggerConnector' + +function Trigger() { + return ( + <> + + + + + ) +} + +export default Trigger \ No newline at end of file diff --git a/app/src/modules/visualization/RealTimeVisulization.tsx b/app/src/modules/visualization/RealTimeVisulization.tsx index cd2c57c..30f0014 100644 --- a/app/src/modules/visualization/RealTimeVisulization.tsx +++ b/app/src/modules/visualization/RealTimeVisulization.tsx @@ -125,7 +125,7 @@ const RealTimeVisulization: React.FC = () => { {} ); setZonesData(formattedData); - } catch (error) {} + } catch (error) { } } GetZoneData(); @@ -362,6 +362,10 @@ const RealTimeVisulization: React.FC = () => { "RotateY", "Delete", ]} + onClick={(e) => { + setRightSelect(e); + setEditWidgetOptions(false); + }} /> )} diff --git a/app/src/services/visulization/zone/getSelect2dZoneData.ts b/app/src/services/visulization/zone/getSelect2dZoneData.ts index b2c39e9..00d4dfe 100644 --- a/app/src/services/visulization/zone/getSelect2dZoneData.ts +++ b/app/src/services/visulization/zone/getSelect2dZoneData.ts @@ -7,7 +7,7 @@ export const getSelect2dZoneData = async ( ) => { try { const response = await fetch( - `${url_Backend_dwinzo}/api/v2/Zone/visualization/${ZoneId}?organization=${organization}`, + `${url_Backend_dwinzo}/api/v2/ZoneVisualization/${ZoneId}?organization=${organization}`, { method: "GET", headers: { diff --git a/app/src/store/simulation/useProductStore.ts b/app/src/store/simulation/useProductStore.ts index 81feb7f..91576c7 100644 --- a/app/src/store/simulation/useProductStore.ts +++ b/app/src/store/simulation/useProductStore.ts @@ -55,6 +55,11 @@ type ProductsStore = { // Helper functions getProductById: (productId: string) => { productName: string; productId: string; eventsData: EventsSchema[] } | undefined; + getEventByModelUuid: (productId: string, modelUuid: string) => EventsSchema | undefined; + getPointByUuid: (productId: string, modelUuid: string, pointUuid: string) => ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | undefined; + getActionByUuid: (productId: string, actionUuid: string) => (ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']) | undefined; + getTriggerByUuid: (productId: string, triggerUuid: string) => TriggerSchema | undefined; + getIsEventInProduct: (productId: string, modelUuid: string) => boolean; }; export const useProductStore = create()( @@ -417,6 +422,89 @@ export const useProductStore = create()( // Helper functions getProductById: (productId) => { return get().products.find(p => p.productId === productId); + }, + + getEventByModelUuid: (productId, modelUuid) => { + const product = get().getProductById(productId); + if (!product) return undefined; + return product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); + }, + + getPointByUuid: (productId, modelUuid, pointUuid) => { + const event = get().getEventByModelUuid(productId, modelUuid); + if (!event) return undefined; + + if ('points' in event) { + return (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid); + } else if ('point' in event && (event as any).point.uuid === pointUuid) { + return (event as VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema).point; + } + return undefined; + }, + + getActionByUuid: (productId, actionUuid) => { + const product = get().products.find(p => p.productId === productId); + if (!product) return undefined; + + for (const event of product.eventsData) { + if ('points' in event) { + for (const point of (event as ConveyorEventSchema).points) { + if (point.action?.actionUuid === actionUuid) { + return point.action; + } + } + } else if ('point' in event) { + const point = (event as any).point; + if ('action' in point && point.action?.actionUuid === actionUuid) { + return point.action; + } else if ('actions' in point) { + const action = point.actions.find((a: any) => a.actionUuid === actionUuid); + if (action) return action; + } + } + } + return undefined; + }, + + getTriggerByUuid: (productId, triggerUuid) => { + const product = get().products.find(p => p.productId === productId); + if (!product) return undefined; + + for (const event of product.eventsData) { + if ('points' in event) { + for (const point of (event as ConveyorEventSchema).points) { + for (const trigger of point.action?.triggers || []) { + if (trigger.triggerUuid === triggerUuid) { + return trigger; + } + } + } + } else if ('point' in event) { + const point = (event as any).point; + if ('action' in point) { + for (const trigger of point.action?.triggers || []) { + if (trigger.triggerUuid === triggerUuid) { + return trigger; + } + } + } else if ('actions' in point) { + for (const action of point.actions) { + for (const trigger of action.triggers || []) { + if (trigger.triggerUuid === triggerUuid) { + return trigger; + } + } + } + } + } + } + return undefined; + }, + + getIsEventInProduct: (productId, modelUuid) => { + const product = get().getProductById(productId); + if (!product) return false; + return product.eventsData.some(e => 'modelUuid' in e && e.modelUuid === modelUuid); } })) ); diff --git a/app/src/store/simulation/useSimulationStore.ts b/app/src/store/simulation/useSimulationStore.ts index 9c0fc00..ae6ac81 100644 --- a/app/src/store/simulation/useSimulationStore.ts +++ b/app/src/store/simulation/useSimulationStore.ts @@ -24,6 +24,50 @@ export const useSelectedEventSphere = create()( })) ); +interface SelectedEventDataState { + selectedEventData: { data: EventsSchema; selectedPoint: string } | undefined; + setSelectedEventData: (data: EventsSchema, selectedPoint: string) => void; + clearSelectedEventData: () => void; +} + +export const useSelectedEventData = create()( + immer((set) => ({ + selectedEventData: undefined, + setSelectedEventData: (data, selectedPoint) => { + set((state) => { + state.selectedEventData = { data, selectedPoint }; + }); + }, + clearSelectedEventData: () => { + set((state) => { + state.selectedEventData = undefined; + }); + }, + })) +); + +interface SelectedAssetState { + selectedAsset: EventsSchema | undefined; + setSelectedAsset: (EventData: EventsSchema) => void; + clearSelectedAsset: () => void; +} + +export const useSelectedAsset = create()( + immer((set) => ({ + selectedAsset: undefined, + setSelectedAsset: (EventData) => { + set((state) => { + state.selectedAsset = EventData; + }); + }, + clearSelectedAsset: () => { + set((state) => { + state.selectedAsset = undefined; + }); + }, + })) +); + interface SelectedProductState { selectedProduct: { productId: string; productName: string }; setSelectedProduct: (productId: string, productName: string) => void; diff --git a/app/src/store/useModuleStore.ts b/app/src/store/useModuleStore.ts index 1012792..3cc1d00 100644 --- a/app/src/store/useModuleStore.ts +++ b/app/src/store/useModuleStore.ts @@ -13,14 +13,17 @@ const useModuleStore = create((set) => ({ export default useModuleStore; // New store for subModule + +type SubModule = 'properties' | 'simulations' | 'mechanics' | 'analysis' | 'zoneProperties'; + interface SubModuleStore { - subModule: string; - setSubModule: (subModule: string) => void; + subModule: SubModule; + setSubModule: (subModule: SubModule) => void; } const useSubModuleStore = create((set) => ({ subModule: "properties", // Initial subModule state - setSubModule: (subModule) => set({ subModule }), // Update subModule state + setSubModule: (value) => set({ subModule: value }), // Update subModule state })); export { useSubModuleStore }; diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index 1b99456..12c0dc2 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -25,7 +25,7 @@ interface ConveyorPointSchema { action: { actionUuid: string; actionName: string; - actionType: "default" | "spawn" | "swap" | "despawn"; + actionType: "default" | "spawn" | "swap" | "delay" | "despawn"; material: string; delay: number | "inherit"; spawnInterval: number | "inherit"; @@ -119,6 +119,8 @@ interface StorageEventSchema extends AssetEventSchema { point: StoragePointSchema; } +type PointsScheme = ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema; + type EventsSchema = ConveyorEventSchema | VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema; type productsSchema = { From c5d4679068287e3d605a4d5e3887e7ee839a61ef Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Thu, 24 Apr 2025 17:51:52 +0530 Subject: [PATCH 17/22] fix --- app/src/modules/simulation/roboticArm/roboticArm.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/modules/simulation/roboticArm/roboticArm.tsx b/app/src/modules/simulation/roboticArm/roboticArm.tsx index 7899f56..4295ac7 100644 --- a/app/src/modules/simulation/roboticArm/roboticArm.tsx +++ b/app/src/modules/simulation/roboticArm/roboticArm.tsx @@ -1,7 +1,5 @@ -import React, { useEffect } from "react"; +import { useEffect } from "react"; import RoboticArmInstances from "./instances/roboticArmInstances"; -import IkInstances from "./instances/ikInstances"; -import { log } from "node:console"; import { useArmBotStore } from "../../../store/simulation/useArmBotStore"; function RoboticArm() { @@ -85,7 +83,7 @@ function RoboticArm() { addArmBot('123', armBotStatusSample[0]); // addCurrentAction('armbot-xyz-001', 'action-001'); }, []); - + useEffect(() => { console.log('armBots: ', armBots); From 4310b473d0065251848538956477c7a104bab12e Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Thu, 24 Apr 2025 19:15:36 +0530 Subject: [PATCH 18/22] feat: Enhance EventProperties and mechanics components with new state management and action handling; add DelayAction component and remove unused IkInstances --- .../layout/sidebarRight/SideBarRight.tsx | 2 +- .../eventProperties/EventProperties.tsx | 272 ++++++++++-------- .../eventProperties/actions/DelayAction.tsx | 22 ++ .../eventProperties/actions/DespawnAction.tsx | 11 - .../mechanics/conveyorMechanics.tsx | 78 ++++- .../mechanics/roboticArmMechanics.tsx | 164 ++++++++++- .../mechanics/vehicleMechanics.tsx | 70 ++++- .../roboticArm/instances/ikInstances.tsx | 14 - 8 files changed, 481 insertions(+), 152 deletions(-) create mode 100644 app/src/components/layout/sidebarRight/properties/eventProperties/actions/DelayAction.tsx delete mode 100644 app/src/modules/simulation/roboticArm/instances/ikInstances.tsx diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx index f5668bf..5c37dec 100644 --- a/app/src/components/layout/sidebarRight/SideBarRight.tsx +++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx @@ -123,7 +123,7 @@ const SideBarRight: React.FC = () => {
)} - {subModule === "mechanics" && selectedEventData && selectedEventSphere && ( + {subModule === "mechanics" && (
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx index 6c44947..887aaaa 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx @@ -22,6 +22,9 @@ import Trigger from "./trigger/Trigger"; import { useSelectedEventData, useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; +import ConveyorMechanics from "./mechanics/conveyorMechanics"; +import VehicleMechanics from "./mechanics/vehicleMechanics"; +import RoboticArmMechanics from "./mechanics/roboticArmMechanics"; const EventProperties: React.FC = () => { const actionsContainerRef = useRef(null); @@ -32,21 +35,43 @@ const EventProperties: React.FC = () => { const { getEventByModelUuid } = useProductStore(); const { selectedProduct } = useSelectedProduct(); + // State for derived values + const [currentEventData, setCurrentEventData] = useState(null); + const [assetType, setAssetType] = useState(null); + const [availableActions, setAvailableActions] = useState({ + defaultOption: "default", + options: ["default"] + }); + const [actions, setActions] = useState<{ uuid: string; name: string }[]>([]); + const [speed, setSpeed] = useState("0.5"); + useEffect(() => { - const actions = getActions(); - if (actions.length > 0 && !selectedItem.item) { - setSelectedItem({ item: actions[0] }); + const event = getCurrentEventData(); + setCurrentEventData(event); + + const type = determineAssetType(event); + setAssetType(type); + + const actionsConfig = determineAvailableActions(type); + setAvailableActions(actionsConfig); + + const actionList = getActionList(event, type); + setActions(actionList); + + if (actionList.length > 0 && !selectedItem.item) { + setSelectedItem({ item: actionList[0] }); } - }, [selectedEventData]); + + const currentSpeed = getCurrentSpeed(); + setSpeed(currentSpeed); + }, [selectedEventData, selectedProduct]); const getCurrentEventData = () => { if (!selectedEventData?.data || !selectedProduct) return null; - const event = getEventByModelUuid(selectedProduct.productId, selectedEventData.data.modelUuid); - return event || null; + return getEventByModelUuid(selectedProduct.productId, selectedEventData.data.modelUuid) || null; }; - const getAssetType = () => { - const event = getCurrentEventData(); + const determineAssetType = (event: EventsSchema | null) => { if (!event) return null; switch (event.type) { @@ -59,8 +84,8 @@ const EventProperties: React.FC = () => { } }; - const getAvailableActions = () => { - switch (getAssetType()) { + const determineAvailableActions = (type: string | null) => { + switch (type) { case "conveyor": return { defaultOption: "default", @@ -94,12 +119,10 @@ const EventProperties: React.FC = () => { } }; - // Get actions based on asset type - const getActions = () => { + const getActionList = (event: EventsSchema | null, type: string | null) => { if (!selectedEventData?.data) return []; - const event = selectedEventData.data; - switch (getAssetType()) { + switch (type) { case "conveyor": return (event as ConveyorEventSchema).points .find((point) => point.uuid === selectedEventData?.selectedPoint) @@ -141,8 +164,13 @@ const EventProperties: React.FC = () => { } }; + const getCurrentSpeed = () => { + if (!selectedEventData) return "0.5"; + if ("speed" in selectedEventData.data) return selectedEventData.data.speed.toString(); + return "0.5"; + }; + const handleActionToggle = (actionUuid: string) => { - const actions = getActions(); const selected = actions.find(action => action.uuid === actionUuid); if (selected) { setSelectedItem({ item: selected }); @@ -150,130 +178,128 @@ const EventProperties: React.FC = () => { }; const handleDeleteAction = (actionUuid: string) => { - - }; - - const actions = getActions(); - - const getSpeed = () => { - if (!selectedEventData) return "0.5"; - if ("speed" in selectedEventData.data) return selectedEventData.data.speed.toString(); - return "0.5"; + // Implementation for delete action }; return ( <> - {getCurrentEventData() && -
-
-
{selectedEventData?.data.modelName}
-
-
-
-
- { }} - onChange={(value) => console.log(value)} - /> -
+
+ {currentEventData && + <> +
+
{selectedEventData?.data.modelName}
+
+
+
+
+ { }} + onChange={(value) => console.log(value)} + /> +
-
- { }} - onChange={(value) => console.log(value)} - /> +
+ { }} + onChange={(value) => console.log(value)} + /> +
-
- {getAssetType() === 'roboticArm' && -
-
-
-
Actions
-
{ }}> - Add -
-
-
-
- {actions.map((action) => ( -
-
handleActionToggle(action.uuid)} - > - -
- {actions.length > 1 && ( -
handleDeleteAction(action.uuid)} - > - -
- )} -
- ))} + {assetType === 'roboticArm' && +
+
+
+
Actions
+
{ }}> + Add +
handleResize(e, actionsContainerRef)} + className="lists-main-container" + ref={actionsContainerRef} + style={{ height: "120px" }} > - +
+ {actions.map((action) => ( +
+
handleActionToggle(action.uuid)} + > + +
+ {actions.length > 1 && ( +
handleDeleteAction(action.uuid)} + > + +
+ )} +
+ ))} +
+
handleResize(e, actionsContainerRef)} + > + +
+ } +
+
+ +
+
+ setActiveOption(option)} + /> + {activeOption === "default" && } + {activeOption === "spawn" && } + {activeOption === "swap" && } + {activeOption === "despawn" && } + {activeOption === "travel" && } + {activeOption === "pickAndPlace" && } + {activeOption === "process" && } + {activeOption === "store" && } +
- } -
-
- +
+
-
- setActiveOption(option)} - /> - {activeOption === "default" && } - {activeOption === "spawn" && } - {activeOption === "swap" && } - {activeOption === "despawn" && } - {activeOption === "travel" && } - {activeOption === "pickAndPlace" && } - {activeOption === "process" && } - {activeOption === "store" && } -
-
-
- -
-
- } + + {/* {assetType === 'conveyor' && } + {assetType === 'vehicle' && } + {assetType === 'roboticArm' && } */} + + } +
); }; -export default EventProperties; +export default EventProperties; \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DelayAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DelayAction.tsx new file mode 100644 index 0000000..e4bceb9 --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DelayAction.tsx @@ -0,0 +1,22 @@ +import React from "react"; +import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; + +const DelayAction: React.FC = () => { + return ( + <> + { }} + onChange={(value) => console.log(value)} + /> + + ); +}; + +export default DelayAction; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DespawnAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DespawnAction.tsx index a0f081f..0d54476 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DespawnAction.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DespawnAction.tsx @@ -4,17 +4,6 @@ import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; const DespawnAction: React.FC = () => { return ( <> - {}} - onChange={(value) => console.log(value)} - /> ); }; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx index 000a9d7..4f3122b 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx @@ -1,8 +1,84 @@ -import React from 'react' +import { useEffect, useState } from 'react' +import InputWithDropDown from '../../../../../ui/inputs/InputWithDropDown' +import DelayAction from '../actions/DelayAction' +import RenameInput from '../../../../../ui/inputs/RenameInput' +import LabledDropdown from '../../../../../ui/inputs/LabledDropdown' +import DespawnAction from '../actions/DespawnAction' +import SwapAction from '../actions/SwapAction' +import SpawnAction from '../actions/SpawnAction' +import DefaultAction from '../actions/DefaultAction' +import Trigger from '../trigger/Trigger' +import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; +import { useProductStore } from "../../../../../../store/simulation/useProductStore"; function ConveyorMechanics() { + const [activeOption, setActiveOption] = useState("default"); + const [selectedPointData, setSelectedPointData] = useState(); + const { selectedEventData } = useSelectedEventData(); + const { getPointByUuid } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); + + useEffect(() => { + if (selectedEventData) { + const point = getPointByUuid(selectedProduct.productId, selectedEventData?.data.modelUuid, selectedEventData?.selectedPoint); + if (point && 'action' in point) { + setSelectedPointData(point as PointsScheme & { action: { actionType: string } }); + setActiveOption((point as PointsScheme & { action: { actionType: string } }).action.actionType); + } + } + }, [selectedProduct, selectedEventData]) + + const availableActions = { + defaultOption: "default", + options: ["default", "spawn", "swap", "delay", "despawn"], + }; + return ( <> + {selectedEventData && + <> +
+
+
+ { }} + onChange={(value) => console.log(value)} + /> +
+
+
+ +
+
+ +
+
+ setActiveOption(option)} + /> + {activeOption === "default" && } + {activeOption === "spawn" && } + {activeOption === "swap" && } + {activeOption === "despawn" && } + {activeOption === "delay" && } +
+
+
+ +
+ + } ) } diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx index 56e4c27..9a044ac 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx @@ -1,8 +1,170 @@ -import React from 'react' +import { useEffect, useRef, useState } from 'react' +import * as THREE from 'three'; +import InputWithDropDown from '../../../../../ui/inputs/InputWithDropDown' +import RenameInput from '../../../../../ui/inputs/RenameInput' +import LabledDropdown from '../../../../../ui/inputs/LabledDropdown' +import Trigger from '../trigger/Trigger' +import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; +import { useProductStore } from "../../../../../../store/simulation/useProductStore"; +import { AddIcon, RemoveIcon, ResizeHeightIcon } from '../../../../../icons/ExportCommonIcons' +import { handleResize } from '../../../../../../functions/handleResizePannel' +import PickAndPlaceAction from '../actions/PickAndPlaceAction' function RoboticArmMechanics() { + const actionsContainerRef = useRef(null); + + const [activeOption, setActiveOption] = useState("pickAndPlace"); + const [selectedItem, setSelectedItem] = useState<{ item: { uuid: string; name: string } | null; }>({ item: null }); + const { selectedEventData } = useSelectedEventData(); + const { getEventByModelUuid, addAction } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); + + const availableActions = { + defaultOption: "pickAndPlace", + options: ["pickAndPlace"] + }; + const [actions, setActions] = useState<{ uuid: string; name: string }[]>([]); + + useEffect(() => { + const event = getCurrentEventData(); + const actionList = getActionList(event as RoboticArmEventSchema); + setActions(actionList); + + if (actionList.length > 0 && !selectedItem.item) { + setSelectedItem({ item: actionList[0] }); + } + }, [selectedEventData, selectedProduct]); + + const getCurrentEventData = () => { + if (!selectedEventData?.data || !selectedProduct) return null; + return getEventByModelUuid(selectedProduct.productId, selectedEventData.data.modelUuid) || null; + }; + + const getActionList = (event: RoboticArmEventSchema) => { + if (!event || !('point' in event)) return []; + + return event.point.actions.flatMap( + (action) => + action.triggers.map((trigger) => ({ + uuid: trigger.triggerUuid, + name: trigger.triggerName, + })) + ) || []; + }; + + const handleActionToggle = (actionUuid: string) => { + const action = actions.find(a => a.uuid === actionUuid); + if (action) { + setSelectedItem({ item: action }); + } + }; + + const handleAddAction = () => { + if (selectedEventData) { + const newEvent = { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: `Action ${actions.length + 1}`, + actionType: "pickAndPlace" as const, + process: { + startPoint: null as [number, number, number] | null, + endPoint: null as [number, number, number] | null + }, + triggers: [] as TriggerSchema[] + } + addAction( + selectedProduct.productId, + selectedEventData?.data.modelUuid, + selectedEventData?.selectedPoint, + newEvent + ) + } + }; + + const handleDeleteAction = (actionUuid: string) => { + + }; + return ( <> +
+
+
+ { }} + onChange={(value) => console.log(value)} + /> +
+
+
+
+
+
+
Actions
+
handleAddAction()}> + Add +
+
+
+
+ {actions.map((action) => ( +
+
handleActionToggle(action.uuid)} + > + +
+ {actions.length > 1 && ( +
handleDeleteAction(action.uuid)} + > + +
+ )} +
+ ))} +
+
handleResize(e, actionsContainerRef)} + > + +
+
+
+
+
+
+ +
+
+ setActiveOption(option)} + /> + {activeOption === "pickAndPlace" && } +
+
+
+ +
) } diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx index cdb32c4..b689734 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx @@ -1,8 +1,76 @@ -import React from 'react' +import { useEffect, useState } from 'react' +import InputWithDropDown from '../../../../../ui/inputs/InputWithDropDown' +import RenameInput from '../../../../../ui/inputs/RenameInput' +import LabledDropdown from '../../../../../ui/inputs/LabledDropdown' +import Trigger from '../trigger/Trigger' +import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; +import { useProductStore } from "../../../../../../store/simulation/useProductStore"; +import TravelAction from '../actions/TravelAction' function VehicleMechanics() { + const [activeOption, setActiveOption] = useState("default"); + const [selectedPointData, setSelectedPointData] = useState(); + const { selectedEventData } = useSelectedEventData(); + const { getPointByUuid } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); + + useEffect(() => { + if (selectedEventData) { + const point = getPointByUuid(selectedProduct.productId, selectedEventData?.data.modelUuid, selectedEventData?.selectedPoint); + if (point && 'action' in point) { + setSelectedPointData(point as PointsScheme & { action: { actionType: string } }); + setActiveOption((point as PointsScheme & { action: { actionType: string } }).action.actionType); + } + } + }, [selectedProduct, selectedEventData]) + + const availableActions = { + defaultOption: "travel", + options: ["travel"], + }; + return ( <> + {selectedEventData && + <> +
+
+
+ { }} + onChange={(value) => console.log(value)} + /> +
+
+
+ +
+
+ +
+
+ setActiveOption(option)} + /> + {activeOption === "travel" && } +
+
+
+ +
+ + } ) } diff --git a/app/src/modules/simulation/roboticArm/instances/ikInstances.tsx b/app/src/modules/simulation/roboticArm/instances/ikInstances.tsx deleted file mode 100644 index d44ddd2..0000000 --- a/app/src/modules/simulation/roboticArm/instances/ikInstances.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react' -import IKInstance from './ikInstance/ikInstance'; - -function IkInstances() { - return ( - <> - - - - - ) -} - -export default IkInstances; \ No newline at end of file From bfcb67c3c8ea9e7fa0877bdffe9a1b05a00d2437 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Fri, 25 Apr 2025 11:19:40 +0530 Subject: [PATCH 19/22] feat: Enhance EventProperties and mechanics components with new mechanics; refactor action handling and improve state management for various actions --- .../eventProperties/EventProperties.tsx | 122 +------------ .../eventProperties/actions/DelayAction.tsx | 20 ++- .../eventProperties/actions/ProcessAction.tsx | 58 +++++-- .../eventProperties/actions/SpawnAction.tsx | 93 +++++++--- .../eventProperties/actions/SwapAction.tsx | 27 ++- .../eventProperties/actions/TravelAction.tsx | 100 +++++++---- .../mechanics/conveyorMechanics.tsx | 162 ++++++++++++++++-- .../mechanics/machineMechanics.tsx | 116 ++++++++++++- .../mechanics/storageMechanics.tsx | 51 +++++- .../mechanics/vehicleMechanics.tsx | 151 ++++++++++++++-- .../ui/inputs/PreviewSelectionWithUpload.tsx | 6 - .../IntialLoad/loadInitialFloorItems.ts | 2 +- 12 files changed, 663 insertions(+), 245 deletions(-) diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx index 887aaaa..21781f0 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx @@ -25,6 +25,8 @@ import { useProductStore } from "../../../../../store/simulation/useProductStore import ConveyorMechanics from "./mechanics/conveyorMechanics"; import VehicleMechanics from "./mechanics/vehicleMechanics"; import RoboticArmMechanics from "./mechanics/roboticArmMechanics"; +import MachineMechanics from "./mechanics/machineMechanics"; +import StorageMechanics from "./mechanics/storageMechanics"; const EventProperties: React.FC = () => { const actionsContainerRef = useRef(null); @@ -170,17 +172,6 @@ const EventProperties: React.FC = () => { return "0.5"; }; - const handleActionToggle = (actionUuid: string) => { - const selected = actions.find(action => action.uuid === actionUuid); - if (selected) { - setSelectedItem({ item: selected }); - } - }; - - const handleDeleteAction = (actionUuid: string) => { - // Implementation for delete action - }; - return ( <>
@@ -189,112 +180,11 @@ const EventProperties: React.FC = () => {
{selectedEventData?.data.modelName}
-
-
-
- { }} - onChange={(value) => console.log(value)} - /> -
- -
- { }} - onChange={(value) => console.log(value)} - /> -
-
-
- {assetType === 'roboticArm' && -
-
-
-
Actions
-
{ }}> - Add -
-
-
-
- {actions.map((action) => ( -
-
handleActionToggle(action.uuid)} - > - -
- {actions.length > 1 && ( -
handleDeleteAction(action.uuid)} - > - -
- )} -
- ))} -
-
handleResize(e, actionsContainerRef)} - > - -
-
-
-
- } -
-
- -
-
- setActiveOption(option)} - /> - {activeOption === "default" && } - {activeOption === "spawn" && } - {activeOption === "swap" && } - {activeOption === "despawn" && } - {activeOption === "travel" && } - {activeOption === "pickAndPlace" && } - {activeOption === "process" && } - {activeOption === "store" && } -
-
-
- -
- - {/* {assetType === 'conveyor' && } + {assetType === 'conveyor' && } {assetType === 'vehicle' && } - {assetType === 'roboticArm' && } */} + {assetType === 'roboticArm' && } + {assetType === 'machine' && } + {assetType === 'storageUnit' && } }
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DelayAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DelayAction.tsx index e4bceb9..2bb63d4 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DelayAction.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DelayAction.tsx @@ -1,19 +1,27 @@ import React from "react"; import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; -const DelayAction: React.FC = () => { +interface DelayActionProps { + value: string; + defaultValue: string; + min: number; + max: number; + onChange: (value: string) => void; +} + +const DelayAction: React.FC = ({ value, defaultValue, min, max, onChange }) => { return ( <> { }} - onChange={(value) => console.log(value)} + onChange={onChange} /> ); diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/ProcessAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/ProcessAction.tsx index a27894e..331cf1b 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/ProcessAction.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/ProcessAction.tsx @@ -2,23 +2,47 @@ import React from "react"; import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; import SwapAction from "./SwapAction"; -const ProcessAction: React.FC = () => { - return ( - <> - {}} - onChange={(value) => console.log(value)} - /> - - - ); +interface ProcessActionProps { + value: string; + min: number; + max: number; + defaultValue: string; + onChange: (value: string) => void; + swapOptions: string[]; + swapDefaultOption: string; + onSwapSelect: (value: string) => void; +} + +const ProcessAction: React.FC = ({ + value, + min, + max, + defaultValue, + onChange, + swapOptions, + swapDefaultOption, + onSwapSelect, +}) => { + return ( + <> + { }} + onChange={onChange} + /> + + + ); }; export default ProcessAction; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SpawnAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SpawnAction.tsx index 0c37cdb..7d8002e 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SpawnAction.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SpawnAction.tsx @@ -1,35 +1,72 @@ import React from "react"; import PreviewSelectionWithUpload from "../../../../../ui/inputs/PreviewSelectionWithUpload"; import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; +import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; -const SpawnAction: React.FC = () => { - return ( - <> - {}} - onChange={(value) => console.log(value)} - /> - {}} - onChange={(value) => console.log(value)} - /> - - - ); +interface SpawnActionProps { + onChangeInterval: (value: string) => void; + onChangeCount: (value: string) => void; + defaultOption: string; + options: string[]; + onSelect: (option: string) => void; + intervalValue: string; + countValue: string; + intervalMin: number; + intervalMax: number; + intervalDefaultValue: string; + countMin: number; + countMax: number; + countDefaultValue: string; +} + +const SpawnAction: React.FC = ({ + onChangeInterval, + onChangeCount, + defaultOption, + options, + onSelect, + intervalValue, + countValue, + intervalMin, + intervalMax, + intervalDefaultValue, + countMin, + countMax, + countDefaultValue, +}) => { + return ( + <> + { }} + onChange={onChangeInterval} + /> + { }} + onChange={onChangeCount} + /> + {/* */} + + + ); }; export default SpawnAction; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SwapAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SwapAction.tsx index 2e18d80..23b203f 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SwapAction.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SwapAction.tsx @@ -1,12 +1,27 @@ import React from "react"; import PreviewSelectionWithUpload from "../../../../../ui/inputs/PreviewSelectionWithUpload"; +import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; -const SwapAction: React.FC = () => { - return ( - <> - - - ); +interface SwapActionProps { + onSelect: (option: string) => void; + defaultOption: string; + options: string[]; +} + +const SwapAction: React.FC = ({ onSelect, defaultOption, options }) => { + + return ( + <> + {/* */} + + + + ); }; export default SwapAction; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/TravelAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/TravelAction.tsx index ee4bda0..49eb683 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/TravelAction.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/TravelAction.tsx @@ -2,35 +2,77 @@ import React from "react"; import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; import EyeDropInput from "../../../../../ui/inputs/EyeDropInput"; -const TravelAction: React.FC = () => { - return ( - <> - {}} - onChange={(value) => console.log(value)} - /> - {}} - onChange={(value) => console.log(value)} - /> - {}} /> - {}} /> - - ); +interface TravelActionProps { + loadCapacity: { + value: string; + min: number; + max: number; + defaultValue: string; + onChange: (value: string) => void; + }; + unloadDuration: { + value: string; + min: number; + max: number; + defaultValue: string; + onChange: (value: string) => void; + }; + pickPoint?: { + value: string; + onChange: (value: string) => void; + }; + unloadPoint?: { + value: string; + onChange: (value: string) => void; + }; +} + +const TravelAction: React.FC = ({ + loadCapacity, + unloadDuration, + pickPoint, + unloadPoint, +}) => { + return ( + <> + { }} + onChange={loadCapacity.onChange} + /> + { }} + onChange={unloadDuration.onChange} + /> + {pickPoint && ( + + )} + {unloadPoint && ( + + )} + + ); }; export default TravelAction; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx index 4f3122b..c13bd75 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx @@ -12,27 +12,116 @@ import { useSelectedEventData, useSelectedProduct } from "../../../../../../stor import { useProductStore } from "../../../../../../store/simulation/useProductStore"; function ConveyorMechanics() { - const [activeOption, setActiveOption] = useState("default"); - const [selectedPointData, setSelectedPointData] = useState(); + const [activeOption, setActiveOption] = useState<"default" | "spawn" | "swap" | "delay" | "despawn">("default"); + const [selectedPointData, setSelectedPointData] = useState(); const { selectedEventData } = useSelectedEventData(); - const { getPointByUuid } = useProductStore(); + const { getPointByUuid, updateEvent, updateAction } = useProductStore(); const { selectedProduct } = useSelectedProduct(); useEffect(() => { if (selectedEventData) { - const point = getPointByUuid(selectedProduct.productId, selectedEventData?.data.modelUuid, selectedEventData?.selectedPoint); + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData?.data.modelUuid, + selectedEventData?.selectedPoint + ) as ConveyorPointSchema | undefined; if (point && 'action' in point) { - setSelectedPointData(point as PointsScheme & { action: { actionType: string } }); - setActiveOption((point as PointsScheme & { action: { actionType: string } }).action.actionType); + setSelectedPointData(point); + setActiveOption(point.action.actionType as "default" | "spawn" | "swap" | "delay" | "despawn"); } } }, [selectedProduct, selectedEventData]) + const handleSpeedChange = (value: string) => { + if (!selectedEventData) return; + updateEvent( + selectedProduct.productId, + selectedEventData.data.modelUuid, + { speed: parseFloat(value) } + ); + }; + + const handleActionTypeChange = (option: string) => { + if (!selectedEventData || !selectedPointData) return; + const validOption = option as "default" | "spawn" | "swap" | "delay" | "despawn"; + setActiveOption(validOption); + + updateAction( + selectedPointData.action.actionUuid, + { actionType: validOption } + ); + }; + + const handleRenameAction = (newName: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { actionName: newName } + ); + }; + + const handleSpawnCountChange = (value: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { spawnCount: value === "inherit" ? "inherit" : parseFloat(value) } + ); + }; + + const handleSpawnIntervalChange = (value: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { spawnInterval: value === "inherit" ? "inherit" : parseFloat(value) } + ); + }; + + const handleMaterialSelect = (material: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { material } + ); + }; + + const handleDelayChange = (value: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { delay: value === "inherit" ? "inherit" : parseFloat(value) } + ); + }; + const availableActions = { defaultOption: "default", options: ["default", "spawn", "swap", "delay", "despawn"], }; + // Get current values from store + const currentSpeed = selectedEventData?.data.type === "transfer" + ? selectedEventData.data.speed.toString() + : "0.5"; + + const currentActionName = selectedPointData + ? selectedPointData.action.actionName + : "Action Name"; + + const currentMaterial = selectedPointData + ? selectedPointData.action.material + : "Default material"; + + const currentSpawnCount = selectedPointData + ? selectedPointData.action.spawnCount?.toString() || "1" + : "1"; + + const currentSpawnInterval = selectedPointData + ? selectedPointData.action.spawnInterval?.toString() || "1" + : "1"; + + const currentDelay = selectedPointData + ? selectedPointData.action.delay?.toString() || "0" + : "0"; + return ( <> {selectedEventData && @@ -42,14 +131,14 @@ function ConveyorMechanics() {
{ }} - onChange={(value) => console.log(value)} + onChange={handleSpeedChange} />
@@ -57,21 +146,58 @@ function ConveyorMechanics() {
- +
setActiveOption(option)} + onSelect={handleActionTypeChange} /> - {activeOption === "default" && } - {activeOption === "spawn" && } - {activeOption === "swap" && } - {activeOption === "despawn" && } - {activeOption === "delay" && } + {activeOption === "default" && + + } + {activeOption === "spawn" && + + } + {activeOption === "swap" && + + } + {activeOption === "despawn" && + + } + {activeOption === "delay" && + + }
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx index b6e4fb9..138ed7c 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx @@ -1,8 +1,122 @@ -import React from 'react' +import { useEffect, useState } from 'react' +import RenameInput from '../../../../../ui/inputs/RenameInput' +import LabledDropdown from '../../../../../ui/inputs/LabledDropdown' +import Trigger from '../trigger/Trigger' +import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; +import { useProductStore } from "../../../../../../store/simulation/useProductStore"; +import ProcessAction from '../actions/ProcessAction' function MachineMechanics() { + const [activeOption, setActiveOption] = useState<"default" | "process">("default"); + const [selectedPointData, setSelectedPointData] = useState(); + const { selectedEventData } = useSelectedEventData(); + const { getPointByUuid, updateAction } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); + + useEffect(() => { + if (selectedEventData) { + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData?.data.modelUuid, + selectedEventData?.selectedPoint + ) as MachinePointSchema | undefined; + if (point && 'action' in point) { + setSelectedPointData(point); + setActiveOption(point.action.actionType as "process"); + } + } + }, [selectedProduct, selectedEventData]) + + const handleActionTypeChange = (option: string) => { + if (!selectedEventData || !selectedPointData) return; + const validOption = option as "process"; + setActiveOption(validOption); + + updateAction( + selectedPointData.action.actionUuid, + { actionType: validOption } + ); + }; + + const handleRenameAction = (newName: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { actionName: newName } + ); + }; + + const handleProcessTimeChange = (value: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { processTime: parseFloat(value) } + ); + }; + + const handleMaterialSelect = (material: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { swapMaterial: material } + ); + }; + + // Get current values from store + const currentActionName = selectedPointData + ? selectedPointData.action.actionName + : "Action Name"; + + const currentProcessTime = selectedPointData + ? selectedPointData.action.processTime.toString() + : "1"; + + const currentMaterial = selectedPointData + ? selectedPointData.action.swapMaterial + : "Default material"; + + const availableActions = { + defaultOption: "process", + options: ["process"], + }; + return ( <> + {selectedEventData && + <> +
+
+ +
+
+ + {activeOption === "process" && + + } +
+
+
+ +
+ + } ) } diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx index 0cda40e..d513768 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx @@ -1,8 +1,57 @@ -import React from 'react' +import { useEffect, useState } from 'react' +import RenameInput from '../../../../../ui/inputs/RenameInput' +import LabledDropdown from '../../../../../ui/inputs/LabledDropdown' +import Trigger from '../trigger/Trigger' +import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; +import { useProductStore } from "../../../../../../store/simulation/useProductStore"; +import StorageAction from '../actions/StorageAction'; function StorageMechanics() { + const [activeOption, setActiveOption] = useState("default"); + const [selectedPointData, setSelectedPointData] = useState(); + const { selectedEventData } = useSelectedEventData(); + const { getPointByUuid } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); + + useEffect(() => { + if (selectedEventData) { + const point = getPointByUuid(selectedProduct.productId, selectedEventData?.data.modelUuid, selectedEventData?.selectedPoint); + if (point && 'action' in point) { + setSelectedPointData(point as PointsScheme & { action: { actionType: string } }); + setActiveOption((point as PointsScheme & { action: { actionType: string } }).action.actionType); + } + } + }, [selectedProduct, selectedEventData]) + + const availableActions = { + defaultOption: "store", + options: ["store", "spawn"], + }; + return ( <> + {selectedEventData && + <> +
+
+ +
+
+ setActiveOption(option)} + /> + {activeOption === "store" && } +
+
+
+ +
+ + } ) } diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx index b689734..cc2bfa0 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx @@ -8,22 +8,114 @@ import { useProductStore } from "../../../../../../store/simulation/useProductSt import TravelAction from '../actions/TravelAction' function VehicleMechanics() { - const [activeOption, setActiveOption] = useState("default"); - const [selectedPointData, setSelectedPointData] = useState(); + const [activeOption, setActiveOption] = useState<"default" | "travel">("default"); + const [selectedPointData, setSelectedPointData] = useState(); const { selectedEventData } = useSelectedEventData(); - const { getPointByUuid } = useProductStore(); + const { getPointByUuid, updateEvent, updateAction } = useProductStore(); const { selectedProduct } = useSelectedProduct(); useEffect(() => { if (selectedEventData) { - const point = getPointByUuid(selectedProduct.productId, selectedEventData?.data.modelUuid, selectedEventData?.selectedPoint); - if (point && 'action' in point) { - setSelectedPointData(point as PointsScheme & { action: { actionType: string } }); - setActiveOption((point as PointsScheme & { action: { actionType: string } }).action.actionType); + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData.data.modelUuid, + selectedEventData.selectedPoint + ) as VehiclePointSchema | undefined; + + if (point) { + setSelectedPointData(point); + setActiveOption(point.action.actionType as "travel"); } } }, [selectedProduct, selectedEventData]) + const handleSpeedChange = (value: string) => { + if (!selectedEventData) return; + updateEvent( + selectedProduct.productId, + selectedEventData.data.modelUuid, + { speed: parseFloat(value) } + ); + }; + + const handleActionTypeChange = (option: string) => { + if (!selectedEventData || !selectedPointData) return; + const validOption = option as "travel"; + setActiveOption(validOption); + + updateAction( + selectedPointData.action.actionUuid, + { actionType: validOption } + ); + }; + + const handleRenameAction = (newName: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { actionName: newName } + ); + }; + + const handleLoadCapacityChange = (value: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { loadCapacity: parseFloat(value) } + ); + }; + + const handleUnloadDurationChange = (value: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { unLoadDuration: parseFloat(value) } + ); + }; + + const handlePickPointChange = (value: string) => { + if (!selectedPointData) return; + const [x, y, z] = value.split(',').map(Number); + updateAction( + selectedPointData.action.actionUuid, + { pickUpPoint: { x, y, z } } + ); + }; + + const handleUnloadPointChange = (value: string) => { + if (!selectedPointData) return; + const [x, y, z] = value.split(',').map(Number); + updateAction( + selectedPointData.action.actionUuid, + { unLoadPoint: { x, y, z } } + ); + }; + + // Get current values from store + const currentSpeed = selectedEventData?.data.type === "vehicle" + ? selectedEventData.data.speed.toString() + : "0.5"; + + const currentActionName = selectedPointData + ? selectedPointData.action.actionName + : "Action Name"; + + const currentLoadCapacity = selectedPointData + ? selectedPointData.action.loadCapacity.toString() + : "1"; + + const currentUnloadDuration = selectedPointData + ? selectedPointData.action.unLoadDuration.toString() + : "1"; + + const currentPickPoint = selectedPointData?.action.pickUpPoint + ? `${selectedPointData.action.pickUpPoint.x},${selectedPointData.action.pickUpPoint.y},${selectedPointData.action.pickUpPoint.z}` + : ""; + + const currentUnloadPoint = selectedPointData?.action.unLoadPoint + ? `${selectedPointData.action.unLoadPoint.x},${selectedPointData.action.unLoadPoint.y},${selectedPointData.action.unLoadPoint.z}` + : ""; + const availableActions = { defaultOption: "travel", options: ["travel"], @@ -38,14 +130,14 @@ function VehicleMechanics() {
{ }} - onChange={(value) => console.log(value)} + onChange={handleSpeedChange} />
@@ -53,17 +145,44 @@ function VehicleMechanics() {
- +
setActiveOption(option)} + onSelect={handleActionTypeChange} /> - {activeOption === "travel" && } + + {activeOption === 'travel' && + + }
diff --git a/app/src/components/ui/inputs/PreviewSelectionWithUpload.tsx b/app/src/components/ui/inputs/PreviewSelectionWithUpload.tsx index e2c2936..3e14517 100644 --- a/app/src/components/ui/inputs/PreviewSelectionWithUpload.tsx +++ b/app/src/components/ui/inputs/PreviewSelectionWithUpload.tsx @@ -35,12 +35,6 @@ const PreviewSelectionWithUpload: React.FC = () => { Upload here
- console.log(option)} - />
); diff --git a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts index 2378bf3..82b5596 100644 --- a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts +++ b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts @@ -243,7 +243,7 @@ function processLoadedModel( rotation: [0, 0, 0], action: { actionUuid: THREE.MathUtils.generateUUID(), - actionName: `Action ${index}`, + actionName: `Action ${index + 1}`, actionType: 'default', material: 'inherit', delay: 0, From c0e0bcb69d9880522313419f5e3d8884446cd7d8 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Fri, 25 Apr 2025 11:49:39 +0530 Subject: [PATCH 20/22] refactor: Update material default value and remove console logs for cleaner output --- .../modules/builder/IntialLoad/loadInitialFloorItems.ts | 2 +- .../instances/armInstance/roboticArmInstance.tsx | 4 ++-- .../roboticArm/instances/roboticArmInstances.tsx | 9 +++------ app/src/modules/simulation/roboticArm/roboticArm.tsx | 2 +- app/src/modules/simulation/simulation.tsx | 2 +- 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts index 82b5596..0359f1f 100644 --- a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts +++ b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts @@ -245,7 +245,7 @@ function processLoadedModel( actionUuid: THREE.MathUtils.generateUUID(), actionName: `Action ${index + 1}`, actionType: 'default', - material: 'inherit', + material: 'Default material', delay: 0, spawnInterval: 5, spawnCount: 1, diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index 42b775a..4b6e0a0 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -7,12 +7,12 @@ import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore'; function RoboticArmInstance({ armBot }: any) { const { isPlaying } = usePlayButtonStore(); const [currentPhase, setCurrentPhase] = useState<(string)>("init"); - console.log('currentPhase: ', currentPhase); + // console.log('currentPhase: ', currentPhase); const { armBots, addArmBot, addCurrentAction } = useArmBotStore(); useEffect(() => { - console.log('isPlaying: ', isPlaying); + // console.log('isPlaying: ', isPlaying); if (isPlaying) { //Moving armBot from initial point to rest position. diff --git a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx index 1f963c8..6f578e9 100644 --- a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx +++ b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx @@ -9,12 +9,9 @@ function RoboticArmInstances() { return ( <> { - armBots?.map((robot: any) => ( - - - ) - ) - + armBots?.map((robot) => ( + + )) } diff --git a/app/src/modules/simulation/roboticArm/roboticArm.tsx b/app/src/modules/simulation/roboticArm/roboticArm.tsx index 4295ac7..89f6b76 100644 --- a/app/src/modules/simulation/roboticArm/roboticArm.tsx +++ b/app/src/modules/simulation/roboticArm/roboticArm.tsx @@ -86,7 +86,7 @@ function RoboticArm() { useEffect(() => { - console.log('armBots: ', armBots); + // console.log('armBots: ', armBots); }, [armBots]); return ( diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index 757a9ef..5ca0ec5 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -23,7 +23,7 @@ function Simulation() { }, [events]) useEffect(() => { - console.log('products: ', products); + // console.log('products: ', products); }, [products]) return ( From a1a1eacb795d4732b9f6d82d52312246167a2da3 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Fri, 25 Apr 2025 13:47:46 +0530 Subject: [PATCH 21/22] feat: Refactor event data handling and API integration; update variable names for consistency and clarity --- .../layout/sidebarRight/SideBarRight.tsx | 2 +- .../eventProperties/EventProperties.tsx | 131 ------------------ .../eventProperties/actions/StorageAction.tsx | 36 +++-- .../mechanics/machineMechanics.tsx | 1 - .../mechanics/storageMechanics.tsx | 80 +++++++++-- .../sidebarRight/simulation/Simulations.tsx | 2 +- .../instances/roboticArmInstances.tsx | 9 +- .../simulation/UpsertProductOrEventApi.ts | 26 ++++ .../services/simulation/deleteEventDataApi.ts | 26 ++++ .../simulation/deleteProductDataApi.ts | 25 ++++ app/src/services/simulation/getProductApi.ts | 25 ++++ .../services/simulation/getallProductsApi.ts | 25 ++++ app/src/services/simulation/temp.md | 0 app/src/store/simulation/useProductStore.ts | 42 +++--- app/src/types/simulationTypes.d.ts | 3 +- 15 files changed, 245 insertions(+), 188 deletions(-) create mode 100644 app/src/services/simulation/UpsertProductOrEventApi.ts create mode 100644 app/src/services/simulation/deleteEventDataApi.ts create mode 100644 app/src/services/simulation/deleteProductDataApi.ts create mode 100644 app/src/services/simulation/getProductApi.ts create mode 100644 app/src/services/simulation/getallProductsApi.ts delete mode 100644 app/src/services/simulation/temp.md diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx index 5c37dec..38f0b18 100644 --- a/app/src/components/layout/sidebarRight/SideBarRight.tsx +++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx @@ -37,7 +37,7 @@ const SideBarRight: React.FC = () => { useEffect(() => { if (activeModule !== "mechanics" && selectedEventData && selectedEventSphere) { setSubModule("mechanics"); - } else { + } else if (!selectedEventData && !selectedEventSphere) { if (activeModule === 'simulation') { setSubModule("simulations"); } diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx index 21781f0..ca32594 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx @@ -1,25 +1,4 @@ import React, { useEffect, useRef, useState } from "react"; -import InputWithDropDown from "../../../../ui/inputs/InputWithDropDown"; -import LabledDropdown from "../../../../ui/inputs/LabledDropdown"; -import { - AddIcon, - RemoveIcon, - ResizeHeightIcon, -} from "../../../../icons/ExportCommonIcons"; -import RenameInput from "../../../../ui/inputs/RenameInput"; -import { handleResize } from "../../../../../functions/handleResizePannel"; -import { handleActionToggle } from "./functions/handleActionToggle"; -import { handleDeleteAction } from "./functions/handleDeleteAction"; -import DefaultAction from "./actions/DefaultAction"; -import SpawnAction from "./actions/SpawnAction"; -import SwapAction from "./actions/SwapAction"; -import DespawnAction from "./actions/DespawnAction"; -import TravelAction from "./actions/TravelAction"; -import PickAndPlaceAction from "./actions/PickAndPlaceAction"; -import ProcessAction from "./actions/ProcessAction"; -import StorageAction from "./actions/StorageAction"; -import Trigger from "./trigger/Trigger"; - import { useSelectedEventData, useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; import ConveyorMechanics from "./mechanics/conveyorMechanics"; @@ -29,23 +8,11 @@ import MachineMechanics from "./mechanics/machineMechanics"; import StorageMechanics from "./mechanics/storageMechanics"; const EventProperties: React.FC = () => { - const actionsContainerRef = useRef(null); - - const [activeOption, setActiveOption] = useState("default"); - const [selectedItem, setSelectedItem] = useState<{ item: { uuid: string; name: string } | null; }>({ item: null }); const { selectedEventData } = useSelectedEventData(); const { getEventByModelUuid } = useProductStore(); const { selectedProduct } = useSelectedProduct(); - - // State for derived values const [currentEventData, setCurrentEventData] = useState(null); const [assetType, setAssetType] = useState(null); - const [availableActions, setAvailableActions] = useState({ - defaultOption: "default", - options: ["default"] - }); - const [actions, setActions] = useState<{ uuid: string; name: string }[]>([]); - const [speed, setSpeed] = useState("0.5"); useEffect(() => { const event = getCurrentEventData(); @@ -54,18 +21,6 @@ const EventProperties: React.FC = () => { const type = determineAssetType(event); setAssetType(type); - const actionsConfig = determineAvailableActions(type); - setAvailableActions(actionsConfig); - - const actionList = getActionList(event, type); - setActions(actionList); - - if (actionList.length > 0 && !selectedItem.item) { - setSelectedItem({ item: actionList[0] }); - } - - const currentSpeed = getCurrentSpeed(); - setSpeed(currentSpeed); }, [selectedEventData, selectedProduct]); const getCurrentEventData = () => { @@ -86,92 +41,6 @@ const EventProperties: React.FC = () => { } }; - const determineAvailableActions = (type: string | null) => { - switch (type) { - case "conveyor": - return { - defaultOption: "default", - options: ["default", "spawn", "swap", "despawn"], - }; - case "vehicle": - return { - defaultOption: "travel", - options: ["travel"], - }; - case "roboticArm": - return { - defaultOption: "pickAndPlace", - options: ["pickAndPlace"], - }; - case "machine": - return { - defaultOption: "process", - options: ["process"], - }; - case "storageUnit": - return { - defaultOption: "store", - options: ["store", "spawn"], - }; - default: - return { - defaultOption: "default", - options: ["default"], - }; - } - }; - - const getActionList = (event: EventsSchema | null, type: string | null) => { - if (!selectedEventData?.data) return []; - - switch (type) { - case "conveyor": - return (event as ConveyorEventSchema).points - .find((point) => point.uuid === selectedEventData?.selectedPoint) - ?.action?.triggers.map((trigger) => ({ - uuid: trigger.triggerUuid, - name: trigger.triggerName, - })) || []; - case "vehicle": - return (event as VehicleEventSchema).point.action.triggers.map( - (trigger) => ({ - uuid: trigger.triggerUuid, - name: trigger.triggerName, - }) - ) || []; - case "roboticArm": - return (event as RoboticArmEventSchema).point.actions.flatMap( - (action) => - action.triggers.map((trigger) => ({ - uuid: trigger.triggerUuid, - name: trigger.triggerName, - })) - ) || []; - case "machine": - return (event as MachineEventSchema).point.action.triggers.map( - (trigger) => ({ - uuid: trigger.triggerUuid, - name: trigger.triggerName, - }) - ) || []; - case "storageUnit": - return [ - { - uuid: (event as StorageEventSchema).point.action.actionUuid, - name: (event as StorageEventSchema).point.action.actionName, - }, - ]; - default: - return []; - } - }; - - const getCurrentSpeed = () => { - if (!selectedEventData) return "0.5"; - if ("speed" in selectedEventData.data) return selectedEventData.data.speed.toString(); - return "0.5"; - }; - return ( <>
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/StorageAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/StorageAction.tsx index ab2109b..5c9bf86 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/StorageAction.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/StorageAction.tsx @@ -1,20 +1,28 @@ import React from "react"; import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; -const StorageAction: React.FC = () => { - return ( - {}} - onChange={(value) => console.log(value)} - /> - ); +interface StorageActionProps { + value: string; + min: number; + max: number; + defaultValue: string; + onChange: (value: string) => void; +} + +const StorageAction: React.FC = ({ value, min, max, defaultValue, onChange }) => { + return ( + { }} + onChange={onChange} + /> + ); }; export default StorageAction; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx index 138ed7c..e131864 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx @@ -96,7 +96,6 @@ function MachineMechanics() { defaultOption="process" options={availableActions.options} onSelect={handleActionTypeChange} - disabled={true} /> {activeOption === "process" && (); + const [activeOption, setActiveOption] = useState<"default" | "store" | "spawn">("default"); + const [selectedPointData, setSelectedPointData] = useState(); const { selectedEventData } = useSelectedEventData(); - const { getPointByUuid } = useProductStore(); + const { getPointByUuid, updateAction } = useProductStore(); const { selectedProduct } = useSelectedProduct(); useEffect(() => { if (selectedEventData) { - const point = getPointByUuid(selectedProduct.productId, selectedEventData?.data.modelUuid, selectedEventData?.selectedPoint); + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData?.data.modelUuid, + selectedEventData?.selectedPoint + ) as StoragePointSchema | undefined; if (point && 'action' in point) { - setSelectedPointData(point as PointsScheme & { action: { actionType: string } }); - setActiveOption((point as PointsScheme & { action: { actionType: string } }).action.actionType); + setSelectedPointData(point); + setActiveOption(point.action.actionType as "store" | "spawn"); } } }, [selectedProduct, selectedEventData]) + const handleActionTypeChange = (option: string) => { + if (!selectedEventData || !selectedPointData) return; + const validOption = option as "store" | "spawn"; + setActiveOption(validOption); + + updateAction( + selectedPointData.action.actionUuid, + { actionType: validOption } + ); + }; + + const handleRenameAction = (newName: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { actionName: newName } + ); + }; + + const handleCapacityChange = (value: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { storageCapacity: parseInt(value) } + ); + }; + + // Get current values from store + const currentActionName = selectedPointData + ? selectedPointData.action.actionName + : "Action Name"; + + const currentCapacity = selectedPointData + ? selectedPointData.action.storageCapacity.toString() + : "0"; + const availableActions = { defaultOption: "store", options: ["store", "spawn"], }; - + return ( <> {selectedEventData && <>
- +
setActiveOption(option)} + onSelect={handleActionTypeChange} /> - {activeOption === "store" && } + {activeOption === "store" && + + } + {activeOption === "spawn" && ( +
+

Spawn configuration options would go here

+
+ )}
diff --git a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx index 12a424c..d6b4ac8 100644 --- a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx +++ b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx @@ -90,7 +90,7 @@ const Simulations: React.FC = () => { (product) => product.productId === selectedProduct.productId ); - const events: Event[] = selectedProductData?.eventsData.map((event) => ({ + const events: Event[] = selectedProductData?.eventDatas.map((event) => ({ pathName: event.modelName, })) || []; diff --git a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx index 6f578e9..415c1d3 100644 --- a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx +++ b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx @@ -8,11 +8,10 @@ function RoboticArmInstances() { return ( <> - { - armBots?.map((robot) => ( - - )) - } + + {armBots?.map((robot) => ( + + ))} ) diff --git a/app/src/services/simulation/UpsertProductOrEventApi.ts b/app/src/services/simulation/UpsertProductOrEventApi.ts new file mode 100644 index 0000000..27fa126 --- /dev/null +++ b/app/src/services/simulation/UpsertProductOrEventApi.ts @@ -0,0 +1,26 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const addProductOrEventApi = async (body: any) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/UpsertProductOrEvent`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(body), + }); + + if (!response.ok) { + throw new Error("Failed to add product or event"); + } + + const result = await response.json(); + return result; + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message); + } else { + throw new Error("An unknown error occurred"); + } + } +}; diff --git a/app/src/services/simulation/deleteEventDataApi.ts b/app/src/services/simulation/deleteEventDataApi.ts new file mode 100644 index 0000000..f263065 --- /dev/null +++ b/app/src/services/simulation/deleteEventDataApi.ts @@ -0,0 +1,26 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const deleteEventDataApi = async (body: any) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/EventDataDelete`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(body), + }); + + if (!response.ok) { + throw new Error("Failed to delete event data"); + } + + const result = await response.json(); + return result; + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message); + } else { + throw new Error("An unknown error occurred"); + } + } +}; diff --git a/app/src/services/simulation/deleteProductDataApi.ts b/app/src/services/simulation/deleteProductDataApi.ts new file mode 100644 index 0000000..06718f8 --- /dev/null +++ b/app/src/services/simulation/deleteProductDataApi.ts @@ -0,0 +1,25 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const deleteProductDataApi = async (productId: string, organization: string) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/productDataDelete?productId=${productId}&organization=${organization}`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + }, + }); + + if (!response.ok) { + throw new Error("Failed to delete product data"); + } + + const result = await response.json(); + return result; + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message); + } else { + throw new Error("An unknown error occurred"); + } + } +}; diff --git a/app/src/services/simulation/getProductApi.ts b/app/src/services/simulation/getProductApi.ts new file mode 100644 index 0000000..cf80013 --- /dev/null +++ b/app/src/services/simulation/getProductApi.ts @@ -0,0 +1,25 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const getProductApi = async (productId: string, organization: string) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/productDatas?productId=${productId}&organization=${organization}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }); + + if (!response.ok) { + throw new Error("Failed to fetch product data"); + } + + const result = await response.json(); + return result; + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message); + } else { + throw new Error("An unknown error occurred"); + } + } +}; \ No newline at end of file diff --git a/app/src/services/simulation/getallProductsApi.ts b/app/src/services/simulation/getallProductsApi.ts new file mode 100644 index 0000000..46627f9 --- /dev/null +++ b/app/src/services/simulation/getallProductsApi.ts @@ -0,0 +1,25 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const getAllProductsApi = async ( organization: string) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/AllProducts/${organization}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }); + + if (!response.ok) { + throw new Error("Failed to fetch all products data"); + } + + const result = await response.json(); + return result; + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message); + } else { + throw new Error("An unknown error occurred"); + } + } +}; \ No newline at end of file diff --git a/app/src/services/simulation/temp.md b/app/src/services/simulation/temp.md deleted file mode 100644 index e69de29..0000000 diff --git a/app/src/store/simulation/useProductStore.ts b/app/src/store/simulation/useProductStore.ts index 91576c7..8ec74cf 100644 --- a/app/src/store/simulation/useProductStore.ts +++ b/app/src/store/simulation/useProductStore.ts @@ -7,7 +7,7 @@ type ProductsStore = { // Product-level actions addProduct: (productName: string, productId: string) => void; removeProduct: (productId: string) => void; - updateProduct: (productId: string, updates: Partial<{ productName: string; eventsData: EventsSchema[] }>) => void; + updateProduct: (productId: string, updates: Partial<{ productName: string; eventDatas: EventsSchema[] }>) => void; // Event-level actions addEvent: (productId: string, event: EventsSchema) => void; @@ -54,7 +54,7 @@ type ProductsStore = { renameTrigger: (triggerUuid: string, newName: string) => void; // Helper functions - getProductById: (productId: string) => { productName: string; productId: string; eventsData: EventsSchema[] } | undefined; + getProductById: (productId: string) => { productName: string; productId: string; eventDatas: EventsSchema[] } | undefined; getEventByModelUuid: (productId: string, modelUuid: string) => EventsSchema | undefined; getPointByUuid: (productId: string, modelUuid: string, pointUuid: string) => ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | undefined; getActionByUuid: (productId: string, actionUuid: string) => (ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']) | undefined; @@ -72,7 +72,7 @@ export const useProductStore = create()( const newProduct = { productName, productId: productId, - eventsData: [] + eventDatas: [] }; state.products.push(newProduct); }); @@ -98,7 +98,7 @@ export const useProductStore = create()( set((state) => { const product = state.products.find(p => p.productId === productId); if (product) { - product.eventsData.push(event); + product.eventDatas.push(event); } }); }, @@ -107,7 +107,7 @@ export const useProductStore = create()( set((state) => { const product = state.products.find(p => p.productId === productId); if (product) { - product.eventsData = product.eventsData.filter(e => 'modelUuid' in e && e.modelUuid !== modelUuid); + product.eventDatas = product.eventDatas.filter(e => 'modelUuid' in e && e.modelUuid !== modelUuid); } }); }, @@ -116,7 +116,7 @@ export const useProductStore = create()( set((state) => { const product = state.products.find(p => p.productId === productId); if (product) { - const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); + const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); if (event) { Object.assign(event, updates); } @@ -129,7 +129,7 @@ export const useProductStore = create()( set((state) => { const product = state.products.find(p => p.productId === productId); if (product) { - const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); + const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); if (event && 'points' in event) { (event as ConveyorEventSchema).points.push(point as ConveyorPointSchema); } else if (event && 'point' in event) { @@ -143,7 +143,7 @@ export const useProductStore = create()( set((state) => { const product = state.products.find(p => p.productId === productId); if (product) { - const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); + const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); if (event && 'points' in event) { (event as ConveyorEventSchema).points = (event as ConveyorEventSchema).points.filter(p => p.uuid !== pointUuid); } else if (event && 'point' in event && (event as any).point.uuid === pointUuid) { @@ -157,7 +157,7 @@ export const useProductStore = create()( set((state) => { const product = state.products.find(p => p.productId === productId); if (product) { - const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); + 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) { @@ -175,7 +175,7 @@ export const useProductStore = create()( set((state) => { const product = state.products.find(p => p.productId === productId); if (product) { - const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); + 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) { @@ -195,7 +195,7 @@ export const useProductStore = create()( removeAction: (actionUuid: string) => { set((state) => { for (const product of state.products) { - for (const event of product.eventsData) { + for (const event of product.eventDatas) { if ('points' in event) { // Handle ConveyorEventSchema for (const point of (event as ConveyorEventSchema).points) { @@ -219,7 +219,7 @@ export const useProductStore = create()( updateAction: (actionUuid, updates) => { set((state) => { for (const product of state.products) { - for (const event of product.eventsData) { + 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) { @@ -249,7 +249,7 @@ export const useProductStore = create()( addTrigger: (actionUuid, trigger) => { set((state) => { for (const product of state.products) { - for (const event of product.eventsData) { + 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) { @@ -278,7 +278,7 @@ export const useProductStore = create()( removeTrigger: (triggerUuid) => { set((state) => { for (const product of state.products) { - for (const event of product.eventsData) { + 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) { @@ -305,7 +305,7 @@ export const useProductStore = create()( updateTrigger: (triggerUuid, updates) => { set((state) => { for (const product of state.products) { - for (const event of product.eventsData) { + 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) { @@ -354,7 +354,7 @@ export const useProductStore = create()( renameAction: (actionUuid, newName) => { set((state) => { for (const product of state.products) { - for (const event of product.eventsData) { + 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) { @@ -383,7 +383,7 @@ export const useProductStore = create()( renameTrigger: (triggerUuid, newName) => { set((state) => { for (const product of state.products) { - for (const event of product.eventsData) { + 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) { @@ -427,7 +427,7 @@ export const useProductStore = create()( getEventByModelUuid: (productId, modelUuid) => { const product = get().getProductById(productId); if (!product) return undefined; - return product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); + return product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); }, getPointByUuid: (productId, modelUuid, pointUuid) => { @@ -446,7 +446,7 @@ export const useProductStore = create()( const product = get().products.find(p => p.productId === productId); if (!product) return undefined; - for (const event of product.eventsData) { + for (const event of product.eventDatas) { if ('points' in event) { for (const point of (event as ConveyorEventSchema).points) { if (point.action?.actionUuid === actionUuid) { @@ -470,7 +470,7 @@ export const useProductStore = create()( const product = get().products.find(p => p.productId === productId); if (!product) return undefined; - for (const event of product.eventsData) { + for (const event of product.eventDatas) { if ('points' in event) { for (const point of (event as ConveyorEventSchema).points) { for (const trigger of point.action?.triggers || []) { @@ -504,7 +504,7 @@ export const useProductStore = create()( getIsEventInProduct: (productId, modelUuid) => { const product = get().getProductById(productId); if (!product) return false; - return product.eventsData.some(e => 'modelUuid' in e && e.modelUuid === modelUuid); + return product.eventDatas.some(e => 'modelUuid' in e && e.modelUuid === modelUuid); } })) ); diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index 12c0dc2..eb49368 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -126,7 +126,7 @@ type EventsSchema = ConveyorEventSchema | VehicleEventSchema | RoboticArmEventSc type productsSchema = { productName: string; productId: string; - eventsData: EventsSchema[]; + eventDatas: EventsSchema[]; }[] @@ -135,6 +135,7 @@ interface ConveyorStatus extends ConveyorEventSchema { isActive: boolean; idleTime: number; activeTime: number; + } interface MachineStatus extends MachineEventSchema { From d7a22f5bfbd4e5c9edc717aa1bbecb4414833fa5 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Fri, 25 Apr 2025 16:06:24 +0530 Subject: [PATCH 22/22] feat: Refactor PickAndPlaceAction component to accept props for pick and place points; enhance RoboticArmMechanics with action handling and state management --- .../actions/PickAndPlaceAction.tsx | 26 +- .../mechanics/roboticArmMechanics.tsx | 366 +++++++++++------- app/src/components/ui/list/List.tsx | 3 - .../simulation/roboticArm/roboticArm.tsx | 2 + app/src/modules/simulation/simulation.tsx | 2 +- .../store/simulation/useSimulationStore.ts | 24 ++ 6 files changed, 281 insertions(+), 142 deletions(-) diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/PickAndPlaceAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/PickAndPlaceAction.tsx index 9574669..175a824 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/PickAndPlaceAction.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/PickAndPlaceAction.tsx @@ -1,13 +1,25 @@ import React from "react"; import EyeDropInput from "../../../../../ui/inputs/EyeDropInput"; -const PickAndPlaceAction: React.FC = () => { - return ( - <> - {}} /> - {}} /> - - ); +interface PickAndPlaceActionProps { + pickPointValue: string; + pickPointOnChange: (value: string) => void; + placePointValue: string; + placePointOnChange: (value: string) => void; +} + +const PickAndPlaceAction: React.FC = ({ + pickPointValue, + pickPointOnChange, + placePointValue, + placePointOnChange, +}) => { + return ( + <> + + + + ); }; export default PickAndPlaceAction; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx index 9a044ac..78a32f5 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx @@ -4,7 +4,7 @@ import InputWithDropDown from '../../../../../ui/inputs/InputWithDropDown' import RenameInput from '../../../../../ui/inputs/RenameInput' import LabledDropdown from '../../../../../ui/inputs/LabledDropdown' import Trigger from '../trigger/Trigger' -import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; +import { useSelectedEventData, useSelectedProduct, useSelectedAction } from "../../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import { AddIcon, RemoveIcon, ResizeHeightIcon } from '../../../../../icons/ExportCommonIcons' import { handleResize } from '../../../../../../functions/handleResizePannel' @@ -12,159 +12,263 @@ import PickAndPlaceAction from '../actions/PickAndPlaceAction' function RoboticArmMechanics() { const actionsContainerRef = useRef(null); - - const [activeOption, setActiveOption] = useState("pickAndPlace"); - const [selectedItem, setSelectedItem] = useState<{ item: { uuid: string; name: string } | null; }>({ item: null }); + const [activeOption, setActiveOption] = useState<"default" | "pickAndPlace">("default"); + const [selectedPointData, setSelectedPointData] = useState(); const { selectedEventData } = useSelectedEventData(); - const { getEventByModelUuid, addAction } = useProductStore(); + const { getPointByUuid, updateEvent, updateAction, addAction, removeAction } = useProductStore(); const { selectedProduct } = useSelectedProduct(); - - const availableActions = { - defaultOption: "pickAndPlace", - options: ["pickAndPlace"] - }; - const [actions, setActions] = useState<{ uuid: string; name: string }[]>([]); + const { selectedAction, setSelectedAction, clearSelectedAction } = useSelectedAction(); useEffect(() => { - const event = getCurrentEventData(); - const actionList = getActionList(event as RoboticArmEventSchema); - setActions(actionList); - - if (actionList.length > 0 && !selectedItem.item) { - setSelectedItem({ item: actionList[0] }); + if (selectedEventData) { + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData.data.modelUuid, + selectedEventData.selectedPoint + ) as RoboticArmPointSchema | undefined; + if (point) { + setSelectedPointData(point); + setActiveOption(point.actions[0].actionType as "default" | "pickAndPlace"); + if (point.actions.length > 0 && !selectedAction.actionId) { + setSelectedAction(point.actions[0].actionUuid, point.actions[0].actionName); + } + } + } else { + clearSelectedAction(); } }, [selectedEventData, selectedProduct]); - const getCurrentEventData = () => { - if (!selectedEventData?.data || !selectedProduct) return null; - return getEventByModelUuid(selectedProduct.productId, selectedEventData.data.modelUuid) || null; - }; - - const getActionList = (event: RoboticArmEventSchema) => { - if (!event || !('point' in event)) return []; - - return event.point.actions.flatMap( - (action) => - action.triggers.map((trigger) => ({ - uuid: trigger.triggerUuid, - name: trigger.triggerName, - })) - ) || []; - }; - - const handleActionToggle = (actionUuid: string) => { - const action = actions.find(a => a.uuid === actionUuid); - if (action) { - setSelectedItem({ item: action }); - } + const handleActionSelect = (actionUuid: string, actionName: string) => { + setSelectedAction(actionUuid, actionName); }; const handleAddAction = () => { - if (selectedEventData) { - const newEvent = { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: `Action ${actions.length + 1}`, - actionType: "pickAndPlace" as const, - process: { - startPoint: null as [number, number, number] | null, - endPoint: null as [number, number, number] | null - }, - triggers: [] as TriggerSchema[] - } - addAction( - selectedProduct.productId, - selectedEventData?.data.modelUuid, - selectedEventData?.selectedPoint, - newEvent - ) - } + if (!selectedEventData || !selectedPointData) return; + + const newAction = { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: `Action ${selectedPointData.actions.length + 1}`, + actionType: "pickAndPlace" as "pickAndPlace", + process: { + startPoint: null, + endPoint: null + }, + triggers: [] as TriggerSchema[] + }; + + addAction( + selectedProduct.productId, + selectedEventData.data.modelUuid, + selectedEventData.selectedPoint, + newAction + ); + + const updatedPoint = { + ...selectedPointData, + actions: [...selectedPointData.actions, newAction] + }; + setSelectedPointData(updatedPoint); + setSelectedAction(newAction.actionUuid, newAction.actionName); }; const handleDeleteAction = (actionUuid: string) => { + if (!selectedPointData) return; + removeAction(actionUuid); + const newActions = selectedPointData.actions.filter(a => a.actionUuid !== actionUuid); + + const updatedPoint = { + ...selectedPointData, + actions: newActions + }; + setSelectedPointData(updatedPoint); + + if (selectedAction.actionId === actionUuid) { + if (newActions.length > 0) { + setSelectedAction(newActions[0].actionUuid, newActions[0].actionName); + } else { + clearSelectedAction(); + } + } }; + const handleRenameAction = (newName: string) => { + if (!selectedAction.actionId) return; + updateAction( + selectedAction.actionId, + { actionName: newName } + ); + + if (selectedPointData) { + const updatedActions = selectedPointData.actions.map(action => + action.actionUuid === selectedAction.actionId + ? { ...action, actionName: newName } + : action + ); + setSelectedPointData({ + ...selectedPointData, + actions: updatedActions + }); + } + }; + + const handleSpeedChange = (value: string) => { + if (!selectedEventData) return; + updateEvent( + selectedProduct.productId, + selectedEventData.data.modelUuid, + { speed: parseFloat(value) } + ); + }; + + const handlePickPointChange = (value: string) => { + if (!selectedAction.actionId || !selectedPointData) return; + const [x, y, z] = value.split(',').map(Number); + + updateAction( + selectedAction.actionId, + { + process: { + startPoint: [x, y, z] as [number, number, number], + endPoint: selectedPointData.actions.find(a => a.actionUuid === selectedAction.actionId)?.process.endPoint || null + } + } + ); + }; + + const handlePlacePointChange = (value: string) => { + if (!selectedAction.actionId || !selectedPointData) return; + const [x, y, z] = value.split(',').map(Number); + + updateAction( + selectedAction.actionId, + { + process: { + startPoint: selectedPointData.actions.find(a => a.actionUuid === selectedAction.actionId)?.process.startPoint || null, + endPoint: [x, y, z] as [number, number, number] + } + } + ); + }; + + const availableActions = { + defaultOption: "pickAndPlace", + options: ["pickAndPlace"], + }; + + const currentSpeed = selectedEventData?.data.type === "roboticArm" + ? selectedEventData.data.speed.toString() + : "0.5"; + + const currentAction = selectedPointData?.actions.find(a => a.actionUuid === selectedAction.actionId); + const currentPickPoint = currentAction?.process.startPoint + ? `${currentAction.process.startPoint[0]},${currentAction.process.startPoint[1]},${currentAction.process.startPoint[2]}` + : ""; + const currentPlacePoint = currentAction?.process.endPoint + ? `${currentAction.process.endPoint[0]},${currentAction.process.endPoint[1]},${currentAction.process.endPoint[2]}` + : ""; + return ( <> -
-
-
- { }} - onChange={(value) => console.log(value)} - /> -
-
-
-
-
-
-
Actions
-
handleAddAction()}> - Add + {selectedEventData && selectedPointData && ( + <> +
+
+
+ { }} + onChange={handleSpeedChange} + /> +
-
-
- {actions.map((action) => ( -
-
handleActionToggle(action.uuid)} - > - -
- {actions.length > 1 && ( -
handleDeleteAction(action.uuid)} - > - -
- )} + +
+
+
+
Actions
+
+ Add
- ))} -
-
handleResize(e, actionsContainerRef)} - > - +
+
+
+ {selectedPointData.actions.map((action) => ( +
+
handleActionSelect(action.actionUuid, action.actionName)} + > + +
+ {selectedPointData.actions.length > 1 && ( +
handleDeleteAction(action.actionUuid)} + > + +
+ )} +
+ ))} +
+
handleResize(e, actionsContainerRef)} + > + +
+
-
-
-
-
- -
-
- setActiveOption(option)} - /> - {activeOption === "pickAndPlace" && } -
-
-
- -
+ + {selectedAction.actionId && currentAction && ( +
+
+ +
+
+ { }} + disabled={true} + /> + +
+
+ +
+
+ )} + + )} ) } diff --git a/app/src/components/ui/list/List.tsx b/app/src/components/ui/list/List.tsx index cac0b43..ac21c5a 100644 --- a/app/src/components/ui/list/List.tsx +++ b/app/src/components/ui/list/List.tsx @@ -142,9 +142,6 @@ const List: React.FC = ({ items = [], remove }) => { ) ); } - - console.log('newName: ', newName); - } const checkZoneNameDuplicate = (name: string) => { return zones.some( diff --git a/app/src/modules/simulation/roboticArm/roboticArm.tsx b/app/src/modules/simulation/roboticArm/roboticArm.tsx index 89f6b76..d403c6a 100644 --- a/app/src/modules/simulation/roboticArm/roboticArm.tsx +++ b/app/src/modules/simulation/roboticArm/roboticArm.tsx @@ -94,6 +94,8 @@ function RoboticArm() { + <> + ); } diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index 5ca0ec5..757a9ef 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -23,7 +23,7 @@ function Simulation() { }, [events]) useEffect(() => { - // console.log('products: ', products); + console.log('products: ', products); }, [products]) return ( diff --git a/app/src/store/simulation/useSimulationStore.ts b/app/src/store/simulation/useSimulationStore.ts index ae6ac81..5085688 100644 --- a/app/src/store/simulation/useSimulationStore.ts +++ b/app/src/store/simulation/useSimulationStore.ts @@ -90,4 +90,28 @@ export const useSelectedProduct = create()( }); }, })) +); + +interface SelectedActionState { + selectedAction: { actionId: string; actionName: string }; + setSelectedAction: (actionId: string, actionName: string) => void; + clearSelectedAction: () => void; +} + +export const useSelectedAction = create()( + immer((set) => ({ + selectedAction: { actionId: '', actionName: '' }, + setSelectedAction: (actionId, actionName) => { + set((state) => { + state.selectedAction.actionId = actionId; + state.selectedAction.actionName = actionName; + }); + }, + clearSelectedAction: () => { + set((state) => { + state.selectedAction.actionId = ''; + state.selectedAction.actionName = ''; + }); + }, + })) ); \ No newline at end of file