diff --git a/app/package-lock.json b/app/package-lock.json index 8be748e..a820896 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -29,7 +29,6 @@ "chartjs-plugin-annotation": "^3.1.0", "glob": "^11.0.0", "gsap": "^3.12.5", - "html2canvas": "^1.4.1", "leva": "^0.10.0", "mqtt": "^5.10.4", "postprocessing": "^6.36.4", @@ -2020,7 +2019,7 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, + "devOptional": true, "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -2032,7 +2031,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, + "devOptional": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -4135,6 +4134,26 @@ "url": "https://github.com/sponsors/gregberge" } }, + "node_modules/@testing-library/dom": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", + "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@testing-library/jest-dom": { "version": "5.17.0", "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz", @@ -4246,25 +4265,25 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true + "devOptional": true }, "node_modules/@turf/along": { "version": "7.2.0", @@ -8028,15 +8047,6 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, - "node_modules/base64-arraybuffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", - "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6.0" - } - }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -9007,7 +9017,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true + "devOptional": true }, "node_modules/cross-env": { "version": "7.0.3", @@ -9092,15 +9102,6 @@ "postcss": "^8.4" } }, - "node_modules/css-line-break": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", - "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", - "license": "MIT", - "dependencies": { - "utrie": "^1.0.2" - } - }, "node_modules/css-loader": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", @@ -9884,7 +9885,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.3.1" } @@ -12488,19 +12489,6 @@ } } }, - "node_modules/html2canvas": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", - "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", - "license": "MIT", - "dependencies": { - "css-line-break": "^2.1.0", - "text-segmentation": "^1.0.3" - }, - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/htmlparser2": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", @@ -15247,7 +15235,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "devOptional": true }, "node_modules/makeerror": { "version": "1.0.12", @@ -20446,15 +20434,6 @@ "node": "*" } }, - "node_modules/text-segmentation": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", - "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", - "license": "MIT", - "dependencies": { - "utrie": "^1.0.2" - } - }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -20715,7 +20694,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, + "devOptional": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -20758,7 +20737,7 @@ "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "dev": true, + "devOptional": true, "dependencies": { "acorn": "^8.11.0" }, @@ -20770,7 +20749,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "devOptional": true }, "node_modules/tsconfig-paths": { "version": "3.15.0", @@ -21241,15 +21220,6 @@ "node": ">= 0.4.0" } }, - "node_modules/utrie": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", - "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", - "license": "MIT", - "dependencies": { - "base64-arraybuffer": "^1.0.2" - } - }, "node_modules/uuid": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", @@ -21266,7 +21236,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true + "devOptional": true }, "node_modules/v8-to-istanbul": { "version": "8.1.1", @@ -22325,7 +22295,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, + "devOptional": true, "engines": { "node": ">=6" } diff --git a/app/package.json b/app/package.json index ce5c7d3..66e3b39 100644 --- a/app/package.json +++ b/app/package.json @@ -24,7 +24,6 @@ "chartjs-plugin-annotation": "^3.1.0", "glob": "^11.0.0", "gsap": "^3.12.5", - "html2canvas": "^1.4.1", "leva": "^0.10.0", "mqtt": "^5.10.4", "postprocessing": "^6.36.4", diff --git a/app/src/components/layout/3D-cards/cards/ProductionCapacity.tsx b/app/src/components/layout/3D-cards/cards/ProductionCapacity.tsx index 443bdbd..a6343ed 100644 --- a/app/src/components/layout/3D-cards/cards/ProductionCapacity.tsx +++ b/app/src/components/layout/3D-cards/cards/ProductionCapacity.tsx @@ -166,6 +166,7 @@ const ProductionCapacity: React.FC = ({ const response = await axios.get( `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}` ); + if (response.status === 200) { setmeasurements(response.data.Data.measurements); setDuration(response.data.Data.duration); diff --git a/app/src/components/layout/sidebarLeft/Assets.tsx b/app/src/components/layout/sidebarLeft/Assets.tsx index b2839fc..67bf969 100644 --- a/app/src/components/layout/sidebarLeft/Assets.tsx +++ b/app/src/components/layout/sidebarLeft/Assets.tsx @@ -129,6 +129,7 @@ const Assets: React.FC = () => { } else { try { const res = await getCategoryAsset(asset); + console.log('res: ', res); setCategoryAssets(res); setFiltereredAssets(res); } catch (error) {} @@ -191,7 +192,7 @@ const Assets: React.FC = () => { onPointerDown={() => setSelectedItem({ name: asset.filename, - id: asset.modelfileID, + id: asset.AssetID, }) } /> diff --git a/app/src/components/layout/sidebarLeft/visualization/Templates.tsx b/app/src/components/layout/sidebarLeft/visualization/Templates.tsx index 436af7f..efcbcaf 100644 --- a/app/src/components/layout/sidebarLeft/visualization/Templates.tsx +++ b/app/src/components/layout/sidebarLeft/visualization/Templates.tsx @@ -88,22 +88,22 @@ const Templates = () => { return (
{templates.map((template, index) => ( -
+
handleLoadTemplate(template)} + > {template?.snapshot && (
{`${template.name} handleLoadTemplate(template)} />
)}
-
handleLoadTemplate(template)} - className="template-name" - > +
{/* {`Template ${index + 1}`} */}
diff --git a/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets2D.tsx b/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets2D.tsx index c411ffd..d0873c5 100644 --- a/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets2D.tsx +++ b/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets2D.tsx @@ -104,7 +104,7 @@ const ProgressBarWidget = ({ const Widgets2D = () => { return ( -
+
{chartTypes.map((type, index) => { const widgetTitle = `Widget ${index + 1}`; diff --git a/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets3D.tsx b/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets3D.tsx index c54f75c..7457648 100644 --- a/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets3D.tsx +++ b/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets3D.tsx @@ -12,22 +12,21 @@ const Widgets3D = () => { ]; const { widgetSelect, setWidgetSelect } = useAsset3dWidget(); - return ( -
+
{widgets?.map((widget, index) => (
{ - let name = widget.name - let crt = e.target + let name = widget.name; + let crt = e.target; if (crt instanceof HTMLElement) { const widget = crt.cloneNode(true) as HTMLElement; - e.dataTransfer.setDragImage(widget, 0, 0) - e.dataTransfer.effectAllowed = "move" - e.dataTransfer.setData("text/plain", "ui-" + name) + e.dataTransfer.setDragImage(widget, 0, 0); + e.dataTransfer.effectAllowed = "move"; + e.dataTransfer.setData("text/plain", "ui-" + name); } }} onPointerDown={() => { @@ -42,7 +41,7 @@ const Widgets3D = () => { className="widget-image" src={widget.img} alt={widget.name} - draggable={false} + draggable={false} />
))} diff --git a/app/src/components/layout/sidebarRight/mechanics/ArmBotMechanics.tsx b/app/src/components/layout/sidebarRight/mechanics/ArmBotMechanics.tsx index 4dffdb2..cfa7822 100644 --- a/app/src/components/layout/sidebarRight/mechanics/ArmBotMechanics.tsx +++ b/app/src/components/layout/sidebarRight/mechanics/ArmBotMechanics.tsx @@ -1,32 +1,128 @@ import React, { useRef, useMemo, useCallback, useState } from "react"; -import { InfoIcon } from "../../../icons/ExportCommonIcons"; +import { InfoIcon, AddIcon, RemoveIcon, ResizeHeightIcon } from "../../../icons/ExportCommonIcons"; import InputWithDropDown from "../../../ui/inputs/InputWithDropDown"; -import { - useSelectedActionSphere, - useSimulationStates, - useSocketStore -} from "../../../../store/store"; +import { useSelectedActionSphere, useSimulationStates, useSocketStore } from "../../../../store/store"; import * as Types from '../../../../types/world/worldTypes'; -import LabeledButton from "../../../ui/inputs/LabledButton"; import LabledDropdown from "../../../ui/inputs/LabledDropdown"; +import { handleResize } from "../../../../functions/handleResizePannel"; + +interface ConnectedModel { + modelUUID: string; + modelName: string; + points: { + uuid: string; + position: [number, number, number]; + index?: number; + }[]; + triggers?: { + uuid: string; + name: string; + type: string; + isUsed: boolean; + }[]; +} const ArmBotMechanics: React.FC = () => { const { selectedActionSphere } = useSelectedActionSphere(); const { simulationStates, setSimulationStates } = useSimulationStates(); const { socket } = useSocketStore(); - const [selectedTrigger, setSelectedTrigger] = useState(null); + const [selectedProcessIndex, setSelectedProcessIndex] = useState(null); + const actionsContainerRef = useRef(null); - const propertiesContainerRef = useRef(null); - - // Get connected models for dropdowns - const connectedModels = useMemo(() => { + // Get connected models and their triggers + const connectedModels = useMemo(() => { if (!selectedActionSphere?.points?.uuid) return []; + const armBotPaths = simulationStates.filter( + (path): path is Types.ArmBotEventsSchema => path.type === "ArmBot" + ); + + const currentPoint = armBotPaths.find( + (path) => path.points.uuid === selectedActionSphere.points.uuid + )?.points; + + if (!currentPoint?.connections?.targets) return []; + + return currentPoint.connections.targets.reduce((acc, target) => { + const connectedModel = simulationStates.find( + (model) => model.modeluuid === target.modelUUID + ); + + if (!connectedModel) return acc; + + let triggers: { uuid: string; name: string; type: string; isUsed: boolean }[] = []; + let points: { uuid: string; position: [number, number, number] }[] = []; + + if (connectedModel.type === "Conveyor") { + const conveyor = connectedModel as Types.ConveyorEventsSchema; + + const connectedPointUUIDs = currentPoint?.connections?.targets + .filter(t => t.modelUUID === connectedModel.modeluuid) + .map(t => t.pointUUID) || []; + + points = conveyor.points + .map((point, idx) => ({ + uuid: point.uuid, + position: point.position, + index: idx + })) + .filter(point => connectedPointUUIDs.includes(point.uuid)); + + + triggers = conveyor.points.flatMap(p => p.triggers?.filter(t => t.isUsed) || []); + } + else if (connectedModel.type === "StaticMachine") { + const staticMachine = connectedModel as Types.StaticMachineEventsSchema; + + points = [{ + uuid: staticMachine.points.uuid, + position: staticMachine.points.position + }]; + + triggers = staticMachine.points.triggers ? + [{ + uuid: staticMachine.points.triggers.uuid, + name: staticMachine.points.triggers.name, + type: staticMachine.points.triggers.type, + isUsed: true // StaticMachine triggers are always considered used + }] : []; + } + + if (!acc.some(m => m.modelUUID === connectedModel.modeluuid)) { + acc.push({ + modelUUID: connectedModel.modeluuid, + modelName: connectedModel.modelName, + points, + triggers + }); + } + + return acc; + }, []); }, [selectedActionSphere, simulationStates]); - // Get triggers only from connected models + // Get triggers from connected models const connectedTriggers = useMemo(() => { - }, [connectedModels, simulationStates]); + return connectedModels.flatMap(model => + (model.triggers || []).map(trigger => ({ + ...trigger, + displayName: `${model.modelName} - ${trigger.name}`, + modelUUID: model.modelUUID + })) + ); + }, [connectedModels]); + + // Get all points from connected models + const connectedPoints = useMemo(() => { + return connectedModels.flatMap(model => + model.points.map(point => ({ + ...point, + displayName: `${model.modelName} - Point${typeof point.index === 'number' ? ` ${point.index}` : ''}`, + modelUUID: model.modelUUID + })) + ); + }, [connectedModels]); + const { selectedPoint } = useMemo(() => { if (!selectedActionSphere?.points?.uuid) return { selectedPoint: null }; @@ -45,77 +141,148 @@ const ArmBotMechanics: React.FC = () => { }, [selectedActionSphere, simulationStates]); const updateBackend = async (updatedPath: Types.ArmBotEventsSchema | undefined) => { - // if (!updatedPath) return; - // const email = localStorage.getItem("email"); - // const organization = email ? email.split("@")[1].split(".")[0] : ""; + if (!updatedPath) return; + const email = localStorage.getItem("email"); + const organization = email ? email.split("@")[1].split(".")[0] : ""; - // const data = { - // organization: organization, - // modeluuid: updatedPath.modeluuid, - // eventData: { type: "ArmBot", points: updatedPath.points } - // } + const data = { + organization: organization, + modeluuid: updatedPath.modeluuid, + eventData: { type: "ArmBot", points: updatedPath.points } + } + console.log('data: ', data); - // socket.emit('v2:model-asset:updateEventData', data); + socket.emit('v2:model-asset:updateEventData', data); } - // const handleActionUpdate = useCallback((updatedAction: Partial) => { - // if (!selectedActionSphere?.points?.uuid) return; + const handleActionUpdate = useCallback((updatedAction: Partial) => { + if (!selectedActionSphere?.points?.uuid || !selectedPoint) return; - // const updatedPaths = simulationStates.map((path) => { - // return path; - // }); + const updatedPaths = simulationStates.map((path) => { + if (path.type === "ArmBot" && path.points.uuid === selectedActionSphere.points.uuid) { + return { + ...path, + points: { + ...path.points, + actions: { + ...path.points.actions, + ...updatedAction + } + } + }; + } + return path; + }); - // const updatedPath = updatedPaths.find( - // (path): path is Types.ArmBotEventsSchema => - // path.type === "ArmBot" && - // path.points.uuid === selectedActionSphere.points.uuid - // ); - // updateBackend(updatedPath); + const updatedPath = updatedPaths.find( + (path): path is Types.ArmBotEventsSchema => + path.type === "ArmBot" && + path.points.uuid === selectedActionSphere.points.uuid + ); + updateBackend(updatedPath); - // setSimulationStates(updatedPaths); - // }, [selectedActionSphere?.points?.uuid, simulationStates, setSimulationStates]); + setSimulationStates(updatedPaths); + }, [selectedActionSphere?.points?.uuid, selectedPoint, simulationStates, setSimulationStates]); - // const handleSpeedChange = useCallback((speed: number) => { - // handleActionUpdate({ speed }); - // }, [handleActionUpdate]); + const handleSpeedChange = useCallback((speed: number) => { + handleActionUpdate({ speed }); + }, [handleActionUpdate]); - // const handleProcessChange = useCallback((processes: Types.ArmBotEventsSchema['points']['actions']['processes']) => { - // handleActionUpdate({ processes }); - // }, [handleActionUpdate]); + const handleProcessChange = useCallback((processes: Types.ArmBotEventsSchema['points']['actions']['processes']) => { + handleActionUpdate({ processes }); + }, [handleActionUpdate]); - // const handleTriggerSelect = useCallback((displayName: string) => { - // const selected = connectedTriggers.find(t => t.displayName === displayName); - // setSelectedTrigger(selected?.uuid || null); - // }, [connectedTriggers]); + const handleAddProcess = useCallback(() => { + if (!selectedPoint) return; - // const handleStartPointSelect = useCallback((pointUUID: string) => { - // if (!selectedTrigger || !selectedPoint) return; + const newProcess: any = { + triggerId: "", + startPoint: "", + endPoint: "" + }; - // const updatedProcesses = selectedPoint.actions.processes?.map(process => - // process.triggerId === selectedTrigger - // ? { ...process, startPoint: pointUUID } - // : process - // ) || []; + const updatedProcesses = selectedPoint.actions.processes ? [...selectedPoint.actions.processes, newProcess] : [newProcess]; - // handleProcessChange(updatedProcesses); - // }, [selectedTrigger, selectedPoint, handleProcessChange]); + handleProcessChange(updatedProcesses); + setSelectedProcessIndex(updatedProcesses.length - 1); + }, [selectedPoint, handleProcessChange]); - // const handleEndPointSelect = useCallback((pointUUID: string) => { - // if (!selectedTrigger || !selectedPoint) return; + const handleDeleteProcess = useCallback((index: number) => { + if (!selectedPoint?.actions.processes) return; - // const updatedProcesses = selectedPoint.actions.processes?.map(process => - // process.triggerId === selectedTrigger - // ? { ...process, endPoint: pointUUID } - // : process - // ) || []; + const updatedProcesses = [...selectedPoint.actions.processes]; + updatedProcesses.splice(index, 1); - // handleProcessChange(updatedProcesses); - // }, [selectedTrigger, selectedPoint, handleProcessChange]); + handleProcessChange(updatedProcesses); - // const getCurrentProcess = useCallback(() => { - // if (!selectedTrigger || !selectedPoint) return null; - // return selectedPoint.actions.processes?.find(p => p.triggerId === selectedTrigger); - // }, [selectedTrigger, selectedPoint]); + // Reset selection if deleting the currently selected process + if (selectedProcessIndex === index) { + setSelectedProcessIndex(null); + } else if (selectedProcessIndex !== null && selectedProcessIndex > index) { + // Adjust selection index if needed + setSelectedProcessIndex(selectedProcessIndex - 1); + } + }, [selectedPoint, selectedProcessIndex, handleProcessChange]); + + const handleTriggerSelect = useCallback((displayName: string, index: number) => { + const selected = connectedTriggers.find(t => t.displayName === displayName); + if (!selected || !selectedPoint?.actions.processes) return; + + const oldProcess = selectedPoint.actions.processes[index]; + + const updatedProcesses = [...selectedPoint.actions.processes]; + + // Only reset start/end if new trigger invalidates them (your logic can expand this) + updatedProcesses[index] = { + ...oldProcess, + triggerId: selected.uuid, + startPoint: oldProcess.startPoint || "", // preserve if exists + endPoint: oldProcess.endPoint || "" // preserve if exists + }; + + handleProcessChange(updatedProcesses); + }, [connectedTriggers, selectedPoint, handleProcessChange]); + + const handleStartPointSelect = useCallback((displayName: string, index: number) => { + if (!selectedPoint?.actions.processes) return; + + const point = connectedPoints.find(p => p.displayName === displayName); + if (!point) return; + + const updatedProcesses = [...selectedPoint.actions.processes]; + updatedProcesses[index] = { + ...updatedProcesses[index], + startPoint: point.uuid + }; + + handleProcessChange(updatedProcesses); + }, [selectedPoint, connectedPoints, handleProcessChange]); + + const handleEndPointSelect = useCallback((displayName: string, index: number) => { + if (!selectedPoint?.actions.processes) return; + + const point = connectedPoints.find(p => p.displayName === displayName); + if (!point) return; + + const updatedProcesses = [...selectedPoint.actions.processes]; + updatedProcesses[index] = { + ...updatedProcesses[index], + endPoint: point.uuid + }; + + handleProcessChange(updatedProcesses); + }, [selectedPoint, connectedPoints, handleProcessChange]); + + const getProcessByIndex = useCallback((index: number) => { + if (!selectedPoint?.actions.processes || index >= selectedPoint.actions.processes.length) return null; + return selectedPoint.actions.processes[index]; + }, [selectedPoint]); + + const getFilteredTriggerOptions = (currentIndex: number) => { + const usedTriggerUUIDs = selectedPoint?.actions.processes?.filter((_, i) => i !== currentIndex).map(p => p.triggerId).filter(Boolean) ?? []; + + return connectedTriggers.filter(trigger => !usedTriggerUUIDs.includes(trigger.uuid)).map(trigger => trigger.displayName); + }; return (
@@ -124,10 +291,10 @@ const ArmBotMechanics: React.FC = () => {
-
+
ArmBot Properties
- {/* {selectedPoint && ( + {selectedPoint && ( <> { onChange={(value) => handleSpeedChange(parseInt(value))} /> - t.uuid === selectedTrigger)?.displayName || ''} - onSelect={handleTriggerSelect} - options={connectedTriggers.map(trigger => trigger.displayName)} - /> +
+
+
Processes
+
+ Add +
+
+
+
+ {selectedPoint.actions.processes?.map((process, index) => ( +
+
setSelectedProcessIndex(index)} + > + Process {index + 1} +
+
handleDeleteProcess(index)} + > + +
+
+ ))} +
+
handleResize(e, actionsContainerRef)} + > + +
+
+
- {selectedTrigger && ( - <> + {selectedProcessIndex !== null && ( +
+ t.uuid === getProcessByIndex(selectedProcessIndex)?.triggerId + )?.displayName || 'Select a trigger' + } + onSelect={(value) => handleTriggerSelect(value, selectedProcessIndex)} + options={getFilteredTriggerOptions(selectedProcessIndex)} + /> + + `${model.modelName} [${index}]`)} + defaultOption={ + connectedPoints.find(p => + p.uuid === getProcessByIndex(selectedProcessIndex)?.startPoint + )?.displayName || 'Select start point' + } + onSelect={(value) => handleStartPointSelect(value, selectedProcessIndex)} + options={connectedPoints.map(point => point.displayName)} /> `${model.modelName} [${index}]`)} + defaultOption={ + connectedPoints.find(p => + p.uuid === getProcessByIndex(selectedProcessIndex)?.endPoint + )?.displayName || 'Select end point' + } + onSelect={(value) => handleEndPointSelect(value, selectedProcessIndex)} + options={connectedPoints.map(point => point.displayName)} /> - - +
)} - )} */} + )}
diff --git a/app/src/components/layout/sidebarRight/mechanics/ConveyorMechanics.tsx b/app/src/components/layout/sidebarRight/mechanics/ConveyorMechanics.tsx index 6c7487e..71ee9ce 100644 --- a/app/src/components/layout/sidebarRight/mechanics/ConveyorMechanics.tsx +++ b/app/src/components/layout/sidebarRight/mechanics/ConveyorMechanics.tsx @@ -647,7 +647,7 @@ const ConveyorMechanics: React.FC = () => { setSelectedItem({ type: "action", item: action }) } > - +
{ setSelectedItem({ type: "trigger", item: trigger }) } > - +
{ @@ -10,6 +10,7 @@ const ZoneProperties: React.FC = () => { const { selectedZone, setSelectedZone } = useSelectedZoneStore(); const { zonePosition, setZonePosition } = usezonePosition(); const { zoneTarget, setZoneTarget } = usezoneTarget(); + const { zones, setZones } = useZones(); useEffect(() => { setZonePosition(selectedZone.zoneViewPortPosition) @@ -31,11 +32,11 @@ const ZoneProperties: React.FC = () => { if (response.message === "updated successfully") { setEdit(false); } else { - console.log("Not updated Camera Position and Target"); + console.log(response); } } catch (error) { - console.error("Error in handleSetView:", error); + } } @@ -43,17 +44,32 @@ const ZoneProperties: React.FC = () => { setEdit(!Edit); // This will toggle the `Edit` state correctly } - function handleZoneNameChange(newName: string) { - setSelectedZone((prev) => ({ ...prev, zoneName: newName })); + async function handleZoneNameChange(newName: string) { + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; + const zonesdata = { + zoneId: selectedZone.zoneId, + zoneName: newName + }; + // Call your API to update the zone + let response = await zoneCameraUpdate(zonesdata, organization); + console.log('response: ', response); + if (response.message === "updated successfully") { + setZones((prevZones: any[]) => + prevZones.map((zone) => + zone.zoneId === selectedZone.zoneId + ? { ...zone, zoneName: newName } + : zone + ) + ); + }else{ + console.log(response?.message); + } } - function handleVectorChange(key: "zoneViewPortTarget" | "zoneViewPortPosition", newValue: [number, number, number]) { setSelectedZone((prev) => ({ ...prev, [key]: newValue })); } - useEffect(() => { - - }, [selectedZone]); return (
diff --git a/app/src/components/ui/componets/AddButtons.tsx b/app/src/components/ui/componets/AddButtons.tsx index 13e4c89..b79265e 100644 --- a/app/src/components/ui/componets/AddButtons.tsx +++ b/app/src/components/ui/componets/AddButtons.tsx @@ -6,6 +6,8 @@ import { } from "../../icons/RealTimeVisulationIcons"; import { AddIcon } from "../../icons/ExportCommonIcons"; import { useSocketStore } from "../../../store/store"; +import { clearPanel } from "../../../services/realTimeVisulization/zoneData/clearPanel"; +import { lockPanel } from "../../../services/realTimeVisulization/zoneData/lockPanel"; // Define the type for `Side` type Side = "top" | "bottom" | "left" | "right"; @@ -88,8 +90,10 @@ const AddButtons: React.FC = ({ }; // Function to toggle lock/unlock a panel - const toggleLockPanel = (side: Side) => { - console.log("side: ", side); + const toggleLockPanel = async (side: Side) => { + // console.log('side: ', side); + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; // Fallback value //add api const newLockedPanels = selectedZone.lockedPanels.includes(side) ? selectedZone.lockedPanels.filter((panel) => panel !== side) @@ -100,29 +104,70 @@ const AddButtons: React.FC = ({ lockedPanels: newLockedPanels, }; - // Update the selectedZone state + let lockedPanel = { + organization: organization, + lockedPanel: newLockedPanels, + zoneId: selectedZone.zoneId, + }; + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-panel:locked", lockedPanel); + } + setSelectedZone(updatedZone); + // let response = await lockPanel(selectedZone.zoneId, organization, newLockedPanels) + // console.log('response: ', response); + // if (response.message === 'locked panel updated successfully') { + // // Update the selectedZone state + // setSelectedZone(updatedZone); + // } }; // Function to clean all widgets from a panel - const cleanPanel = (side: Side) => { + const cleanPanel = async (side: Side) => { //add api - console.log("side: ", side); + // console.log('side: ', side); + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; // Fallback value + + let clearPanel = { + organization: organization, + panelName: side, + zoneId: selectedZone.zoneId, + }; + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-panel:clear", clearPanel); + } const cleanedWidgets = selectedZone.widgets.filter( (widget) => widget.panel !== side ); - const updatedZone = { ...selectedZone, widgets: cleanedWidgets, }; // Update the selectedZone state + // console.log('updatedZone: ', updatedZone); setSelectedZone(updatedZone); + + // let response = await clearPanel(selectedZone.zoneId, organization, side) + // console.log('response: ', response); + // if (response.message === 'PanelWidgets cleared successfully') { + + // const cleanedWidgets = selectedZone.widgets.filter( + // (widget) => widget.panel !== side + // ); + // const updatedZone = { + // ...selectedZone, + // widgets: cleanedWidgets, + // }; + // // Update the selectedZone state + // setSelectedZone(updatedZone); + // } }; // Function to handle "+" button click const handlePlusButtonClick = async (side: Side) => { if (selectedZone.activeSides.includes(side)) { + console.log("open"); // Panel already exists: Remove widgets from that side and update activeSides const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; // Fallback value diff --git a/app/src/components/ui/componets/DisplayZone.tsx b/app/src/components/ui/componets/DisplayZone.tsx index 03fd44f..fa1f251 100644 --- a/app/src/components/ui/componets/DisplayZone.tsx +++ b/app/src/components/ui/componets/DisplayZone.tsx @@ -13,6 +13,10 @@ import { get3dWidgetZoneData } from "../../../services/realTimeVisulization/zone // Define the type for `Side` type Side = "top" | "bottom" | "left" | "right"; +interface HiddenPanels { + [zoneId: string]: Side[]; +} + interface DisplayZoneProps { zonesData: { [key: string]: { @@ -59,12 +63,15 @@ interface DisplayZoneProps { }[]; }> >; + hiddenPanels: HiddenPanels; // Updated prop type + setHiddenPanels: React.Dispatch>; // Updated prop type } const DisplayZone: React.FC = ({ zonesData, selectedZone, setSelectedZone, + hiddenPanels, }) => { // Ref for the container element const containerRef = useRef(null); @@ -73,9 +80,9 @@ const DisplayZone: React.FC = ({ // State to track overflow visibility const [showLeftArrow, setShowLeftArrow] = useState(false); const [showRightArrow, setShowRightArrow] = useState(false); - const { floatingWidget, setFloatingWidget } = useFloatingWidget() - - const{setSelectedChartId}=useWidgetStore() + const { floatingWidget, setFloatingWidget } = useFloatingWidget(); + + const { setSelectedChartId } = useWidgetStore(); // Function to calculate overflow state const updateOverflowState = useCallback(() => { @@ -152,7 +159,7 @@ const DisplayZone: React.FC = ({ if (selectedZone?.zoneId === zoneId) { return; } - setSelectedChartId(null) + setSelectedChartId(null); const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; let response = await getSelect2dZoneData(zoneId, organization); @@ -167,7 +174,7 @@ const DisplayZone: React.FC = ({ useDroppedObjectsStore.getState().addObject(zoneName, val); }); } - + setSelectedZone({ zoneName, activeSides: response.activeSides || [], @@ -178,15 +185,18 @@ const DisplayZone: React.FC = ({ zoneViewPortTarget: response.viewPortCenter || {}, zoneViewPortPosition: response.viewPortposition || {}, }); - } catch (error) { - - } + } catch (error) {} } return (
{/* Left Arrow */} {showLeftArrow && ( @@ -196,8 +206,8 @@ const DisplayZone: React.FC = ({ )} {/* Scrollable Zones Container */} -
@@ -206,8 +216,12 @@ const DisplayZone: React.FC = ({ {Object.keys(zonesData).map((zoneName, index) => (
handleSelect2dZoneData(zonesData[zoneName]?.zoneId, zoneName)} + className={`zone ${ + selectedZone.zoneName === zoneName ? "active" : "" + }`} + onClick={() => + handleSelect2dZoneData(zonesData[zoneName]?.zoneId, zoneName) + } > {zoneName}
diff --git a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx index 9ac1a05..0d3530f 100644 --- a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx +++ b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx @@ -49,7 +49,7 @@ const DroppedObjects: React.FC = () => { const { visualizationSocket } = useSocketStore(); const { isPlaying } = usePlayButtonStore(); const zones = useDroppedObjectsStore((state) => state.zones); - console.log('zones: ', zones); + const [openKebabId, setOpenKebabId] = useState(null); const updateObjectPosition = useDroppedObjectsStore( (state) => state.updateObjectPosition @@ -568,6 +568,7 @@ const DroppedObjects: React.FC = () => { left: leftPosition, right: rightPosition, bottom: bottomPosition, + pointerEvents: isPlaying ? "none" : "auto", }} onPointerDown={(event) => { setSelectedChartId(obj); diff --git a/app/src/components/ui/componets/RealTimeVisulization.tsx b/app/src/components/ui/componets/RealTimeVisulization.tsx index c594eb7..c78e985 100644 --- a/app/src/components/ui/componets/RealTimeVisulization.tsx +++ b/app/src/components/ui/componets/RealTimeVisulization.tsx @@ -7,7 +7,7 @@ import DisplayZone from "./DisplayZone"; import Scene from "../../../modules/scene/scene"; import useModuleStore from "../../../store/useModuleStore"; -import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore"; +import { useDroppedObjectsStore, useFloatingWidget } from "../../../store/useDroppedObjectsStore"; import { useAsset3dWidget, useSocketStore, @@ -73,9 +73,8 @@ const RealTimeVisulization: React.FC = () => { const { rightClickSelected, setRightClickSelected } = useRightClickSelected(); const [openConfirmationPopup, setOpenConfirmationPopup] = useState(false); - const [floatingWidgets, setFloatingWidgets] = useState< - Record - >({}); + // const [floatingWidgets, setFloatingWidgets] = useState>({}); + const { floatingWidget, setFloatingWidget } = useFloatingWidget() const { widgetSelect, setWidgetSelect } = useAsset3dWidget(); const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption(); const { visualizationSocket } = useSocketStore(); @@ -135,7 +134,6 @@ const RealTimeVisulization: React.FC = () => { const handleDrop = async (event: React.DragEvent) => { event.preventDefault(); - try { event.preventDefault(); const email = localStorage.getItem("email") || ""; @@ -181,6 +179,25 @@ const RealTimeVisulization: React.FC = () => { if (visualizationSocket) { visualizationSocket.emit("v2:viz-float:add", addFloatingWidget); } + useDroppedObjectsStore + .getState() + .addObject(selectedZone.zoneName, newObject); + + //I need to console here objects based on selectedZone.zoneId + // Console the objects after adding + const droppedObjectsStore = useDroppedObjectsStore.getState(); + const currentZone = droppedObjectsStore.zones[selectedZone.zoneName]; + + if (currentZone && currentZone.zoneId === selectedZone.zoneId) { + console.log( + `Objects for Zone ID: ${selectedZone.zoneId}`, + currentZone.objects + ); + setFloatingWidget(currentZone.objects) + } else { + console.warn("Zone not found or mismatched zoneId"); + } + // let response = await addingFloatingWidgets( // selectedZone.zoneId, // organization, @@ -188,24 +205,12 @@ const RealTimeVisulization: React.FC = () => { // ); // Add the dropped object to the zone if the API call is successful // if (response.message === "FloatWidget created successfully") { - useDroppedObjectsStore - .getState() - .addObject(selectedZone.zoneName, newObject); // } + // Update floating widgets state - setFloatingWidgets((prevWidgets) => ({ - ...prevWidgets, - [selectedZone.zoneName]: { - ...prevWidgets[selectedZone.zoneName], - zoneName: selectedZone.zoneName, - zoneId: selectedZone.zoneId, - objects: [ - ...(prevWidgets[selectedZone.zoneName]?.objects || []), - newObject, - ], - }, - })); - } catch (error) {} + + } catch (error) { } + }; useEffect(() => { @@ -289,6 +294,8 @@ const RealTimeVisulization: React.FC = () => { zonesData={zonesData} selectedZone={selectedZone} setSelectedZone={setSelectedZone} + hiddenPanels={hiddenPanels} + setHiddenPanels={setHiddenPanels} /> {!isPlaying && selectedZone?.zoneName !== "" && ( diff --git a/app/src/components/ui/componets/zoneAssets.tsx b/app/src/components/ui/componets/zoneAssets.tsx index daa5a60..e2ec994 100644 --- a/app/src/components/ui/componets/zoneAssets.tsx +++ b/app/src/components/ui/componets/zoneAssets.tsx @@ -12,25 +12,66 @@ export default function ZoneAssets() { if (!zoneAssetId) return console.log('zoneAssetId: ', zoneAssetId); let AssetMesh = scene.getObjectByProperty("uuid", zoneAssetId.id); - if (!AssetMesh) return; + if (AssetMesh) { + const bbox = new THREE.Box3().setFromObject(AssetMesh); + const size = bbox.getSize(new THREE.Vector3()); + const center = bbox.getCenter(new THREE.Vector3()); - const bbox = new THREE.Box3().setFromObject(AssetMesh); - const size = bbox.getSize(new THREE.Vector3()); - const center = bbox.getCenter(new THREE.Vector3()); + const front = new THREE.Vector3(0, 0, 1); + AssetMesh.localToWorld(front); + front.sub(AssetMesh.position).normalize(); - const front = new THREE.Vector3(0, 0, 1); - AssetMesh.localToWorld(front); - front.sub(AssetMesh.position).normalize(); + const distance = Math.max(size.x, size.y, size.z) * 2; + const newPosition = center.clone().addScaledVector(front, distance); - const distance = Math.max(size.x, size.y, size.z) * 2; - const newPosition = center.clone().addScaledVector(front, distance); + controls.setPosition(newPosition.x, newPosition.y, newPosition.z, true); + controls.setTarget(center.x, center.y, center.z, true); + controls.fitToBox(AssetMesh, true, { cover: true, paddingTop: 5, paddingLeft: 5, paddingBottom: 5, paddingRight: 5, }); - controls.setPosition(newPosition.x, newPosition.y, newPosition.z, true); - controls.setTarget(center.x, center.y, center.z, true); - controls.fitToBox(AssetMesh, true, { cover: true, paddingTop: 5, paddingLeft: 5, paddingBottom: 5, paddingRight: 5, }); + setSelectedFloorItem(AssetMesh); + } else { + console.log('zoneAssetId: ', zoneAssetId) + if (Array.isArray(zoneAssetId.position) && zoneAssetId.position.length >= 3) { + let selectedAssetPosition = [ + zoneAssetId.position[0], + 10, + zoneAssetId.position[2] + ]; + console.log('selectedAssetPosition: ', selectedAssetPosition); + let selectedAssetTarget = [ + zoneAssetId.position[0], + zoneAssetId.position[1], + zoneAssetId.position[2] + ]; + console.log('selectedAssetTarget: ', selectedAssetTarget); + const setCam = async () => { + await controls?.setLookAt(...selectedAssetPosition, ...selectedAssetTarget, true); + setTimeout(() => { + let AssetMesh = scene.getObjectByProperty("uuid", zoneAssetId.id); + if (AssetMesh) { + const bbox = new THREE.Box3().setFromObject(AssetMesh); + const size = bbox.getSize(new THREE.Vector3()); + const center = bbox.getCenter(new THREE.Vector3()); - setSelectedFloorItem(AssetMesh); + const front = new THREE.Vector3(0, 0, 1); + AssetMesh.localToWorld(front); + front.sub(AssetMesh.position).normalize(); + const distance = Math.max(size.x, size.y, size.z) * 2; + const newPosition = center.clone().addScaledVector(front, distance); + + controls.setPosition(newPosition.x, newPosition.y, newPosition.z, true); + controls.setTarget(center.x, center.y, center.z, true); + controls.fitToBox(AssetMesh, true, { cover: true, paddingTop: 5, paddingLeft: 5, paddingBottom: 5, paddingRight: 5, }); + + setSelectedFloorItem(AssetMesh); + } + }, 500) + + }; + setCam(); + } + } }, [zoneAssetId, scene, controls]) diff --git a/app/src/components/ui/list/DropDownList.tsx b/app/src/components/ui/list/DropDownList.tsx index faa5f4e..b2f05b9 100644 --- a/app/src/components/ui/list/DropDownList.tsx +++ b/app/src/components/ui/list/DropDownList.tsx @@ -4,6 +4,7 @@ import { AddIcon, ArrowIcon, FocusIcon } from "../../icons/ExportCommonIcons"; import KebabMenuListMultiSelect from "./KebebMenuListMultiSelect"; import { useFloorItems, useZones } from "../../../store/store"; import { useSelectedZoneStore } from "../../../store/useZoneStore"; +import { getZone2dData } from "../../../services/realTimeVisulization/zoneData/getZoneData"; interface DropDownListProps { value?: string; // Value to display in the DropDownList @@ -52,10 +53,10 @@ const DropDownList: React.FC = ({ interface ZoneData { id: string; name: string; - assets: { id: string; name: string; position?: [] ;rotation?:{}}[]; + assets: { id: string; name: string; position?: []; rotation?: {} }[]; } const [zoneDataList, setZoneDataList] = useState([]); - const { floorItems, setFloorItems } = useFloorItems(); + const { floorItems } = useFloorItems(); const isPointInsidePolygon = (point: [number, number], polygon: [number, number][]) => { let inside = false; @@ -70,9 +71,9 @@ const DropDownList: React.FC = ({ } return inside; }; - useEffect(() => { - const updatedZoneList: ZoneData[] = zones.map((zone: Zone) => { + useEffect(() => { + const updatedZoneList: ZoneData[] = zones?.map((zone: Zone) => { const polygon2D = zone.points.map((p: [number, number, number]) => [p[0], p[2]]) as [number, number][]; const assetsInZone = floorItems @@ -84,7 +85,7 @@ const DropDownList: React.FC = ({ id: item.modeluuid, name: item.modelname, position: item.position, - rotation:item.rotation + rotation: item.rotation })); return { @@ -96,9 +97,6 @@ const DropDownList: React.FC = ({ setZoneDataList(updatedZoneList); }, [zones, floorItems]); - - - return (
diff --git a/app/src/components/ui/list/List.tsx b/app/src/components/ui/list/List.tsx index a176e14..06bc129 100644 --- a/app/src/components/ui/list/List.tsx +++ b/app/src/components/ui/list/List.tsx @@ -13,7 +13,9 @@ import { RmoveIcon, } from "../../icons/ExportCommonIcons"; import { useThree } from "@react-three/fiber"; -import { useZoneAssetId } from "../../../store/store"; +import { useFloorItems, useZoneAssetId } from "../../../store/store"; +import { zoneCameraUpdate } from "../../../services/realTimeVisulization/zoneData/zoneCameraUpdation"; +import { setFloorItemApi } from "../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi"; interface Asset { id: string; @@ -38,11 +40,12 @@ const List: React.FC = ({ items = [], remove }) => { const { activeModule, setActiveModule } = useModuleStore(); const { selectedZone, setSelectedZone } = useSelectedZoneStore(); const { zoneAssetId, setZoneAssetId } = useZoneAssetId(); + const { setSubModule } = useSubModuleStore(); const [expandedZones, setExpandedZones] = useState>( {} ); - + const { floorItems, setFloorItems } = useFloorItems(); useEffect(() => { useSelectedZoneStore.getState().setSelectedZone({ @@ -67,7 +70,7 @@ const List: React.FC = ({ items = [], remove }) => { async function handleSelectZone(id: string) { try { if (selectedZone?.zoneId === id) { - console.log("Zone is already selected:", selectedZone.zoneName); + return; } @@ -89,19 +92,52 @@ const List: React.FC = ({ items = [], remove }) => { zoneViewPortPosition: response?.viewPortposition || [], }); - console.log("Zone selected:", response?.zoneName); + } catch (error) { - console.error("Error selecting zone:", error); + } } function handleAssetClick(asset: Asset) { setZoneAssetId(asset) } + async function handleZoneNameChange(newName: string) { + //zone apiiiiii + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; + let zonesdata = { + zoneId: selectedZone.zoneId, + zoneName: newName + }; + let response = await zoneCameraUpdate(zonesdata, organization); + if (response.message === "updated successfully") { + setSelectedZone((prev) => ({ ...prev, zoneName: newName })); + } + } + async function handleZoneAssetName(newName: string) { + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; + + if (zoneAssetId?.id) { + let response = await setFloorItemApi(organization, zoneAssetId.id, newName) + console.log('response: ', response); + setFloorItems((prevFloorItems: any[]) => + prevFloorItems.map((floorItems) => + floorItems.modeluuid === zoneAssetId.id + ? { ...floorItems, modelname: response.modelname } + : floorItems + ) + ); + } + + console.log('newName: ', newName); + + } + return ( <> - {items.length > 0 ? ( + {items?.length > 0 ? (
    - {items.map((item) => ( + {items?.map((item) => (
  • @@ -110,7 +146,7 @@ const List: React.FC = ({ items = [], remove }) => { className="value" onClick={() => handleSelectZone(item.id)} > - +
@@ -147,8 +183,8 @@ const List: React.FC = ({ items = [], remove }) => { className="list-container asset-item" >
-
handleAssetClick(asset)}> - +
handleAssetClick(asset)} > +
diff --git a/app/src/components/ui/realTimeVis/floating/TotalCardComponent.tsx b/app/src/components/ui/realTimeVis/floating/TotalCardComponent.tsx index da03fce..1dfab66 100644 --- a/app/src/components/ui/realTimeVis/floating/TotalCardComponent.tsx +++ b/app/src/components/ui/realTimeVis/floating/TotalCardComponent.tsx @@ -1,103 +1,96 @@ -import React, { useState, useEffect } from 'react' -import { Line } from 'react-chartjs-2' -import useChartStore from '../../../../store/useChartStore'; -import { useWidgetStore } from '../../../../store/useWidgetStore'; -import axios from 'axios'; +import React, { useState, useEffect } from "react"; +import { Line } from "react-chartjs-2"; +import useChartStore from "../../../../store/useChartStore"; +import { useWidgetStore } from "../../../../store/useWidgetStore"; +import axios from "axios"; import io from "socket.io-client"; -import { WalletIcon } from '../../../icons/3dChartIcons'; +import { WalletIcon } from "../../../icons/3dChartIcons"; +const TotalCardComponent = ({ object }: any) => { + const [progress, setProgress] = useState(0); + const [measurements, setmeasurements] = useState({}); + const [duration, setDuration] = useState("1h"); + const [name, setName] = useState(object.header ? object.header : ""); + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; + const { header, flotingDuration, flotingMeasurements } = useChartStore(); + const { selectedChartId } = useWidgetStore(); -const TotalCardComponent = ({ - object -}: any) => { + const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; - const [ progress, setProgress ] = useState(0) - const [measurements, setmeasurements] = useState({}); - const [duration, setDuration] = useState("1h") - const [name, setName] = useState(object.header ? object.header : '') - const email = localStorage.getItem("email") || ""; - const organization = email?.split("@")[1]?.split(".")[0] - const { header, flotingDuration, flotingMeasurements } = useChartStore(); - const { selectedChartId } = useWidgetStore(); + useEffect(() => { + if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) + return; - const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; + const socket = io(`http://${iotApiUrl}`); - useEffect(() => { - if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return; - - const socket = io(`http://${iotApiUrl}`); - - const inputData = { - measurements, - duration, - interval: 1000, - }; - - - const startStream = () => { - socket.emit("lastInput", inputData); - }; - - socket.on("connect", startStream); - - socket.on("lastOutput", (response) => { - const responseData = response.input1; - - if (typeof responseData === "number") { - setProgress(responseData); - } - }); - - return () => { - socket.off("lastOutput"); - socket.emit("stop_stream"); // Stop streaming when component unmounts - socket.disconnect(); - }; - }, [measurements, duration, iotApiUrl]); - - const fetchSavedInputes = async() => { - - if (object?.id !== "") { - try { - const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${object?.id}/${organization}`); - if (response.status === 200) { - setmeasurements(response.data.Data.measurements) - setDuration(response.data.Data.duration) - setName(response.data.header) - } else { - console.log("Unexpected response:", response); - } - } catch (error) { - console.error("There was an error!", error); - } - } + const inputData = { + measurements, + duration, + interval: 1000, + }; + + const startStream = () => { + socket.emit("lastInput", inputData); + }; + + socket.on("connect", startStream); + + socket.on("lastOutput", (response) => { + const responseData = response.input1; + + if (typeof responseData === "number") { + setProgress(responseData); } - - useEffect(() => { - fetchSavedInputes(); - }, []); - - useEffect(() => { - if (selectedChartId?.id === object?.id) { - fetchSavedInputes(); + }); + + return () => { + socket.off("lastOutput"); + socket.emit("stop_stream"); // Stop streaming when component unmounts + socket.disconnect(); + }; + }, [measurements, duration, iotApiUrl]); + + const fetchSavedInputes = async () => { + if (object?.id !== "") { + try { + const response = await axios.get( + `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${object?.id}/${organization}` + ); + if (response.status === 200) { + setmeasurements(response.data.Data.measurements); + setDuration(response.data.Data.duration); + setName(response.data.header); + } else { } - } - ,[header, flotingDuration, flotingMeasurements]) + } catch (error) {} + } + }; - return ( - <> -
-
{name}
-
-
{progress}
-
{object.per}
-
-
-
- -
- - ) -} + useEffect(() => { + fetchSavedInputes(); + }, []); -export default TotalCardComponent \ No newline at end of file + useEffect(() => { + if (selectedChartId?.id === object?.id) { + fetchSavedInputes(); + } + }, [header, flotingDuration, flotingMeasurements]); + + return ( + <> +
+
{name}
+
+
{progress}
+
{object.per}
+
+
+
+ +
+ + ); +}; + +export default TotalCardComponent; diff --git a/app/src/modules/builder/agv/navMeshDetails.tsx b/app/src/modules/builder/agv/navMeshDetails.tsx index ae95942..697d89b 100644 --- a/app/src/modules/builder/agv/navMeshDetails.tsx +++ b/app/src/modules/builder/agv/navMeshDetails.tsx @@ -32,7 +32,7 @@ export default function NavMeshDetails({ const [positions, indices] = getPositionsAndIndices(meshes); - const cellSize = 0.35; + const cellSize = 0.2; const cellHeight = 0.7; const walkableRadius = 0.5; const { success, navMesh } = generateSoloNavMesh(positions, indices, { diff --git a/app/src/modules/builder/geomentries/assets/addAssetModel.ts b/app/src/modules/builder/geomentries/assets/addAssetModel.ts index d66d019..d109eb8 100644 --- a/app/src/modules/builder/geomentries/assets/addAssetModel.ts +++ b/app/src/modules/builder/geomentries/assets/addAssetModel.ts @@ -86,8 +86,8 @@ async function addAssetModel( } else { // console.log(`Added ${selectedItem.name} from Backend`); - loader.load(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`, async (gltf) => { - const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`).then((res) => res.blob()); + loader.load(`${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`, async (gltf) => { + const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`).then((res) => res.blob()); await storeGLTF(selectedItem.id, modelBlob); THREE.Cache.add(selectedItem.id, gltf); await handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationStates, socket); @@ -235,6 +235,7 @@ async function handleModelLoad( points: { uuid: pointUUID, position: res.points.position as [number, number, number], + rotation: res.points.rotation as [number, number, number], actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: '', start: {}, hitCount: 1, end: {}, buffer: 0 }, connections: { source: { modelUUID: model.uuid, pointUUID: pointUUID }, targets: [] }, speed: 2, @@ -297,6 +298,7 @@ async function handleModelLoad( points: { uuid: pointUUID, position: res.points.position as [number, number, number], + rotation: res.points.rotation as [number, number, number], actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', buffer: 0, material: 'Inherit' }, triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' }, connections: { source: { modelUUID: model.uuid, pointUUID: pointUUID }, targets: [] }, @@ -360,6 +362,7 @@ async function handleModelLoad( points: { uuid: pointUUID, position: res.points.position as [number, number, number], + rotation: res.points.rotation as [number, number, number], actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', speed: 1, processes: [] }, triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' }, connections: { source: { modelUUID: model.uuid, pointUUID: pointUUID }, targets: [] }, diff --git a/app/src/modules/builder/geomentries/assets/assetManager.ts b/app/src/modules/builder/geomentries/assets/assetManager.ts index 240e7a1..5ff75a3 100644 --- a/app/src/modules/builder/geomentries/assets/assetManager.ts +++ b/app/src/modules/builder/geomentries/assets/assetManager.ts @@ -53,7 +53,7 @@ export default async function assetManager( if (!activePromises.get(taskId)) return; // Stop processing if task is canceled await new Promise(async (resolve) => { - const modelUrl = `${url_Backend_dwinzo}/api/v1/AssetFile/${item.modelfileID!}`; + const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.modelfileID!}`; // Check Three.js Cache const cachedModel = THREE.Cache.get(item.modelfileID!); diff --git a/app/src/modules/collaboration/socketResponses.dev.tsx b/app/src/modules/collaboration/socketResponses.dev.tsx index ceef567..6e578a1 100644 --- a/app/src/modules/collaboration/socketResponses.dev.tsx +++ b/app/src/modules/collaboration/socketResponses.dev.tsx @@ -105,7 +105,7 @@ export default function SocketResponses({ // console.log(`Getting ${data.data.modelname} from cache`); const model = cachedModel.scene.clone(); model.uuid = data.data.modeluuid; - model.userData = { name: data.data.modelname, modelId: data.data.modelFileID, modeluuid: data.data.modeluuid }; + model.userData = { name: data.data.modelname, modelId: data.data.modelfileID, modeluuid: data.data.modeluuid }; model.position.set(...data.data.position as [number, number, number]); model.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z); model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); @@ -159,7 +159,7 @@ export default function SocketResponses({ url = URL.createObjectURL(indexedDBModel); } else { // console.log(`Getting ${data.data.modelname} from Backend`); - url = `${url_Backend_dwinzo}/api/v1/AssetFile/${data.data.modelfileID}`; + url = `${url_Backend_dwinzo}/api/v2/AssetFile/${data.data.modelfileID}`; const modelBlob = await fetch(url).then((res) => res.blob()); await storeGLTF(data.data.modelfileID, modelBlob); } @@ -179,7 +179,7 @@ export default function SocketResponses({ THREE.Cache.remove(url); const model = gltf.scene; model.uuid = data.data.modeluuid; - model.userData = { name: data.data.modelname, modelId: data.data.modelFileID, modeluuid: data.data.modeluuid }; + model.userData = { name: data.data.modelname, modelId: data.data.modelfileID, modeluuid: data.data.modeluuid }; model.position.set(...data.data.position as [number, number, number]); model.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z); model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); diff --git a/app/src/modules/scene/IntialLoad/loadInitialFloorItems.ts b/app/src/modules/scene/IntialLoad/loadInitialFloorItems.ts index c90fe3b..ea5ea74 100644 --- a/app/src/modules/scene/IntialLoad/loadInitialFloorItems.ts +++ b/app/src/modules/scene/IntialLoad/loadInitialFloorItems.ts @@ -12,7 +12,7 @@ import { getFloorAssets } from '../../../services/factoryBuilder/assest/floorAss async function loadInitialFloorItems( itemsGroup: Types.RefGroup, setFloorItems: Types.setFloorItemSetState, - setSimulationStates: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => void + setSimulationStates: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => void ): Promise { if (!itemsGroup.current) return; let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; @@ -82,16 +82,14 @@ async function loadInitialFloorItems( if (indexedDBModel) { // console.log(`[IndexedDB] Fetching ${item.modelname}`); const blobUrl = URL.createObjectURL(indexedDBModel); - loader.load( - blobUrl, - (gltf) => { - URL.revokeObjectURL(blobUrl); - THREE.Cache.remove(blobUrl); - THREE.Cache.add(item.modelfileID!, gltf); - processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationStates); - modelsLoaded++; - checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); - }, + loader.load(blobUrl, (gltf) => { + URL.revokeObjectURL(blobUrl); + THREE.Cache.remove(blobUrl); + THREE.Cache.add(item.modelfileID!, gltf); + processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationStates); + modelsLoaded++; + checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); + }, undefined, (error) => { toast.error(`[IndexedDB] Error loading ${item.modelname}:`); @@ -104,17 +102,15 @@ async function loadInitialFloorItems( // Fetch from Backend // console.log(`[Backend] Fetching ${item.modelname}`); - const modelUrl = `${url_Backend_dwinzo}/api/v1/AssetFile/${item.modelfileID!}`; - loader.load( - modelUrl, - async (gltf) => { - 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, setSimulationStates); - modelsLoaded++; - checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); - }, + const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.modelfileID!}`; + loader.load(modelUrl, async (gltf) => { + 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, setSimulationStates); + modelsLoaded++; + checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); + }, undefined, (error) => { toast.error(`[Backend] Error loading ${item.modelname}:`); @@ -137,7 +133,7 @@ async function loadInitialFloorItems( }, ]); - if (item.eventData || item.modelfileID === '67e3db95c2e8f37134526fb2') { + if (item.eventData) { processEventData(item, setSimulationStates); } @@ -157,7 +153,7 @@ function processLoadedModel( item: Types.EventData, itemsGroup: Types.RefGroup, setFloorItems: Types.setFloorItemSetState, - setSimulationStates: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => void + setSimulationStates: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => void ) { const model = gltf; model.uuid = item.modeluuid; @@ -192,7 +188,7 @@ function processLoadedModel( }, ]); - if (item.eventData || item.modelfileID === '67e3db5ac2e8f37134526f40') { + if (item.eventData) { processEventData(item, setSimulationStates); } @@ -221,6 +217,7 @@ function processEventData(item: Types.EventData, setSimulationStates: any) { data.modeluuid = item.modeluuid; data.modelName = item.modelname; data.position = item.position; + data.rotation = [item.rotation.x, item.rotation.y, item.rotation.z]; setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => [ ...(prevEvents || []), diff --git a/app/src/modules/scene/controls/selection/copyPasteControls.tsx b/app/src/modules/scene/controls/selection/copyPasteControls.tsx index d315c10..5af10c0 100644 --- a/app/src/modules/scene/controls/selection/copyPasteControls.tsx +++ b/app/src/modules/scene/controls/selection/copyPasteControls.tsx @@ -263,6 +263,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas return { uuid: pointUUID, position: vehiclePoint?.position, + rotation: vehiclePoint?.rotation, actions: hasActions ? { ...vehiclePoint.actions, @@ -315,6 +316,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas newEventData.modeluuid = newFloorItem.modeluuid; newEventData.modelName = newFloorItem.modelname; newEventData.position = newFloorItem.position; + newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => [ ...(prevEvents || []), @@ -339,12 +341,14 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas return { uuid: pointUUID, position: vehiclePoint?.position, + rotation: vehiclePoint?.rotation, actions: hasActions ? { ...vehiclePoint.actions, uuid: THREE.MathUtils.generateUUID() } : defaultAction, + triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' }, connections: { source: { modelUUID: obj.uuid, pointUUID }, targets: [] @@ -415,6 +419,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas return { uuid: pointUUID, position: vehiclePoint?.position, + rotation: vehiclePoint?.rotation, actions: hasActions ? { ...vehiclePoint.actions, diff --git a/app/src/modules/scene/controls/selection/duplicationControls.tsx b/app/src/modules/scene/controls/selection/duplicationControls.tsx index 9c987d0..2964181 100644 --- a/app/src/modules/scene/controls/selection/duplicationControls.tsx +++ b/app/src/modules/scene/controls/selection/duplicationControls.tsx @@ -245,6 +245,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb return { uuid: pointUUID, position: vehiclePoint?.position, + rotation: vehiclePoint?.rotation, actions: hasActions ? { ...vehiclePoint.actions, @@ -297,6 +298,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb newEventData.modeluuid = newFloorItem.modeluuid; newEventData.modelName = newFloorItem.modelname; newEventData.position = newFloorItem.position; + newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => [ ...(prevEvents || []), @@ -321,12 +323,14 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb return { uuid: pointUUID, position: vehiclePoint?.position, + rotation: vehiclePoint?.rotation, actions: hasActions ? { ...vehiclePoint.actions, uuid: THREE.MathUtils.generateUUID() } : defaultAction, + triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' }, connections: { source: { modelUUID: obj.uuid, pointUUID }, targets: [] @@ -397,6 +401,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb return { uuid: pointUUID, position: vehiclePoint?.position, + rotation: vehiclePoint?.rotation, actions: hasActions ? { ...vehiclePoint.actions, diff --git a/app/src/modules/scene/controls/selection/moveControls.tsx b/app/src/modules/scene/controls/selection/moveControls.tsx index 97ddb17..2a11c53 100644 --- a/app/src/modules/scene/controls/selection/moveControls.tsx +++ b/app/src/modules/scene/controls/selection/moveControls.tsx @@ -279,6 +279,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje newEventData.modeluuid = newFloorItem.modeluuid; newEventData.modelName = newFloorItem.modelname; newEventData.position = newFloorItem.position; + newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => { const updatedEvents = (prevEvents || []).map(event => diff --git a/app/src/modules/scene/controls/selection/rotateControls.tsx b/app/src/modules/scene/controls/selection/rotateControls.tsx index 0680f28..90143ca 100644 --- a/app/src/modules/scene/controls/selection/rotateControls.tsx +++ b/app/src/modules/scene/controls/selection/rotateControls.tsx @@ -284,6 +284,7 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo newEventData.modeluuid = newFloorItem.modeluuid; newEventData.modelName = newFloorItem.modelname; newEventData.position = newFloorItem.position; + newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => { const updatedEvents = (prevEvents || []).map(event => diff --git a/app/src/modules/scene/controls/selection/selectionControls.tsx b/app/src/modules/scene/controls/selection/selectionControls.tsx index 686bf42..11c2dfb 100644 --- a/app/src/modules/scene/controls/selection/selectionControls.tsx +++ b/app/src/modules/scene/controls/selection/selectionControls.tsx @@ -122,10 +122,15 @@ const SelectionControls: React.FC = () => { if (!toggleView && activeModule === "builder") { helper.enabled = true; - canvasElement.addEventListener("pointerdown", onPointerDown); - canvasElement.addEventListener("pointermove", onPointerMove); + if (duplicatedObjects.length === 0 && pastedObjects.length === 0) { + canvasElement.addEventListener("pointerdown", onPointerDown); + canvasElement.addEventListener("pointermove", onPointerMove); + canvasElement.addEventListener("pointerup", onPointerUp); + } else { + helper.enabled = false; + helper.dispose(); + } canvasElement.addEventListener("contextmenu", onContextMenu); - canvasElement.addEventListener("pointerup", onPointerUp); canvasElement.addEventListener("keydown", onKeyDown); } else { helper.enabled = false; diff --git a/app/src/modules/simulation/path/pathConnector.tsx b/app/src/modules/simulation/path/pathConnector.tsx index bb4c039..c561cbb 100644 --- a/app/src/modules/simulation/path/pathConnector.tsx +++ b/app/src/modules/simulation/path/pathConnector.tsx @@ -952,8 +952,17 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec ); }) }, - // Ensure all required ArmBot point properties are included - actions: state.points.actions, + actions: { + ...state.points.actions, + processes: state.points.actions.processes?.filter(process => { + return !( + process.startPoint === connection1.point || + process.endPoint === connection1.point || + process.startPoint === connection2.point || + process.endPoint === connection2.point + ); + }) || [] + }, triggers: state.points.triggers } }; diff --git a/app/src/modules/visualization/captureVisualization.ts b/app/src/modules/visualization/captureVisualization.ts index 9927d0e..e1fac77 100644 --- a/app/src/modules/visualization/captureVisualization.ts +++ b/app/src/modules/visualization/captureVisualization.ts @@ -2,19 +2,32 @@ import html2canvas from "html2canvas"; export const captureVisualization = async (): Promise => { const container = document.getElementById("real-time-vis-canvas"); - if (!container) return null; + if (!container) { + console.error("Container element not found"); + return null; + } try { - // Use html2canvas to capture the container + // Hide any elements you don't want in the screenshot + const originalVisibility = container.style.visibility; + container.style.visibility = 'visible'; + const canvas = await html2canvas(container, { - scale: 1, // Adjust scale for higher/lower resolution + scale: 2, // Higher scale for better quality + logging: false, // Disable console logging + useCORS: true, // Handle cross-origin images + allowTaint: true, // Allow tainted canvas + backgroundColor: '#ffffff', // Set white background + removeContainer: true // Clean up temporary containers }); - // Convert the canvas to a data URL (PNG format) - const dataUrl = canvas.toDataURL("image/png"); - return dataUrl; + // Restore original visibility + container.style.visibility = originalVisibility; + + // Convert to PNG with highest quality + return canvas.toDataURL('image/png', 1.0); } catch (error) { console.error("Error capturing visualization:", error); return null; } -}; +}; \ No newline at end of file diff --git a/app/src/modules/visualization/handleSaveTemplate.ts b/app/src/modules/visualization/handleSaveTemplate.ts index f5423b9..3b4fc89 100644 --- a/app/src/modules/visualization/handleSaveTemplate.ts +++ b/app/src/modules/visualization/handleSaveTemplate.ts @@ -1,5 +1,3 @@ -import { saveTemplateApi } from "../../services/realTimeVisulization/zoneData/saveTempleteApi"; -import { useSocketStore } from "../../store/store"; import { Template } from "../../store/useTemplateStore"; import { captureVisualization } from "./captureVisualization"; @@ -28,6 +26,7 @@ export const handleSaveTemplate = async ({ templates = [], visualizationSocket, }: HandleSaveTemplateProps): Promise => { + console.log("floatingWidget: ", floatingWidget); try { // Check if the selected zone has any widgets if (!selectedZone.panelOrder || selectedZone.panelOrder.length === 0) { @@ -50,9 +49,10 @@ export const handleSaveTemplate = async ({ // Capture visualization snapshot const snapshot = await captureVisualization(); - // if (!snapshot) { - // return; - // } + if (!snapshot) { + return; + } + // Create a new template const newTemplate: Template = { id: generateUniqueId(), diff --git a/app/src/modules/visualization/realTimeVizSocket.dev.tsx b/app/src/modules/visualization/realTimeVizSocket.dev.tsx index 9ee6b5b..f1abaaa 100644 --- a/app/src/modules/visualization/realTimeVizSocket.dev.tsx +++ b/app/src/modules/visualization/realTimeVizSocket.dev.tsx @@ -15,22 +15,19 @@ type WidgetData = { export default function SocketRealTimeViz() { const { visualizationSocket } = useSocketStore(); - const { selectedZone, setSelectedZone } = useSelectedZoneStore(); + const { setSelectedZone } = useSelectedZoneStore(); const deleteObject = useDroppedObjectsStore((state) => state.deleteObject); - const duplicateObject = useDroppedObjectsStore((state) => state.duplicateObject); const updateObjectPosition = useDroppedObjectsStore((state) => state.updateObjectPosition); const { addWidget } = useZoneWidgetStore() - const { templates, removeTemplate } = useTemplateStore(); + const { removeTemplate } = useTemplateStore(); const { setTemplates } = useTemplateStore(); const { zoneWidgetData, setZoneWidgetData, updateWidgetPosition, updateWidgetRotation } = useZoneWidgetStore(); useEffect(() => { - const email = localStorage.getItem("email") || ""; - const organization = email?.split("@")[1]?.split(".")[0]; if (visualizationSocket) { //add panel response visualizationSocket.on("viz-panel:response:updates", (addPanel: any) => { - console.log('addPanel: ', addPanel); + if (addPanel.success) { let addPanelData = addPanel.data.data setSelectedZone(addPanelData) @@ -38,15 +35,33 @@ export default function SocketRealTimeViz() { }) //delete panel response visualizationSocket.on("viz-panel:response:delete", (deletePanel: any) => { - console.log('deletePanel: ', deletePanel); + if (deletePanel.success) { let deletePanelData = deletePanel.data.data setSelectedZone(deletePanelData) } }) + //clear Panel response + visualizationSocket.on("viz-panel:response:clear", (clearPanel: any) => { + + if (clearPanel.success && clearPanel.message === "PanelWidgets cleared successfully") { + + let clearPanelData = clearPanel.data.data + setSelectedZone(clearPanelData) + } + }) + //lock Panel response + visualizationSocket.on("viz-panel:response:locked", (lockPanel: any) => { + + if (lockPanel.success && lockPanel.message === "locked panel updated successfully") { + + let lockPanelData = lockPanel.data.data + setSelectedZone(lockPanelData) + } + }) // add 2dWidget response visualizationSocket.on("viz-widget:response:updates", (add2dWidget: any) => { - console.log('add2dWidget: ', add2dWidget); + if (add2dWidget.success && add2dWidget.data) { setSelectedZone((prev) => { @@ -65,7 +80,7 @@ export default function SocketRealTimeViz() { }); //delete 2D Widget response visualizationSocket.on("viz-widget:response:delete", (deleteWidget: any) => { - console.log('deleteWidget: ', deleteWidget); + if (deleteWidget?.success && deleteWidget.data) { setSelectedZone((prevZone: any) => ({ @@ -78,7 +93,7 @@ export default function SocketRealTimeViz() { }); //add Floating Widget response visualizationSocket.on("viz-float:response:updates", (addFloatingWidget: any) => { - console.log('addFloatingWidget: ', addFloatingWidget); + if (addFloatingWidget.success) { if (addFloatingWidget.success && addFloatingWidget.message === "FloatWidget created successfully") { @@ -105,7 +120,7 @@ export default function SocketRealTimeViz() { }); //duplicate Floating Widget response visualizationSocket.on("viz-float:response:addDuplicate", (duplicateFloatingWidget: any) => { - console.log('duplicateFloatingWidget: ', duplicateFloatingWidget); + if (duplicateFloatingWidget.success && duplicateFloatingWidget.message === "duplicate FloatWidget created successfully") { useDroppedObjectsStore.setState((state) => { @@ -133,7 +148,7 @@ export default function SocketRealTimeViz() { }); //delete Floating Widget response visualizationSocket.on("viz-float:response:delete", (deleteFloatingWidget: any) => { - console.log('deleteFloatingWidget: ', deleteFloatingWidget); + if (deleteFloatingWidget.success) { deleteObject(deleteFloatingWidget.data.zoneName, deleteFloatingWidget.data.floatWidgetID); @@ -142,9 +157,9 @@ export default function SocketRealTimeViz() { //add 3D Widget response visualizationSocket.on("viz-widget3D:response:updates", (add3DWidget: any) => { - console.log('add3DWidget: ', add3DWidget); + if (add3DWidget.success) { - console.log('add3DWidget: ', add3DWidget); + if (add3DWidget.message === "Widget created successfully") { addWidget(add3DWidget.data.zoneId, add3DWidget.data.widget); } @@ -152,7 +167,7 @@ export default function SocketRealTimeViz() { }); //delete 3D Widget response visualizationSocket.on("viz-widget3D:response:delete", (delete3DWidget: any) => { - console.log('delete3DWidget: ', delete3DWidget); + // "3DWidget delete unsuccessfull" if (delete3DWidget.success && delete3DWidget.message === "3DWidget delete successfull") { const activeZoneWidgets = zoneWidgetData[delete3DWidget.data.zoneId] || []; @@ -164,16 +179,16 @@ export default function SocketRealTimeViz() { }); //update3D widget response visualizationSocket.on("viz-widget3D:response:modifyPositionRotation", (update3DWidget: any) => { - console.log('update3DWidget: ', update3DWidget); - - if (update3DWidget.success && update3DWidget.message==="widget update successfully") { + + + if (update3DWidget.success && update3DWidget.message === "widget update successfully") { updateWidgetPosition(update3DWidget.data.zoneId, update3DWidget.data.widget.id, update3DWidget.data.widget.position); updateWidgetRotation(update3DWidget.data.zoneId, update3DWidget.data.widget.id, update3DWidget.data.widget.rotation); } }); // add Template response visualizationSocket.on("viz-template:response:add", (addingTemplate: any) => { - console.log('addingTemplate: ', addingTemplate); + if (addingTemplate.success) { if (addingTemplate.message === "Template saved successfully") { @@ -183,7 +198,7 @@ export default function SocketRealTimeViz() { }); //load Template response visualizationSocket.on("viz-template:response:addTemplateZone", (loadTemplate: any) => { - console.log('loadTemplate: ', loadTemplate); + if (loadTemplate.success) { if (loadTemplate.message === "Template placed in Zone") { @@ -206,14 +221,12 @@ export default function SocketRealTimeViz() { }); //delete Template response visualizationSocket.on("viz-template:response:delete", (deleteTemplate: any) => { - console.log('deleteTemplate: ', deleteTemplate); + if (deleteTemplate.success) { if (deleteTemplate.message === 'Template deleted successfully') { removeTemplate(deleteTemplate.data); } - - } }); } diff --git a/app/src/services/factoryBuilder/assest/assets/getAssetModel.ts b/app/src/services/factoryBuilder/assest/assets/getAssetModel.ts index 4ccb6e9..ae7aaa4 100644 --- a/app/src/services/factoryBuilder/assest/assets/getAssetModel.ts +++ b/app/src/services/factoryBuilder/assest/assets/getAssetModel.ts @@ -2,7 +2,7 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL} export const getAssetModel = async (modelId: string) => { try { - const response = await fetch(`${url_Backend_dwinzo}/api/v1/AssetFile/${modelId}`, { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/AssetFile/${modelId}`, { method: "GET", headers: { "Content-Type": "application/json", diff --git a/app/src/services/factoryBuilder/assest/floorAsset/getFloorItemsApi.ts b/app/src/services/factoryBuilder/assest/floorAsset/getFloorItemsApi.ts index 7a0290a..7c78c41 100644 --- a/app/src/services/factoryBuilder/assest/floorAsset/getFloorItemsApi.ts +++ b/app/src/services/factoryBuilder/assest/floorAsset/getFloorItemsApi.ts @@ -1,5 +1,6 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + export const getFloorAssets = async (organization: string) => { try { const response = await fetch(`${url_Backend_dwinzo}/api/v2/floorAssets/${organization}`, { @@ -14,6 +15,7 @@ export const getFloorAssets = async (organization: string) => { } const result = await response.json(); + return result; } catch (error) { if (error instanceof Error) { diff --git a/app/src/services/factoryBuilder/assest/floorAsset/setFloorItemApi.ts b/app/src/services/factoryBuilder/assest/floorAsset/setFloorItemApi.ts index e25e05e..3e156cb 100644 --- a/app/src/services/factoryBuilder/assest/floorAsset/setFloorItemApi.ts +++ b/app/src/services/factoryBuilder/assest/floorAsset/setFloorItemApi.ts @@ -1,14 +1,13 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; - export const setFloorItemApi = async ( organization: string, - modeluuid: string, - modelname: string, - modelfileID: string, - position: Object, - rotation: Object, - isLocked: boolean, - isVisible: boolean, + modeluuid?: string, + modelname?: string, + modelfileID?: string, + position?: Object, + rotation?: Object, + isLocked?: boolean, + isVisible?: boolean, eventData?: any ) => { try { diff --git a/app/src/services/factoryBuilder/webWorkers/gltfLoaderWorker.js b/app/src/services/factoryBuilder/webWorkers/gltfLoaderWorker.js index 2fbdc13..9e7397d 100644 --- a/app/src/services/factoryBuilder/webWorkers/gltfLoaderWorker.js +++ b/app/src/services/factoryBuilder/webWorkers/gltfLoaderWorker.js @@ -26,7 +26,7 @@ onmessage = async (event) => { const message = "gltfLoaded"; postMessage({ message, modelID, modelBlob }); } else { - const modelUrl = `${url_Backend_dwinzo}/api/v1/AssetFile/${modelID}`; + const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${modelID}`; const modelBlob = await fetch(modelUrl).then((res) => res.blob()); await storeGLTF(modelID, modelBlob); const message = "gltfLoaded"; diff --git a/app/src/services/factoryBuilder/zones/getZonesApi.ts b/app/src/services/factoryBuilder/zones/getZonesApi.ts index be7741c..413458c 100644 --- a/app/src/services/factoryBuilder/zones/getZonesApi.ts +++ b/app/src/services/factoryBuilder/zones/getZonesApi.ts @@ -1,4 +1,5 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +// let url_Backend_dwinzo = `http://192.168.0.102:5000`; export const getZonesApi = async (organization: string) => { try { diff --git a/app/src/services/realTimeVisulization/zoneData/clearPanel.ts b/app/src/services/realTimeVisulization/zoneData/clearPanel.ts new file mode 100644 index 0000000..6e1f1d1 --- /dev/null +++ b/app/src/services/realTimeVisulization/zoneData/clearPanel.ts @@ -0,0 +1,30 @@ +// let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +let url_Backend_dwinzo = `http://192.168.0.102:5000`; +export const clearPanel = async ( + zoneId: string, + organization: string, + panelName: string +) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/clearpanel`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ organization, zoneId, panelName }), + }); + + if (!response.ok) { + throw new Error("Failed to clearPanel in the zone"); + } + + 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/realTimeVisulization/zoneData/lockPanel.ts b/app/src/services/realTimeVisulization/zoneData/lockPanel.ts new file mode 100644 index 0000000..4b5898f --- /dev/null +++ b/app/src/services/realTimeVisulization/zoneData/lockPanel.ts @@ -0,0 +1,30 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +// let url_Backend_dwinzo = `http://192.168.0.102:5000`; +export const lockPanel = async ( + zoneId: string, + organization: string, + lockedPanel: any +) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/zones/lockedPanels`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ organization, zoneId, lockedPanel }), + }); + + if (!response.ok) { + throw new Error("Failed to Lock Panel in the zone"); + } + + 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/realTimeVisulization/zoneData/update3dWidget.ts b/app/src/services/realTimeVisulization/zoneData/update3dWidget.ts index 553fc68..cb37a7f 100644 --- a/app/src/services/realTimeVisulization/zoneData/update3dWidget.ts +++ b/app/src/services/realTimeVisulization/zoneData/update3dWidget.ts @@ -9,20 +9,16 @@ export const update3dWidget = async ( console.log("organization: ", organization); console.log("zoneId: ", zoneId); try { - const response = await fetch( - `${url_Backend_dwinzo}/api/v2/modifyPR/widget3D`, - { - method: "PATCH", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - organization, - zoneId, - id, - position, - }), - } + const response = await fetch(`${url_Backend_dwinzo}/api/v2/modifyPR/widget3D`, { + method: "PATCH", + headers: { "Content-Type": "application/json", }, + body: JSON.stringify({ + organization, + zoneId, + id, + position, + }), + } ); if (!response.ok) { diff --git a/app/src/store/store.ts b/app/src/store/store.ts index 57fd6a6..8810dbe 100644 --- a/app/src/store/store.ts +++ b/app/src/store/store.ts @@ -68,7 +68,11 @@ export const useWalls = create((set: any) => ({ export const useZones = create((set: any) => ({ zones: [], - setZones: (x: any) => set(() => ({ zones: x })), + setZones: (callback: any) => + set((state: any) => ({ + zones: + typeof callback === 'function' ? callback(state.zones) : callback + })) })); interface ZonePointsState { diff --git a/app/src/styles/components/input.scss b/app/src/styles/components/input.scss index f627c2c..40cff59 100644 --- a/app/src/styles/components/input.scss +++ b/app/src/styles/components/input.scss @@ -45,6 +45,7 @@ input { .toggle-header-container { @include flex-center; padding: 6px 12px; + margin: 6px 0; .toggle-header-item { width: 100%; @@ -553,6 +554,7 @@ input { .input-value { width: 42px; text-align: center; + &::-webkit-inner-spin-button, &::-webkit-outer-spin-button { -webkit-appearance: none; @@ -654,4 +656,4 @@ input { .multi-email-invite-input.active { border: 1px solid var(--accent-color); } -} +} \ No newline at end of file diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss index 3b14aac..b021833 100644 --- a/app/src/styles/layout/sidebar.scss +++ b/app/src/styles/layout/sidebar.scss @@ -66,9 +66,9 @@ .sidebar-left-content-container { border-bottom: 1px solid var(--border-color); // flex: 1; - height: calc(100% - 36px); + // height: calc(100% - 36px); position: relative; - overflow: auto; + // overflow: auto; .template-list { display: flex; @@ -78,19 +78,19 @@ min-height: 50vh; max-height: 60vh; } - + .template-item { border: 1px solid #e0e0e0; border-radius: 8px; padding: 1rem; transition: box-shadow 0.3s ease; } - + .template-image-container { position: relative; padding-bottom: 56.25%; // 16:9 aspect ratio } - + .template-image { position: absolute; width: 100%; @@ -100,19 +100,19 @@ cursor: pointer; transition: transform 0.3s ease; } - + .template-details { display: flex; justify-content: space-between; align-items: center; margin-top: 0.5rem; } - + .template-name { cursor: pointer; font-weight: 500; } - + .delete-button { padding: 0.25rem 0.5rem; background: #ff4444; @@ -122,18 +122,22 @@ cursor: pointer; transition: opacity 0.3s ease; } - + .no-templates { text-align: center; color: #666; padding: 2rem; grid-column: 1 / -1; } - + .widget-left-sideBar { - min-height: 50vh; - max-height: 60vh; + .widgets-wrapper { + + min-height: 50vh; + max-height: 60vh; + overflow: auto; + } .widget2D { overflow: auto; diff --git a/app/src/styles/pages/realTimeViz.scss b/app/src/styles/pages/realTimeViz.scss index 19cd2b4..aa42fd1 100644 --- a/app/src/styles/pages/realTimeViz.scss +++ b/app/src/styles/pages/realTimeViz.scss @@ -365,7 +365,7 @@ .panel.hidePanel { pointer-events: none; - opacity: 0.1; + opacity: 0; } } diff --git a/app/src/types/world/worldTypes.d.ts b/app/src/types/world/worldTypes.d.ts index 25ef4b6..fefca2a 100644 --- a/app/src/types/world/worldTypes.d.ts +++ b/app/src/types/world/worldTypes.d.ts @@ -310,11 +310,13 @@ interface VehicleEventsSchema { points: { uuid: string; position: [number, number, number]; + rotation: [number, number, number]; actions: { uuid: string; name: string; type: string; start: { x: number, y: number } | {}, hitCount: number, end: { x: number, y: number } | {}, buffer: number }; connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] }; speed: number; }; position: [number, number, number]; + rotation: [number, number, number]; } interface StaticMachineEventsSchema { @@ -324,6 +326,7 @@ interface StaticMachineEventsSchema { points: { uuid: string; position: [number, number, number]; + rotation: [number, number, number]; actions: { uuid: string; name: string; buffer: number; material: string; }; triggers: { uuid: string; name: string; type: string }; connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] }; @@ -339,6 +342,7 @@ interface ArmBotEventsSchema { points: { uuid: string; position: [number, number, number]; + rotation: [number, number, number]; actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[] }; triggers: { uuid: string; name: string; type: string }; connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] }; @@ -371,6 +375,7 @@ export type EventData = { points: { uuid: string; position: [number, number, number]; + rotation: [number, number, number]; actions: { uuid: string; name: string; type: string; start: { x: number, y: number } | {}, hitCount: number, end: { x: number, y: number } | {}, buffer: number }; connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] }; speed: number; @@ -380,6 +385,7 @@ export type EventData = { points: { uuid: string; position: [number, number, number]; + rotation: [number, number, number]; actions: { uuid: string; name: string; buffer: number; material: string; }; triggers: { uuid: string; name: string; type: string }; connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] }; @@ -389,6 +395,7 @@ export type EventData = { points: { uuid: string; position: [number, number, number]; + rotation: [number, number, number]; actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[] }; triggers: { uuid: string; name: string; type: string }; connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] }; diff --git a/app/src/utils/shortcutkeys/handleShortcutKeys.ts b/app/src/utils/shortcutkeys/handleShortcutKeys.ts index 73388d5..57fdf66 100644 --- a/app/src/utils/shortcutkeys/handleShortcutKeys.ts +++ b/app/src/utils/shortcutkeys/handleShortcutKeys.ts @@ -55,9 +55,21 @@ const KeyPressListener: React.FC = () => { useEffect(() => { // Function to handle keydown events const handleKeyPress = (event: KeyboardEvent) => { - // Allow default behavior for F5 and F12 - const keyCombination = detectModifierKeys(event); + const activeElement = document.activeElement; + + const isTyping = + activeElement instanceof HTMLInputElement || + activeElement instanceof HTMLTextAreaElement || + (activeElement && activeElement.getAttribute('contenteditable') === 'true'); + + if (isTyping) { + return; // Don't trigger shortcuts while typing + } + + const keyCombination = detectModifierKeys(event); + + // Allow default behavior for F5 and F12 if (["F5", "F11", "F12"].includes(event.key) || keyCombination === "Ctrl+R") { return; } @@ -148,11 +160,10 @@ const KeyPressListener: React.FC = () => { setActiveTool("draw-floor"); setToolMode("Floor"); } - } else { - if (keyCombination === "M") { - setActiveTool("measure"); - setToolMode("MeasurementScale"); - } + } + if (keyCombination === "M") { + setActiveTool("measure"); + setToolMode("MeasurementScale"); } }