From a305c3c00635bdced28b15149e52bfdc81a94d1b Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Thu, 24 Apr 2025 16:38:42 +0530 Subject: [PATCH] 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 = {