Merge remote-tracking branch 'origin/main-dev' into feature/agv-edit

This commit is contained in:
2025-07-05 11:20:50 +05:30
68 changed files with 3868 additions and 860 deletions

View File

@@ -22,7 +22,9 @@ interface AssetsStore {
// Animation controls
setAnimations: (modelUuid: string, animations: string[]) => void;
setCurrentAnimation: (modelUuid: string, current: string, isPlaying: boolean) => void;
setCurrentAnimation: (modelUuid: string, current: string, isPlaying: boolean, loopAnimation: boolean, isCompleted: boolean) => void;
setAnimationComplete: (modelUuid: string, isCompleted: boolean) => void;
resetAnimation: (modelUuid: string) => void;
addAnimation: (modelUuid: string, animation: string) => void;
removeAnimation: (modelUuid: string, animation: string) => void;
@@ -149,22 +151,44 @@ export const createAssetStore = () => {
if (asset) {
asset.animations = animations;
if (!asset.animationState) {
asset.animationState = { current: '', playing: false };
asset.animationState = { current: '', isPlaying: false, loopAnimation: true, isCompleted: true };
}
}
});
},
setCurrentAnimation: (modelUuid, current, isPlaying) => {
setCurrentAnimation: (modelUuid, current, isPlaying, loopAnimation, isCompleted) => {
set((state) => {
const asset = state.assets.find(a => a.modelUuid === modelUuid);
if (asset?.animationState) {
asset.animationState.current = current;
asset.animationState.playing = isPlaying;
asset.animationState.isPlaying = isPlaying;
asset.animationState.loopAnimation = loopAnimation;
asset.animationState.isCompleted = isCompleted;
}
});
},
setAnimationComplete: (modelUuid, isCompleted) => {
set((state) => {
const asset = state.assets.find(a => a.modelUuid === modelUuid);
if (asset?.animationState) {
asset.animationState.isCompleted = isCompleted;
}
});
},
resetAnimation: (modelUuid) => {
set((state) => {
const asset = state.assets.find(a => a.modelUuid === modelUuid);
if (asset?.animationState) {
asset.animationState.current = '';
asset.animationState.isPlaying = true;
asset.animationState.loopAnimation = true;
asset.animationState.isCompleted = true; }
});
},
addAnimation: (modelUuid, animation) => {
set((state) => {
const asset = state.assets.find(a => a.modelUuid === modelUuid);
@@ -184,7 +208,7 @@ export const createAssetStore = () => {
if (asset?.animations) {
asset.animations = asset.animations.filter(a => a !== animation);
if (asset.animationState?.current === animation) {
asset.animationState.playing = false;
asset.animationState.isPlaying = false;
asset.animationState.current = '';
}
}

View File

@@ -15,6 +15,7 @@ interface BuilderState {
// Floor Asset
selectedFloorAsset: Object3D | null;
loopAnimation: boolean;
// Wall Settings
selectedWall: Object3D | null;
@@ -64,6 +65,7 @@ interface BuilderState {
// Setters - Floor Asset
setSelectedFloorAsset: (asset: Object3D | null) => void;
setLoopAnimation: (loop: boolean) => void;
// Setters - Wall
setSelectedWall: (wall: Object3D | null) => void;
@@ -118,6 +120,7 @@ export const useBuilderStore = create<BuilderState>()(
deletableWallAsset: null,
selectedFloorAsset: null,
loopAnimation: true,
selectedWall: null,
wallThickness: 0.5,
@@ -197,6 +200,12 @@ export const useBuilderStore = create<BuilderState>()(
});
},
setLoopAnimation(loopAnimation: boolean) {
set((state) => {
state.loopAnimation = loopAnimation;
});
},
// === Setters: Wall ===
setSelectedWall: (wall: Object3D | null) => {

View File

@@ -0,0 +1,238 @@
import { create } from "zustand";
import { immer } from "zustand/middleware/immer";
interface HumansStore {
humans: HumanStatus[];
addHuman: (productUuid: string, event: HumanEventSchema) => void;
removeHuman: (modelUuid: string) => void;
updateHuman: (
modelUuid: string,
updates: Partial<Omit<HumanStatus, "modelUuid" | "productUuid">>
) => void;
clearHumans: () => void;
setHumanActive: (modelUuid: string, isActive: boolean) => void;
setHumanPicking: (modelUuid: string, isPicking: boolean) => void;
setHumanLoad: (modelUuid: string, load: number) => void;
setHumanState: (
modelUuid: string,
newState: HumanStatus["state"]
) => void;
incrementHumanLoad: (modelUuid: string, incrementBy: number) => void;
decrementHumanLoad: (modelUuid: string, decrementBy: number) => void;
addCurrentMaterial: (modelUuid: string, materialType: string, materialId: string) => void;
setCurrentMaterials: (modelUuid: string, materials: { materialType: string; materialId: string }[]) => void;
removeLastMaterial: (modelUuid: string) => { materialType: string; materialId: string } | undefined;
getLastMaterial: (modelUuid: string) => { materialType: string; materialId: string } | undefined;
clearCurrentMaterials: (modelUuid: string) => void;
incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
incrementDistanceTraveled: (modelUuid: string, incrementBy: number) => void;
resetTime: (modelUuid: string) => void;
getHumanById: (modelUuid: string) => HumanStatus | undefined;
getHumansByProduct: (productUuid: string) => HumanStatus[];
getActiveHumans: () => HumanStatus[];
}
export const createHumanStore = () => {
return create<HumansStore>()(
immer((set, get) => ({
humans: [],
addHuman: (productUuid, event) => {
set((state) => {
const exists = state.humans.some(h => h.modelUuid === event.modelUuid);
if (!exists) {
state.humans.push({
...event,
productUuid,
isActive: false,
isPicking: false,
idleTime: 0,
activeTime: 0,
currentLoad: 0,
currentMaterials: [],
distanceTraveled: 0
});
}
});
},
removeHuman: (modelUuid) => {
set((state) => {
state.humans = state.humans.filter(h => h.modelUuid !== modelUuid);
});
},
updateHuman: (modelUuid, updates) => {
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);
if (human) {
Object.assign(human, updates);
}
});
},
clearHumans: () => {
set((state) => {
state.humans = [];
});
},
setHumanActive: (modelUuid, isActive) => {
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);
if (human) {
human.isActive = isActive;
}
});
},
setHumanPicking: (modelUuid, isPicking) => {
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);
if (human) {
human.isPicking = isPicking;
}
});
},
setHumanLoad: (modelUuid, load) => {
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);
if (human) {
human.currentLoad = load;
}
});
},
setHumanState: (modelUuid, newState) => {
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);
if (human) {
human.state = newState;
}
});
},
incrementHumanLoad: (modelUuid, incrementBy) => {
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);
if (human) {
human.currentLoad += incrementBy;
}
});
},
decrementHumanLoad: (modelUuid, decrementBy) => {
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);
if (human) {
human.currentLoad -= decrementBy;
}
});
},
addCurrentMaterial: (modelUuid, materialType, materialId) => {
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);
if (human) {
human.currentMaterials.push({ materialType, materialId });
}
});
},
setCurrentMaterials: (modelUuid, materials) => {
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);
if (human) {
human.currentMaterials = materials;
}
});
},
removeLastMaterial: (modelUuid) => {
let removed;
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);
if (human && human.currentMaterials.length > 0) {
removed = JSON.parse(JSON.stringify(human.currentMaterials.pop()));
}
});
return removed;
},
getLastMaterial: (modelUuid) => {
const human = get().humans.find(h => h.modelUuid === modelUuid);
if (human && human.currentMaterials.length > 0) {
return human.currentMaterials[human.currentMaterials.length - 1];
}
return undefined;
},
clearCurrentMaterials: (modelUuid) => {
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);
if (human) {
human.currentMaterials = [];
}
});
},
incrementActiveTime: (modelUuid, incrementBy) => {
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);
if (human) {
human.activeTime += incrementBy;
}
});
},
incrementIdleTime: (modelUuid, incrementBy) => {
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);
if (human) {
human.idleTime += incrementBy;
}
});
},
incrementDistanceTraveled: (modelUuid, incrementBy) => {
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);
if (human) {
human.distanceTraveled += incrementBy;
}
});
},
resetTime: (modelUuid) => {
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);
if (human) {
human.activeTime = 0;
human.idleTime = 0;
}
});
},
getHumanById: (modelUuid) => {
return get().humans.find(h => h.modelUuid === modelUuid);
},
getHumansByProduct: (productUuid) => {
return get().humans.filter(h => h.productUuid === productUuid);
},
getActiveHumans: () => {
return get().humans.filter(h => h.isActive);
}
}))
);
};
export type HumanStoreType = ReturnType<typeof createHumanStore>;

View File

@@ -32,13 +32,13 @@ type ProductsStore = {
productUuid: string,
modelUuid: string,
pointUuid: string,
action: ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']
action: ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] | HumanPointSchema['action']
) => EventsSchema | undefined;
removeAction: (productUuid: string, actionUuid: string) => EventsSchema | undefined;
updateAction: (
productUuid: string,
actionUuid: string,
updates: Partial<ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']>
updates: Partial<ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] | HumanPointSchema['action']>
) => EventsSchema | undefined;
// Trigger-level actionss
@@ -276,6 +276,15 @@ export const createProductStore = () => {
return;
}
}
} else if (event.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 = JSON.parse(JSON.stringify(event));
return;
}
}
} else if ('action' in point && point.action?.actionUuid === actionUuid) {
point.action = undefined;
updatedEvent = JSON.parse(JSON.stringify(event));

View File

@@ -146,6 +146,40 @@ export const useSelectedAction = create<SelectedActionState>()(
}))
);
interface SelectedAnimationState {
selectedAnimation: {
animationUuid: string;
animationName: string;
animationType: "behaviour" | "animatedTravel";
animation: string | null;
travelPoints?: { startPoint: [number, number, number] | null; endPoint: [number, number, number] | null; }
} | null;
setSelectedAnimation: (animation: {
animationUuid: string;
animationName: string;
animationType: "behaviour" | "animatedTravel";
animation: string | null;
travelPoints?: { startPoint: [number, number, number] | null; endPoint: [number, number, number] | null; }
}) => void;
clearSelectedAnimation: () => void;
}
export const useSelectedAnimation = create<SelectedAnimationState>()(
immer((set) => ({
selectedAnimation: null,
setSelectedAnimation: (animation) => {
set((state) => {
state.selectedAnimation = animation;
});
},
clearSelectedAnimation: () => {
set((state) => {
state.selectedAnimation = null;
});
},
}))
);
interface IsDraggingState {
isDragging: "start" | "end" | null;
setIsDragging: (state: "start" | "end" | null) => void;