From cba37f2675cdcb5c218e827d608efe4114244648 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Sat, 20 Dec 2025 16:02:30 +0530 Subject: [PATCH 1/4] feat: Add new simulation module and a detailed performance analyzer component. --- .../modules/simulation/analyzer/analyzer.tsx | 35 +++++++++---------- app/src/modules/simulation/simulation.tsx | 2 +- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/app/src/modules/simulation/analyzer/analyzer.tsx b/app/src/modules/simulation/analyzer/analyzer.tsx index 28a3d09..744bac2 100644 --- a/app/src/modules/simulation/analyzer/analyzer.tsx +++ b/app/src/modules/simulation/analyzer/analyzer.tsx @@ -1722,8 +1722,8 @@ function Analyzer() { // Success rates const liftAttempts = totalLifts + errorCount; - const liftSuccessRate = liftAttempts > 0 ? (totalLifts / liftAttempts) * 100 : 100; - const positioningAccuracy = liftSuccessRate * 0.98; // Slightly lower than success rate + const liftSuccessRate = liftAttempts > 0 ? (totalLifts / liftAttempts) * 100 : 0; + const positioningAccuracy = totalLifts > 0 ? liftSuccessRate * 1.0 : 0; // Slightly lower than success rate // Load utilization const maxPickUpCount = crane.point?.actions?.[0]?.maxPickUpCount || 1; @@ -2499,22 +2499,6 @@ function Analyzer() { const previousPhase = previousCranePhasesRef.current[crane.modelUuid]; const currentPhase = crane.currentPhase; - // Check for transition from 'pickup-drop' to 'init' (Cycle completed) - if (previousPhase === "pickup-drop" && currentPhase === "init") { - // Increment cycles completed - if (!completedActionsRef.current[crane.modelUuid]) { - completedActionsRef.current[crane.modelUuid] = 0; - } - completedActionsRef.current[crane.modelUuid]++; - - // Track loads handled (number of materials carried in this cycle) - const loadsInCycle = crane.currentMaterials?.length || 1; - if (!completedActionsRef.current[`${crane.modelUuid}_loads`]) { - completedActionsRef.current[`${crane.modelUuid}_loads`] = 0; - } - completedActionsRef.current[`${crane.modelUuid}_loads`] += loadsInCycle; - } - // Track lifts (picking phase indicates a lift operation) if (previousPhase !== "picking" && currentPhase === "picking") { if (!completedActionsRef.current[`${crane.modelUuid}_lifts`]) { @@ -2528,6 +2512,21 @@ function Analyzer() { completedActionsRef.current[`${crane.modelUuid}_lift_height`] = 0; } completedActionsRef.current[`${crane.modelUuid}_lift_height`] += 5; + + // Track loads handled when picking (each pick is a load) + if (!completedActionsRef.current[`${crane.modelUuid}_loads`]) { + completedActionsRef.current[`${crane.modelUuid}_loads`] = 0; + } + completedActionsRef.current[`${crane.modelUuid}_loads`]++; + } + + // Track cycles completed when dropping is done (transition from 'dropping' to any other phase) + if (previousPhase === "dropping" && currentPhase !== "dropping") { + // Increment cycles completed + if (!completedActionsRef.current[crane.modelUuid]) { + completedActionsRef.current[crane.modelUuid] = 0; + } + completedActionsRef.current[crane.modelUuid]++; } previousCranePhasesRef.current[crane.modelUuid] = currentPhase; diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index cefba91..0bc5bb2 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -25,7 +25,7 @@ function Simulation() { const { analysis } = analysisStore(); useEffect(() => { - console.log("analysis: ", analysis); + // console.log("analysis: ", analysis); }, [analysis]); useEffect(() => { From 6a46ae7bd96b5a564cfb073329a59220ad7de001 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Sat, 20 Dec 2025 16:12:14 +0530 Subject: [PATCH 2/4] feat: add ElementDesign component for UI element styling and positioning. --- .../components/element/ElementDesign.tsx | 196 ++++-------------- 1 file changed, 37 insertions(+), 159 deletions(-) diff --git a/app/src/components/SimulationDashboard/components/element/ElementDesign.tsx b/app/src/components/SimulationDashboard/components/element/ElementDesign.tsx index 1696481..8537778 100644 --- a/app/src/components/SimulationDashboard/components/element/ElementDesign.tsx +++ b/app/src/components/SimulationDashboard/components/element/ElementDesign.tsx @@ -1,15 +1,7 @@ import React, { RefObject, useEffect, useState } from "react"; import DataSourceSelector from "../../../ui/inputs/DataSourceSelector"; import RenameInput from "../../../ui/inputs/RenameInput"; -import { - AlignJustifyIcon, - AlignLeftIcon, - AlignRightIcon, - ArrowIcon, - FlexColumnIcon, - FlexRowIcon, - FlexRowReverseIcon, -} from "../../../icons/ExportCommonIcons"; +import { AlignJustifyIcon, AlignLeftIcon, AlignRightIcon, ArrowIcon, FlexColumnIcon, FlexRowIcon, FlexRowReverseIcon } from "../../../icons/ExportCommonIcons"; import InputWithDropDown from "../../../ui/inputs/InputWithDropDown"; import InputRange from "../../../ui/inputs/InputRange"; import { getAlphaFromRgba, hexToRgba, rgbaToHex } from "../../functions/helpers/colorHandlers"; @@ -24,35 +16,15 @@ interface ElementDesignProps { selectedBlock: string; selectedElement: string; updateElementStyle: (blockId: string, elementId: string, style: ExtendedCSSProperties) => void; - updateElementSize: ( - blockId: string, - elementId: string, - size: { width: number; height: number } - ) => void; - updateElementPosition: ( - blockId: string, - elementId: string, - position: { x: number; y: number } - ) => void; - updateElementPositionType: ( - blockId: string, - elementId: string, - positionType: "relative" | "absolute" | "fixed" - ) => void; + updateElementSize: (blockId: string, elementId: string, size: { width: number; height: number }) => void; + updateElementPosition: (blockId: string, elementId: string, position: { x: number; y: number }) => void; + updateElementPositionType: (blockId: string, elementId: string, positionType: "relative" | "absolute" | "fixed") => void; updateElementZIndex: (blockId: string, elementId: string, zIndex: number) => void; - updateElementData: ( - blockId: string, - elementId: string, - updates: Partial - ) => void; + updateElementData: (blockId: string, elementId: string, updates: Partial) => void; updateGraphData: (blockId: string, elementId: string, newData: GraphDataPoint[]) => void; updateGraphTitle: (blockId: string, elementId: string, title: string) => void; updateGraphType: (blockId: string, elementId: string, type: GraphTypes) => void; - updateDataType: ( - blockId: string, - elementId: string, - dataType: "single-machine" | "multiple-machine" - ) => void; + updateDataType: (blockId: string, elementId: string, dataType: "single-machine" | "multiple-machine") => void; updateCommonValue: (blockId: string, elementId: string, commonValue: string) => void; updateDataValue: (blockId: string, elementId: string, dataValue: string | string[]) => void; updateDataSource: (blockId: string, elementId: string, dataSource: string | string[]) => void; @@ -76,9 +48,7 @@ const ElementDesign: React.FC = ({ const [color, setColor] = useState("#000000"); useEffect(() => { - setColor( - rgbaToHex(getCurrentElementStyleValue(currentElement, "backgroundColor") || "#000000") - ); + setColor(rgbaToHex(getCurrentElementStyleValue(currentElement, "backgroundColor") || "#000000")); }, [currentElement]); return ( @@ -95,11 +65,7 @@ const ElementDesign: React.FC = ({ { id: "radar", label: "Radar Chart" }, ]} onSelect={(newValue) => { - updateGraphType( - selectedBlock, - selectedElement, - newValue.id as GraphTypes - ); + updateGraphType(selectedBlock, selectedElement, newValue.id as GraphTypes); }} showEyeDropper={false} /> @@ -112,15 +78,8 @@ const ElementDesign: React.FC = ({ {["relative", "absolute"].map((position) => (
- updateElementPositionType( - selectedBlock, - selectedElement, - position as "relative" | "absolute" | "fixed" - ) - } + className={`type ${currentElement.positionType === position ? "active" : ""}`} + onClick={() => updateElementPositionType(selectedBlock, selectedElement, position as "relative" | "absolute" | "fixed")} > {position.charAt(0).toUpperCase() + position.slice(1)}
@@ -129,48 +88,16 @@ const ElementDesign: React.FC = ({
- +
- +
- +
- +
@@ -178,10 +105,7 @@ const ElementDesign: React.FC = ({
updateElementStyle(selectedBlock, selectedElement, { textAlign: "right", @@ -191,11 +115,7 @@ const ElementDesign: React.FC = ({
updateElementStyle(selectedBlock, selectedElement, { textAlign: "justify", @@ -205,10 +125,7 @@ const ElementDesign: React.FC = ({
updateElementStyle(selectedBlock, selectedElement, { textAlign: "left", @@ -220,10 +137,7 @@ const ElementDesign: React.FC = ({
updateElementStyle(selectedBlock, selectedElement, { flexDirection: "row", @@ -233,11 +147,7 @@ const ElementDesign: React.FC = ({
updateElementStyle(selectedBlock, selectedElement, { flexDirection: "column", @@ -247,11 +157,7 @@ const ElementDesign: React.FC = ({
updateElementStyle(selectedBlock, selectedElement, { flexDirection: "row-reverse", @@ -261,11 +167,7 @@ const ElementDesign: React.FC = ({
updateElementStyle(selectedBlock, selectedElement, { flexDirection: "column-reverse", @@ -282,22 +184,12 @@ const ElementDesign: React.FC = ({ label="Layer" value={String(currentElement.zIndex || 1)} placeholder={"Layer"} - onChange={(newValue: string) => - updateElementZIndex( - selectedBlock, - selectedElement, - Number(newValue) - ) - } + onChange={(newValue: string) => updateElementZIndex(selectedBlock, selectedElement, Number(newValue))} />
+ { + updateElementStyle(selectedBlock, selectedElement, { + borderRadius: Number(newValue), + }); + }} + />
@@ -443,21 +336,6 @@ const ElementDesign: React.FC = ({ updateElementStyle(selectedBlock, selectedElement, { backdropFilter: `blur(${Number(value)}px)` }); }} /> - { - updateElementStyle(selectedBlock, selectedElement, { - borderRadius: Number(newValue), - }); - }} - />
); From a30b42d39ed59f495c1b42a8095a6ab7950250d4 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Sat, 20 Dec 2025 16:33:35 +0530 Subject: [PATCH 3/4] feat: Add `ElementComponent` for dashboard UI elements and `Analyzer` for comprehensive simulation performance tracking. --- .../components/element/ElementComponent.tsx | 33 ++++++------------- .../modules/simulation/analyzer/analyzer.tsx | 33 ++++++++++++++++++- 2 files changed, 42 insertions(+), 24 deletions(-) diff --git a/app/src/components/SimulationDashboard/components/element/ElementComponent.tsx b/app/src/components/SimulationDashboard/components/element/ElementComponent.tsx index 28ec04d..ccd0f9e 100644 --- a/app/src/components/SimulationDashboard/components/element/ElementComponent.tsx +++ b/app/src/components/SimulationDashboard/components/element/ElementComponent.tsx @@ -14,24 +14,10 @@ interface ElementComponentProps { handleElementResizeStart: (elementId: string, event: React.MouseEvent) => void; } -const ElementComponent: React.FC = ({ - element, - blockId, - editMode, - selectedElement, - handleElementClick, - handleElementDragStart, - handleElementResizeStart, -}) => { +const ElementComponent: React.FC = ({ element, blockId, editMode, selectedElement, handleElementClick, handleElementDragStart, handleElementResizeStart }) => { const isSelected = selectedElement === element.elementUuid; - const elementClasses = [ - "element", - element.positionType === "absolute" ? "absolute" : "", - element.type === "graph" ? "graph" : "", - editMode ? "edit-mode" : "", - isSelected ? "selected" : "", - ] + const elementClasses = ["element", element.positionType === "absolute" ? "absolute" : "", element.type === "graph" ? "graph" : "", editMode ? "edit-mode" : "", isSelected ? "selected" : ""] .filter(Boolean) .join(" "); @@ -43,8 +29,7 @@ const ElementComponent: React.FC = ({ style={{ ...element.style, position: element.positionType || "relative", - left: - element.positionType === "absolute" ? `${element.position?.x || 0}px` : "auto", + left: element.positionType === "absolute" ? `${element.position?.x || 0}px` : "auto", top: element.positionType === "absolute" ? `${element.position?.y || 0}px` : "auto", width: element.size?.width || "auto", height: element.size?.height || "auto", @@ -55,16 +40,18 @@ const ElementComponent: React.FC = ({ e.stopPropagation(); handleElementClick(blockId, element.elementUuid, e); }} - onMouseDown={(e) => handleElementDragStart(element.elementUuid, e)} + onMouseDown={(e) => { + // Only allow dragging for absolute positioned elements + if (element.positionType === "absolute") { + handleElementDragStart(element.elementUuid, e); + } + }} > {editMode && ( <> -
handleElementResizeStart(element.elementUuid, e)} - > +
handleElementResizeStart(element.elementUuid, e)}>
diff --git a/app/src/modules/simulation/analyzer/analyzer.tsx b/app/src/modules/simulation/analyzer/analyzer.tsx index 744bac2..bf41928 100644 --- a/app/src/modules/simulation/analyzer/analyzer.tsx +++ b/app/src/modules/simulation/analyzer/analyzer.tsx @@ -187,6 +187,9 @@ function Analyzer() { // Track previous actions for ArmBots to detect cycle completion const previousArmBotActionsRef = useRef>({}); + // Track previous actions for Machines to detect cycle completion + const previousMachineActionsRef = useRef>({}); + // Track previous action counts for Humans to detect completion from EventManager const previousHumanCountsRef = useRef>>({}); @@ -228,6 +231,7 @@ function Analyzer() { bottleneckEventsRef.current = {}; previousAssetStatesRef.current = {}; previousArmBotActionsRef.current = {}; + previousMachineActionsRef.current = {}; previousHumanCountsRef.current = {}; previousVehiclePhasesRef.current = {}; previousCranePhasesRef.current = {}; @@ -278,7 +282,7 @@ function Analyzer() { const calculateQualityMetrics = (assetId: string, totalOperations: number, defects: number, historicalData: any[] = []) => { const errorCount = errorCountsRef.current[assetId] || 0; - const firstPassYield = totalOperations > 0 ? ((totalOperations - defects) / totalOperations) * 100 : 100; + const firstPassYield = totalOperations > 0 ? ((totalOperations - defects) / totalOperations) * 100 : 0; const defectRate = totalOperations > 0 ? (defects / totalOperations) * 100 : 0; const scrapRate = defects > 0 ? defects * 0.1 : 0; // Assuming 10% scrap rate const reworkRate = defects > 0 ? defects * 0.9 : 0; // Assuming 90% rework @@ -2395,6 +2399,33 @@ function Analyzer() { }); }, [armBots, isPlaying]); + // Monitor Machine action changes to track cycles + useEffect(() => { + if (!isPlaying) return; + + machines.forEach((machine) => { + const previousActionUuid = previousMachineActionsRef.current[machine.modelUuid]; + const currentActionUuid = machine.currentAction?.actionUuid; + + // Check if action completed (transition from an action to no action or different action) + if (previousActionUuid && previousActionUuid !== currentActionUuid) { + // Action completed - increment cycles + if (!completedActionsRef.current[machine.modelUuid]) { + completedActionsRef.current[machine.modelUuid] = 0; + } + completedActionsRef.current[machine.modelUuid]++; + + // Also update parts processed (assume 1 part per cycle) + if (!completedActionsRef.current[`${machine.modelUuid}_parts`]) { + completedActionsRef.current[`${machine.modelUuid}_parts`] = 0; + } + completedActionsRef.current[`${machine.modelUuid}_parts`]++; + } + + previousMachineActionsRef.current[machine.modelUuid] = currentActionUuid; + }); + }, [machines, isPlaying]); + // Monitor Human action changes from EventManager useEffect(() => { if (!isPlaying || !humanEventManagerRef.current) return; From 6f15b2feccb12ce8b9907654db0dffaef9ce8843 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Sat, 20 Dec 2025 16:39:37 +0530 Subject: [PATCH 4/4] feat: Add core components and styling for the new simulation dashboard editor. --- .../SimulationDashboard/DashboardEditor.tsx | 26 +++++++++++++++++-- .../components/element/ElementComponent.tsx | 2 +- .../_simulationDashBoard.scss | 14 ++++++---- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/app/src/components/SimulationDashboard/DashboardEditor.tsx b/app/src/components/SimulationDashboard/DashboardEditor.tsx index ba4047d..7a2dcfc 100644 --- a/app/src/components/SimulationDashboard/DashboardEditor.tsx +++ b/app/src/components/SimulationDashboard/DashboardEditor.tsx @@ -59,7 +59,6 @@ const DashboardEditor: React.FC = () => { peekUpdateCommonValue, peekUpdateDataValue, peekUpdateDataSource, - } = simulationDashBoardStore(); const [editMode, setEditMode] = useState(false); @@ -209,6 +208,9 @@ const DashboardEditor: React.FC = () => { const elementToDrag = document.querySelector(`[data-element-id="${draggingElement}"]`) as HTMLElement; if (blockElement && elementToDrag) { + // Disable transitions during drag + elementToDrag.classList.add("no-transition"); + const blockRect = blockElement.getBoundingClientRect(); const elementRect = elementToDrag.getBoundingClientRect(); const newX = e.clientX - blockRect.left - elementDragOffset.x; @@ -233,6 +235,9 @@ const DashboardEditor: React.FC = () => { const blockToDrag = document.querySelector(`[data-block-id="${draggingBlock}"]`) as HTMLElement; if (editorElement && blockToDrag) { + // Disable transitions during drag + blockToDrag.classList.add("no-transition"); + const editorRect = editorElement.getBoundingClientRect(); const newX = e.clientX - editorRect.left - blockDragOffset.x; const newY = e.clientY - editorRect.top - blockDragOffset.y; @@ -248,6 +253,9 @@ const DashboardEditor: React.FC = () => { if (resizingElement && selectedBlock) { const elementToResize = document.querySelector(`[data-element-id="${resizingElement}"]`) as HTMLElement; if (elementToResize) { + // Disable transitions during resize + elementToResize.classList.add("no-transition"); + const deltaX = e.clientX - resizeStart.x; const deltaY = e.clientY - resizeStart.y; @@ -280,6 +288,9 @@ const DashboardEditor: React.FC = () => { } else if (resizingBlock) { const blockToResize = document.querySelector(`[data-block-id="${resizingBlock}"]`) as HTMLElement; if (blockToResize) { + // Disable transitions during resize + blockToResize.classList.add("no-transition"); + const deltaX = e.clientX - resizeStart.x; const deltaY = e.clientY - resizeStart.y; @@ -328,6 +339,9 @@ const DashboardEditor: React.FC = () => { const elementToDrag = document.querySelector(`[data-element-id="${draggingElement}"]`) as HTMLElement; if (blockElement && elementToDrag) { + // Re-enable transitions + elementToDrag.classList.remove("no-transition"); + const computedStyle = window.getComputedStyle(elementToDrag); const x = parseFloat(computedStyle.left); const y = parseFloat(computedStyle.top); @@ -341,6 +355,9 @@ const DashboardEditor: React.FC = () => { const blockToDrag = document.querySelector(`[data-block-id="${draggingBlock}"]`) as HTMLElement; if (blockToDrag) { + // Re-enable transitions + blockToDrag.classList.remove("no-transition"); + const computedStyle = window.getComputedStyle(blockToDrag); const x = parseFloat(computedStyle.left); const y = parseFloat(computedStyle.top); @@ -355,6 +372,9 @@ const DashboardEditor: React.FC = () => { const blockElement = document.querySelector(`[data-block-id="${selectedBlock}"]`) as HTMLElement; if (elementToResize && blockElement) { + // Re-enable transitions + elementToResize.classList.remove("no-transition"); + const computedStyle = window.getComputedStyle(elementToResize); const width = parseFloat(computedStyle.width); const height = parseFloat(computedStyle.height); @@ -367,6 +387,9 @@ const DashboardEditor: React.FC = () => { // Update backend for block resize const blockToResize = document.querySelector(`[data-block-id="${resizingBlock}"]`) as HTMLElement; if (blockToResize) { + // Re-enable transitions + blockToResize.classList.remove("no-transition"); + const computedStyle = window.getComputedStyle(blockToResize); const width = parseFloat(computedStyle.width); const height = parseFloat(computedStyle.height); @@ -638,7 +661,6 @@ const DashboardEditor: React.FC = () => { /> )}
-
); }; diff --git a/app/src/components/SimulationDashboard/components/element/ElementComponent.tsx b/app/src/components/SimulationDashboard/components/element/ElementComponent.tsx index ccd0f9e..7ae4e64 100644 --- a/app/src/components/SimulationDashboard/components/element/ElementComponent.tsx +++ b/app/src/components/SimulationDashboard/components/element/ElementComponent.tsx @@ -49,7 +49,7 @@ const ElementComponent: React.FC = ({ element, blockId, e > - {editMode && ( + {editMode && isSelected && ( <>
handleElementResizeStart(element.elementUuid, e)}> diff --git a/app/src/styles/components/simulationDashboard/_simulationDashBoard.scss b/app/src/styles/components/simulationDashboard/_simulationDashBoard.scss index 2012686..7161671 100644 --- a/app/src/styles/components/simulationDashboard/_simulationDashBoard.scss +++ b/app/src/styles/components/simulationDashboard/_simulationDashBoard.scss @@ -12,7 +12,13 @@ left: 0; pointer-events: none; - *> { + // Utility class to disable transitions during drag/resize + .no-transition, + .no-transition * { + transition: none !important; + } + + * > { pointer-events: auto; } @@ -479,9 +485,7 @@ .colorValue { width: 100%; - background: linear-gradient(90.85deg, - rgba(240, 228, 255, 0.3) 3.6%, - rgba(211, 174, 253, 0.3) 96.04%); + background: linear-gradient(90.85deg, rgba(240, 228, 255, 0.3) 3.6%, rgba(211, 174, 253, 0.3) 96.04%); text-align: center; padding: 4px 0; border-radius: 100px; @@ -1116,4 +1120,4 @@ } } } -} \ No newline at end of file +}