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 = {