Merge remote-tracking branch 'origin/main-dev' into feature/layout-comparison-version

This commit is contained in:
2025-10-15 16:31:51 +05:30
11 changed files with 107 additions and 66 deletions

View File

@@ -70,12 +70,19 @@ function StorageMechanics() {
};
const handleCapacityChange = (value: string) => {
if (!selectedEventData) return;
if (!selectedEventData || selectedEventData.data.type !== "storageUnit") return;
const numericValue = parseInt(value);
if (isNaN(numericValue)) return;
const event = peekUpdateEvent(selectedProduct.productUuid, selectedEventData.data.modelUuid, { storageCapacity: numericValue } as StorageEventSchema);
const currentCount = selectedEventData.data.storageCount;
const updatedEventData: Partial<StorageEventSchema> = { storageCapacity: numericValue };
if (currentCount > numericValue) {
updatedEventData.storageCount = numericValue;
}
const event = peekUpdateEvent(selectedProduct.productUuid, selectedEventData.data.modelUuid, updatedEventData as StorageEventSchema);
if (event) {
updateBackend(event);
@@ -83,11 +90,15 @@ function StorageMechanics() {
};
const handleSpawnCountChange = (value: string) => {
if (!selectedEventData) return;
if (!selectedEventData || selectedEventData.data.type !== "storageUnit") return;
const numericValue = parseInt(value);
if (isNaN(numericValue)) return;
const { storageCapacity } = selectedEventData.data;
if (numericValue > storageCapacity) return;
const event = peekUpdateEvent(selectedProduct.productUuid, selectedEventData.data.modelUuid, { storageCount: numericValue } as StorageEventSchema);
if (event) {

View File

@@ -92,9 +92,9 @@ const Tools: React.FC = () => {
// 3. Update tools behavior based on selected tool and view mode
useEffect(() => {
resetTools();
updateToolBehavior(activeTool, toggleView);
updateToolBehavior(activeTool, toggleView, activeModule);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [activeTool, toggleView]);
}, [activeTool, toggleView, activeModule]);
// 4. Dropdown auto-close
useEffect(() => {
@@ -111,7 +111,7 @@ const Tools: React.FC = () => {
setToolMode(null);
};
const updateToolBehavior = (tool: string, is2D: boolean) => {
const updateToolBehavior = (tool: string, is2D: boolean, activeModule: string) => {
switch (tool) {
case "cursor":
is2D ? setToolMode("move") : setToolMode("cursor");
@@ -129,10 +129,27 @@ const Tools: React.FC = () => {
is2D && setToolMode("Floor");
break;
case "move":
if (!is2D) setToolMode("Move-Asset");
if (!is2D) {
if (activeModule === "builder") {
setToolMode("Move-Asset");
} else if (activeModule === "simulation") {
setToolMode("Move-Point");
} else {
setToolMode("Move-Asset");
}
}
break;
case "rotate":
if (!is2D) setToolMode("Rotate-Asset");
if (!is2D) {
if (activeModule === "builder") {
setToolMode("Rotate-Asset");
} else if (activeModule === "simulation") {
setToolMode("Rotate-Point");
} else {
setToolMode("Rotate-Asset");
}
}
break;
case "measure":
setToolMode("MeasurementScale");

View File

@@ -528,12 +528,12 @@ export const AssetOutline = () => {
if (isGroup(draggedItem)) {
addChildToGroup(targetGroupUuid, {
type: "Group",
childrenUuid: draggedItem.groupUuid,
childUuid: draggedItem.groupUuid,
});
} else {
addChildToGroup(targetGroupUuid, {
type: "Asset",
childrenUuid: draggedItem.modelUuid,
childUuid: draggedItem.modelUuid,
});
}
}

View File

@@ -107,6 +107,11 @@ function SimulationResponses() {
if (hasSelectedAction && hasNewAction && newActions.length > 0 && diffActions.length > 0) {
setSelectedAction(diffActions[0].actionUuid, diffActions[0].actionName);
} else if (selectedAction.actionId && selectedAction.actionName) {
const action: [string, string] = [selectedAction.actionId, selectedAction.actionName];
setTimeout(() => {
setSelectedAction(...action);
}, 0);
}
}
}

View File

@@ -61,7 +61,7 @@ function GroupControls() {
isLocked: false,
isExpanded: true,
children: assetUuids.map((assetUuid) => {
return { type: "Asset", childrenUuid: assetUuid };
return { type: "Asset", childUuid: assetUuid };
}),
};

View File

@@ -3,7 +3,7 @@ import * as THREE from "three";
import { useParams } from "react-router-dom";
import { useThree } from "@react-three/fiber";
import useModuleStore, { useSubModuleStore } from "../../../../../store/ui/useModuleStore";
import { useToolMode } from "../../../../../store/builder/store";
import { useActiveTool, useToolMode } from "../../../../../store/builder/store";
import { TransformControls } from "@react-three/drei";
import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys";
import { useSelectedEventSphere, useSelectedEventData, useDeletableEventSphere } from "../../../../../store/simulation/useSimulationStore";
@@ -18,6 +18,7 @@ function PointsCreator() {
const { gl, raycaster, scene, pointer, camera } = useThree();
const { subModule } = useSubModuleStore();
const { toolMode } = useToolMode();
const { setActiveTool } = useActiveTool();
const { activeModule } = useModuleStore();
const { simulationSocket } = useSocketStore();
const { eventStore, productStore, versionStore } = useSceneContext();
@@ -41,9 +42,11 @@ function PointsCreator() {
const { projectId } = useParams();
useEffect(() => {
clearSelectedEventSphere();
clearSelectedEventData();
clearDeletableEventSphere();
if (toolMode !== "Move-Point" && toolMode !== "Rotate-Point" && activeModule !== "simulation") {
clearSelectedEventSphere();
clearSelectedEventData();
clearDeletableEventSphere();
}
}, [toolMode, activeModule]);
const updateBackend = (eventData: EventsSchema) => {
@@ -81,13 +84,28 @@ function PointsCreator() {
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
const keyCombination = detectModifierKeys(e);
if (!selectedEventSphere) return;
if (!selectedEventSphere || e.repeat) return;
if (keyCombination === "G") {
setTransformMode((prev) => (prev === "translate" ? null : "translate"));
setTransformMode((prev) => {
const newMode = prev === "translate" ? null : "translate";
setTimeout(() => {
newMode === "translate" ? setActiveTool("move") : setActiveTool("cursor");
}, 0);
return newMode;
});
}
if (keyCombination === "R") {
setTransformMode((prev) => (prev === "rotate" ? null : "rotate"));
setTransformMode((prev) => {
const newMode = prev === "rotate" ? null : "rotate";
setTimeout(() => {
newMode === "rotate" ? setActiveTool("rotate") : setActiveTool("cursor");
}, 0);
return newMode;
});
}
if (keyCombination === "DELETE") {
deletePointfromConveyor(selectedEventSphere);
}
@@ -97,6 +115,16 @@ function PointsCreator() {
return () => window.removeEventListener("keydown", handleKeyDown);
}, [selectedEventSphere]);
useEffect(() => {
if (toolMode === "Move-Point") {
setTransformMode("translate");
} else if (toolMode === "Rotate-Point") {
setTransformMode("rotate");
} else {
setTransformMode(null);
}
}, [selectedEventSphere, toolMode]);
const deletePointfromConveyor = (selectedEventSphere: THREE.Mesh) => {
const eventModel = getEventByModelUuidFromProduct(selectedProduct.productUuid, selectedEventSphere.userData.modelUuid);
if (!eventModel || eventModel.type !== "transfer" || eventModel.points.length < 2) return;

View File

@@ -25,7 +25,7 @@ export default function PointInstance({ point, modelUuid, color, ...meshProps }:
const { deletableEventSphere, setDeletableEventSphere, clearDeletableEventSphere } = useDeletableEventSphere();
const { toolMode } = useToolMode();
const { productStore, versionStore } = useSceneContext();
const { getEventByModelUuid, getTriggersByTriggeredPointUuid, peekRemoveTriggersAndPoints, peekRemovePoint, selectedProduct, updateEvent } = productStore();
const { getEventByModelUuid, getTriggersByTriggeredPointUuid, peekRemoveTriggersAndPoints, selectedProduct, updateEvent } = productStore();
const { selectedVersion } = versionStore();
const { projectId } = useParams();
@@ -69,7 +69,7 @@ export default function PointInstance({ point, modelUuid, color, ...meshProps }:
position={new THREE.Vector3(...point.position)}
onClick={(e) => {
e.stopPropagation();
if (toolMode === "cursor") {
if (toolMode === "cursor" || toolMode === "Move-Point" || toolMode === "Rotate-Point") {
setSelectedEventSphere(ref.current);
} else if (toolMode === "3D-Delete") {
handleEventPointDelete();

View File

@@ -19,7 +19,7 @@ export const createAssetGroupApi = async ({
isLocked: boolean;
children: {
type: "Asset" | "Group";
childrenUuid: string;
childUuid: string;
}[];
}) => {
try {

View File

@@ -21,9 +21,9 @@ interface AssetGroupStore {
hasSelectedGroup: (groupUuid: string) => boolean;
// Group children management
addChildToGroup: (groupUuid: string, child: { type: "Asset" | "Group"; childrenUuid: string }) => { updatedGroups: AssetGroup[] };
addChildToGroup: (groupUuid: string, child: { type: "Asset" | "Group"; childUuid: string }) => { updatedGroups: AssetGroup[] };
removeChildFromGroup: (groupUuid: string, childUuid: string) => void;
getGroupChildren: (groupUuid: string) => { type: "Asset" | "Group"; childrenUuid: string }[];
getGroupChildren: (groupUuid: string) => { type: "Asset" | "Group"; childUuid: string }[];
// Group properties
setGroupName: (groupUuid: string, newName: string) => void;
@@ -71,14 +71,14 @@ export const createAssetGroupStore = () => {
// Find all asset children in the new group
const assetChildren = group.children.filter((child) => child.type === "Asset");
const assetUuids = new Set(assetChildren.map((child) => child.childrenUuid));
const assetUuids = new Set(assetChildren.map((child) => child.childUuid));
// Remove these assets from existing groups and track updated groups
const updatedGroups: AssetGroup[] = [];
state.assetGroups.forEach((existingGroup) => {
const originalLength = existingGroup.children.length;
existingGroup.children = existingGroup.children.filter((child) => !(child.type === "Asset" && assetUuids.has(child.childrenUuid)));
existingGroup.children = existingGroup.children.filter((child) => !(child.type === "Asset" && assetUuids.has(child.childUuid)));
// If group was modified, add to updated groups
if (existingGroup.children.length !== originalLength) {
@@ -99,7 +99,7 @@ export const createAssetGroupStore = () => {
set((state) => {
// First remove this group from any parent groups
state.assetGroups.forEach((group) => {
group.children = group.children.filter((child) => !(child.type === "Group" && child.childrenUuid === groupUuid));
group.children = group.children.filter((child) => !(child.type === "Group" && child.childUuid === groupUuid));
});
// Then remove the group itself
@@ -181,7 +181,7 @@ export const createAssetGroupStore = () => {
if (group.groupUuid === groupUuid) return; // skip target group
const originalLength = group.children.length;
group.children = group.children.filter((c) => c.childrenUuid !== child.childrenUuid);
group.children = group.children.filter((c) => c.childUuid !== child.childUuid);
if (group.children.length !== originalLength) {
updatedGroups.push({ ...group });
@@ -189,7 +189,7 @@ export const createAssetGroupStore = () => {
});
// 2⃣ Add the child to the target group (if not already present)
if (!targetGroup.children.some((c) => c.childrenUuid === child.childrenUuid)) {
if (!targetGroup.children.some((c) => c.childUuid === child.childUuid)) {
targetGroup.children.push(child);
updatedGroups.push({ ...targetGroup });
}
@@ -207,7 +207,7 @@ export const createAssetGroupStore = () => {
set((state) => {
const group = state.assetGroups.find((g) => g.groupUuid === groupUuid);
if (group) {
group.children = group.children.filter((child) => child.childrenUuid !== childUuid);
group.children = group.children.filter((child) => child.childUuid !== childUuid);
state.groupHierarchy = get().buildHierarchy([], state.assetGroups);
}
});
@@ -274,14 +274,14 @@ export const createAssetGroupStore = () => {
group.children.forEach((child) => {
if (child.type === "Asset") {
const asset = assetMap.get(child.childrenUuid);
const asset = assetMap.get(child.childUuid);
if (asset) {
children.push(asset);
// Remove from assetMap so we know it's been processed
assetMap.delete(child.childrenUuid);
assetMap.delete(child.childUuid);
}
} else if (child.type === "Group") {
const childGroup = groupMap.get(child.childrenUuid);
const childGroup = groupMap.get(child.childUuid);
if (childGroup) {
children.push(buildNode(childGroup));
}
@@ -303,7 +303,7 @@ export const createAssetGroupStore = () => {
groups.forEach((group) => {
group.children.forEach((child) => {
if (child.type === "Group") {
childGroupUuids.add(child.childrenUuid);
childGroupUuids.add(child.childUuid);
}
});
});
@@ -347,7 +347,7 @@ export const createAssetGroupStore = () => {
isLocked: node.isLocked,
isExpanded: node.isExpanded,
children: node.children.map((child) =>
"modelUuid" in child ? { type: "Asset" as const, childrenUuid: child.modelUuid } : { type: "Group" as const, childrenUuid: child.groupUuid }
"modelUuid" in child ? { type: "Asset" as const, childUuid: child.modelUuid } : { type: "Group" as const, childUuid: child.groupUuid }
),
});
processedGroups.add(node.groupUuid);
@@ -408,11 +408,11 @@ export const createAssetGroupStore = () => {
const allChildren: string[] = [];
const collectChildren = (children: { type: "Asset" | "Group"; childrenUuid: string }[]) => {
const collectChildren = (children: { type: "Asset" | "Group"; childUuid: string }[]) => {
children.forEach((child) => {
allChildren.push(child.childrenUuid);
allChildren.push(child.childUuid);
if (child.type === "Group") {
const childGroup = get().assetGroups.find((g) => g.groupUuid === child.childrenUuid);
const childGroup = get().assetGroups.find((g) => g.groupUuid === child.childUuid);
if (childGroup) {
collectChildren(childGroup.children);
}
@@ -430,11 +430,11 @@ export const createAssetGroupStore = () => {
},
getGroupsContainingAsset: (assetUuid) => {
return get().assetGroups.filter((group) => group.children.some((child) => child.type === "Asset" && child.childrenUuid === assetUuid));
return get().assetGroups.filter((group) => group.children.some((child) => child.type === "Asset" && child.childUuid === assetUuid));
},
getGroupsContainingGroup: (childGroupUuid) => {
return get().assetGroups.filter((group) => group.children.some((child) => child.type === "Group" && child.childrenUuid === childGroupUuid));
return get().assetGroups.filter((group) => group.children.some((child) => child.type === "Group" && child.childUuid === childGroupUuid));
},
getParentGroup: (item) => {

View File

@@ -575,32 +575,12 @@ export const createProductStore = () => {
}
} else if ("point" in eventClone) {
const point = (eventClone as any).point;
if (eventClone.type === "roboticArm") {
if ("actions" in point) {
const index = point.actions.findIndex((a: any) => a.actionUuid === actionUuid);
if (index !== -1) {
point.actions.splice(index, 1);
updatedEvent = eventClone;
return updatedEvent;
}
}
} else if (eventClone.type === "human") {
if ("actions" in point) {
const index = point.actions.findIndex((a: any) => a.actionUuid === actionUuid);
if (index !== -1) {
point.actions.splice(index, 1);
updatedEvent = eventClone;
return updatedEvent;
}
}
} else if (eventClone.type === "crane") {
if ("actions" in point) {
const index = point.actions.findIndex((a: any) => a.actionUuid === actionUuid);
if (index !== -1) {
point.actions.splice(index, 1);
updatedEvent = eventClone;
return updatedEvent;
}
if ("actions" in point) {
const index = point.actions.findIndex((a: any) => a.actionUuid === actionUuid);
if (index !== -1) {
point.actions.splice(index, 1);
updatedEvent = eventClone;
return updatedEvent;
}
} else if ("action" in point && point.action?.actionUuid === actionUuid) {
point.action = undefined;

View File

@@ -58,7 +58,7 @@ interface AssetGroup {
isExpanded: boolean;
children: {
type: "Asset" | "Group";
childrenUuid: string;
childUuid: string;
}[];
}