feat: Refactor PickAndPlaceAction component to accept props for pick and place points; enhance RoboticArmMechanics with action handling and state management
This commit is contained in:
parent
a1a1eacb79
commit
d7a22f5bfb
|
@ -1,13 +1,25 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import EyeDropInput from "../../../../../ui/inputs/EyeDropInput";
|
import EyeDropInput from "../../../../../ui/inputs/EyeDropInput";
|
||||||
|
|
||||||
const PickAndPlaceAction: React.FC = () => {
|
interface PickAndPlaceActionProps {
|
||||||
return (
|
pickPointValue: string;
|
||||||
<>
|
pickPointOnChange: (value: string) => void;
|
||||||
<EyeDropInput label="Pick Point" value="na" onChange={() => {}} />
|
placePointValue: string;
|
||||||
<EyeDropInput label="Unload Point" value="na" onChange={() => {}} />
|
placePointOnChange: (value: string) => void;
|
||||||
</>
|
}
|
||||||
);
|
|
||||||
|
const PickAndPlaceAction: React.FC<PickAndPlaceActionProps> = ({
|
||||||
|
pickPointValue,
|
||||||
|
pickPointOnChange,
|
||||||
|
placePointValue,
|
||||||
|
placePointOnChange,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<EyeDropInput label="Pick Point" value={pickPointValue} onChange={pickPointOnChange} />
|
||||||
|
<EyeDropInput label="Unload Point" value={placePointValue} onChange={placePointOnChange} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default PickAndPlaceAction;
|
export default PickAndPlaceAction;
|
||||||
|
|
|
@ -4,7 +4,7 @@ import InputWithDropDown from '../../../../../ui/inputs/InputWithDropDown'
|
||||||
import RenameInput from '../../../../../ui/inputs/RenameInput'
|
import RenameInput from '../../../../../ui/inputs/RenameInput'
|
||||||
import LabledDropdown from '../../../../../ui/inputs/LabledDropdown'
|
import LabledDropdown from '../../../../../ui/inputs/LabledDropdown'
|
||||||
import Trigger from '../trigger/Trigger'
|
import Trigger from '../trigger/Trigger'
|
||||||
import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore";
|
import { useSelectedEventData, useSelectedProduct, useSelectedAction } from "../../../../../../store/simulation/useSimulationStore";
|
||||||
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
||||||
import { AddIcon, RemoveIcon, ResizeHeightIcon } from '../../../../../icons/ExportCommonIcons'
|
import { AddIcon, RemoveIcon, ResizeHeightIcon } from '../../../../../icons/ExportCommonIcons'
|
||||||
import { handleResize } from '../../../../../../functions/handleResizePannel'
|
import { handleResize } from '../../../../../../functions/handleResizePannel'
|
||||||
|
@ -12,159 +12,263 @@ import PickAndPlaceAction from '../actions/PickAndPlaceAction'
|
||||||
|
|
||||||
function RoboticArmMechanics() {
|
function RoboticArmMechanics() {
|
||||||
const actionsContainerRef = useRef<HTMLDivElement>(null);
|
const actionsContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
const [activeOption, setActiveOption] = useState<"default" | "pickAndPlace">("default");
|
||||||
const [activeOption, setActiveOption] = useState("pickAndPlace");
|
const [selectedPointData, setSelectedPointData] = useState<RoboticArmPointSchema | undefined>();
|
||||||
const [selectedItem, setSelectedItem] = useState<{ item: { uuid: string; name: string } | null; }>({ item: null });
|
|
||||||
const { selectedEventData } = useSelectedEventData();
|
const { selectedEventData } = useSelectedEventData();
|
||||||
const { getEventByModelUuid, addAction } = useProductStore();
|
const { getPointByUuid, updateEvent, updateAction, addAction, removeAction } = useProductStore();
|
||||||
const { selectedProduct } = useSelectedProduct();
|
const { selectedProduct } = useSelectedProduct();
|
||||||
|
const { selectedAction, setSelectedAction, clearSelectedAction } = useSelectedAction();
|
||||||
const availableActions = {
|
|
||||||
defaultOption: "pickAndPlace",
|
|
||||||
options: ["pickAndPlace"]
|
|
||||||
};
|
|
||||||
const [actions, setActions] = useState<{ uuid: string; name: string }[]>([]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const event = getCurrentEventData();
|
if (selectedEventData) {
|
||||||
const actionList = getActionList(event as RoboticArmEventSchema);
|
const point = getPointByUuid(
|
||||||
setActions(actionList);
|
selectedProduct.productId,
|
||||||
|
selectedEventData.data.modelUuid,
|
||||||
if (actionList.length > 0 && !selectedItem.item) {
|
selectedEventData.selectedPoint
|
||||||
setSelectedItem({ item: actionList[0] });
|
) as RoboticArmPointSchema | undefined;
|
||||||
|
if (point) {
|
||||||
|
setSelectedPointData(point);
|
||||||
|
setActiveOption(point.actions[0].actionType as "default" | "pickAndPlace");
|
||||||
|
if (point.actions.length > 0 && !selectedAction.actionId) {
|
||||||
|
setSelectedAction(point.actions[0].actionUuid, point.actions[0].actionName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
clearSelectedAction();
|
||||||
}
|
}
|
||||||
}, [selectedEventData, selectedProduct]);
|
}, [selectedEventData, selectedProduct]);
|
||||||
|
|
||||||
const getCurrentEventData = () => {
|
const handleActionSelect = (actionUuid: string, actionName: string) => {
|
||||||
if (!selectedEventData?.data || !selectedProduct) return null;
|
setSelectedAction(actionUuid, actionName);
|
||||||
return getEventByModelUuid(selectedProduct.productId, selectedEventData.data.modelUuid) || null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getActionList = (event: RoboticArmEventSchema) => {
|
|
||||||
if (!event || !('point' in event)) return [];
|
|
||||||
|
|
||||||
return event.point.actions.flatMap(
|
|
||||||
(action) =>
|
|
||||||
action.triggers.map((trigger) => ({
|
|
||||||
uuid: trigger.triggerUuid,
|
|
||||||
name: trigger.triggerName,
|
|
||||||
}))
|
|
||||||
) || [];
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleActionToggle = (actionUuid: string) => {
|
|
||||||
const action = actions.find(a => a.uuid === actionUuid);
|
|
||||||
if (action) {
|
|
||||||
setSelectedItem({ item: action });
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAddAction = () => {
|
const handleAddAction = () => {
|
||||||
if (selectedEventData) {
|
if (!selectedEventData || !selectedPointData) return;
|
||||||
const newEvent = {
|
|
||||||
actionUuid: THREE.MathUtils.generateUUID(),
|
const newAction = {
|
||||||
actionName: `Action ${actions.length + 1}`,
|
actionUuid: THREE.MathUtils.generateUUID(),
|
||||||
actionType: "pickAndPlace" as const,
|
actionName: `Action ${selectedPointData.actions.length + 1}`,
|
||||||
process: {
|
actionType: "pickAndPlace" as "pickAndPlace",
|
||||||
startPoint: null as [number, number, number] | null,
|
process: {
|
||||||
endPoint: null as [number, number, number] | null
|
startPoint: null,
|
||||||
},
|
endPoint: null
|
||||||
triggers: [] as TriggerSchema[]
|
},
|
||||||
}
|
triggers: [] as TriggerSchema[]
|
||||||
addAction(
|
};
|
||||||
selectedProduct.productId,
|
|
||||||
selectedEventData?.data.modelUuid,
|
addAction(
|
||||||
selectedEventData?.selectedPoint,
|
selectedProduct.productId,
|
||||||
newEvent
|
selectedEventData.data.modelUuid,
|
||||||
)
|
selectedEventData.selectedPoint,
|
||||||
}
|
newAction
|
||||||
|
);
|
||||||
|
|
||||||
|
const updatedPoint = {
|
||||||
|
...selectedPointData,
|
||||||
|
actions: [...selectedPointData.actions, newAction]
|
||||||
|
};
|
||||||
|
setSelectedPointData(updatedPoint);
|
||||||
|
setSelectedAction(newAction.actionUuid, newAction.actionName);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteAction = (actionUuid: string) => {
|
const handleDeleteAction = (actionUuid: string) => {
|
||||||
|
if (!selectedPointData) return;
|
||||||
|
|
||||||
|
removeAction(actionUuid);
|
||||||
|
const newActions = selectedPointData.actions.filter(a => a.actionUuid !== actionUuid);
|
||||||
|
|
||||||
|
const updatedPoint = {
|
||||||
|
...selectedPointData,
|
||||||
|
actions: newActions
|
||||||
|
};
|
||||||
|
setSelectedPointData(updatedPoint);
|
||||||
|
|
||||||
|
if (selectedAction.actionId === actionUuid) {
|
||||||
|
if (newActions.length > 0) {
|
||||||
|
setSelectedAction(newActions[0].actionUuid, newActions[0].actionName);
|
||||||
|
} else {
|
||||||
|
clearSelectedAction();
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleRenameAction = (newName: string) => {
|
||||||
|
if (!selectedAction.actionId) return;
|
||||||
|
updateAction(
|
||||||
|
selectedAction.actionId,
|
||||||
|
{ actionName: newName }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (selectedPointData) {
|
||||||
|
const updatedActions = selectedPointData.actions.map(action =>
|
||||||
|
action.actionUuid === selectedAction.actionId
|
||||||
|
? { ...action, actionName: newName }
|
||||||
|
: action
|
||||||
|
);
|
||||||
|
setSelectedPointData({
|
||||||
|
...selectedPointData,
|
||||||
|
actions: updatedActions
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSpeedChange = (value: string) => {
|
||||||
|
if (!selectedEventData) return;
|
||||||
|
updateEvent(
|
||||||
|
selectedProduct.productId,
|
||||||
|
selectedEventData.data.modelUuid,
|
||||||
|
{ speed: parseFloat(value) }
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePickPointChange = (value: string) => {
|
||||||
|
if (!selectedAction.actionId || !selectedPointData) return;
|
||||||
|
const [x, y, z] = value.split(',').map(Number);
|
||||||
|
|
||||||
|
updateAction(
|
||||||
|
selectedAction.actionId,
|
||||||
|
{
|
||||||
|
process: {
|
||||||
|
startPoint: [x, y, z] as [number, number, number],
|
||||||
|
endPoint: selectedPointData.actions.find(a => a.actionUuid === selectedAction.actionId)?.process.endPoint || null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePlacePointChange = (value: string) => {
|
||||||
|
if (!selectedAction.actionId || !selectedPointData) return;
|
||||||
|
const [x, y, z] = value.split(',').map(Number);
|
||||||
|
|
||||||
|
updateAction(
|
||||||
|
selectedAction.actionId,
|
||||||
|
{
|
||||||
|
process: {
|
||||||
|
startPoint: selectedPointData.actions.find(a => a.actionUuid === selectedAction.actionId)?.process.startPoint || null,
|
||||||
|
endPoint: [x, y, z] as [number, number, number]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const availableActions = {
|
||||||
|
defaultOption: "pickAndPlace",
|
||||||
|
options: ["pickAndPlace"],
|
||||||
|
};
|
||||||
|
|
||||||
|
const currentSpeed = selectedEventData?.data.type === "roboticArm"
|
||||||
|
? selectedEventData.data.speed.toString()
|
||||||
|
: "0.5";
|
||||||
|
|
||||||
|
const currentAction = selectedPointData?.actions.find(a => a.actionUuid === selectedAction.actionId);
|
||||||
|
const currentPickPoint = currentAction?.process.startPoint
|
||||||
|
? `${currentAction.process.startPoint[0]},${currentAction.process.startPoint[1]},${currentAction.process.startPoint[2]}`
|
||||||
|
: "";
|
||||||
|
const currentPlacePoint = currentAction?.process.endPoint
|
||||||
|
? `${currentAction.process.endPoint[0]},${currentAction.process.endPoint[1]},${currentAction.process.endPoint[2]}`
|
||||||
|
: "";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="global-props">
|
{selectedEventData && selectedPointData && (
|
||||||
<div className="property-list-container">
|
<>
|
||||||
<div className="property-item">
|
<div className="global-props">
|
||||||
<InputWithDropDown
|
<div className="property-list-container">
|
||||||
label="Speed"
|
<div className="property-item">
|
||||||
value="0.5"
|
<InputWithDropDown
|
||||||
min={0}
|
label="Speed"
|
||||||
step={0.1}
|
value={currentSpeed}
|
||||||
defaultValue={'0.5'}
|
min={0}
|
||||||
max={10}
|
step={0.1}
|
||||||
activeOption="s"
|
defaultValue={"0.5"}
|
||||||
onClick={() => { }}
|
max={10}
|
||||||
onChange={(value) => console.log(value)}
|
activeOption="m/s"
|
||||||
/>
|
onClick={() => { }}
|
||||||
</div>
|
onChange={handleSpeedChange}
|
||||||
</div>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="actions-list-container">
|
|
||||||
<div className="actions">
|
|
||||||
<div className="header">
|
|
||||||
<div className="header-value">Actions</div>
|
|
||||||
<div className="add-button" onClick={() => handleAddAction()}>
|
|
||||||
<AddIcon /> Add
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
|
||||||
className="lists-main-container"
|
<div className="actions-list-container">
|
||||||
ref={actionsContainerRef}
|
<div className="actions">
|
||||||
style={{ height: "120px" }}
|
<div className="header">
|
||||||
>
|
<div className="header-value">Actions</div>
|
||||||
<div className="list-container">
|
<div className="add-button" onClick={handleAddAction}>
|
||||||
{actions.map((action) => (
|
<AddIcon /> Add
|
||||||
<div
|
|
||||||
key={action.uuid}
|
|
||||||
className={`list-item ${selectedItem.item?.uuid === action.uuid ? "active" : ""}`}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="value"
|
|
||||||
onClick={() => handleActionToggle(action.uuid)}
|
|
||||||
>
|
|
||||||
<RenameInput value={action.name} />
|
|
||||||
</div>
|
|
||||||
{actions.length > 1 && (
|
|
||||||
<div
|
|
||||||
className="remove-button"
|
|
||||||
onClick={() => handleDeleteAction(action.uuid)}
|
|
||||||
>
|
|
||||||
<RemoveIcon />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
</div>
|
||||||
</div>
|
<div
|
||||||
<div
|
className="lists-main-container"
|
||||||
className="resize-icon"
|
ref={actionsContainerRef}
|
||||||
id="action-resize"
|
style={{ height: "120px" }}
|
||||||
onMouseDown={(e) => handleResize(e, actionsContainerRef)}
|
>
|
||||||
>
|
<div className="list-container">
|
||||||
<ResizeHeightIcon />
|
{selectedPointData.actions.map((action) => (
|
||||||
|
<div
|
||||||
|
key={action.actionUuid}
|
||||||
|
className={`list-item ${selectedAction.actionId === action.actionUuid ? "active" : ""}`}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="value"
|
||||||
|
onClick={() => handleActionSelect(action.actionUuid, action.actionName)}
|
||||||
|
>
|
||||||
|
<RenameInput
|
||||||
|
value={action.actionName}
|
||||||
|
onRename={handleRenameAction}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{selectedPointData.actions.length > 1 && (
|
||||||
|
<div
|
||||||
|
className="remove-button"
|
||||||
|
onClick={() => handleDeleteAction(action.actionUuid)}
|
||||||
|
>
|
||||||
|
<RemoveIcon />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="resize-icon"
|
||||||
|
id="action-resize"
|
||||||
|
onMouseDown={(e) => handleResize(e, actionsContainerRef)}
|
||||||
|
>
|
||||||
|
<ResizeHeightIcon />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
{selectedAction.actionId && currentAction && (
|
||||||
<div className="selected-actions-details">
|
<div className="selected-actions-details">
|
||||||
<div className="selected-actions-header">
|
<div className="selected-actions-header">
|
||||||
<RenameInput value={selectedItem.item?.name || "Action Name"} />
|
<RenameInput
|
||||||
</div>
|
value={selectedAction.actionName}
|
||||||
<div className="selected-actions-list">
|
onRename={handleRenameAction}
|
||||||
<LabledDropdown
|
/>
|
||||||
defaultOption={availableActions.defaultOption}
|
</div>
|
||||||
options={availableActions.options}
|
<div className="selected-actions-list">
|
||||||
onSelect={(option) => setActiveOption(option)}
|
<LabledDropdown
|
||||||
/>
|
defaultOption={activeOption}
|
||||||
{activeOption === "pickAndPlace" && <PickAndPlaceAction />}
|
options={availableActions.options}
|
||||||
</div>
|
onSelect={() => { }}
|
||||||
</div>
|
disabled={true}
|
||||||
<div className="tirgger">
|
/>
|
||||||
<Trigger />
|
<PickAndPlaceAction
|
||||||
</div>
|
pickPointValue={currentPickPoint}
|
||||||
|
pickPointOnChange={handlePickPointChange}
|
||||||
|
placePointValue={currentPlacePoint}
|
||||||
|
placePointOnChange={handlePlacePointChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="tirgger">
|
||||||
|
<Trigger />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,9 +142,6 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('newName: ', newName);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
const checkZoneNameDuplicate = (name: string) => {
|
const checkZoneNameDuplicate = (name: string) => {
|
||||||
return zones.some(
|
return zones.some(
|
||||||
|
|
|
@ -94,6 +94,8 @@ function RoboticArm() {
|
||||||
|
|
||||||
<RoboticArmInstances />
|
<RoboticArmInstances />
|
||||||
|
|
||||||
|
<></>
|
||||||
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ function Simulation() {
|
||||||
}, [events])
|
}, [events])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// console.log('products: ', products);
|
console.log('products: ', products);
|
||||||
}, [products])
|
}, [products])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -90,4 +90,28 @@ export const useSelectedProduct = create<SelectedProductState>()(
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
|
interface SelectedActionState {
|
||||||
|
selectedAction: { actionId: string; actionName: string };
|
||||||
|
setSelectedAction: (actionId: string, actionName: string) => void;
|
||||||
|
clearSelectedAction: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useSelectedAction = create<SelectedActionState>()(
|
||||||
|
immer((set) => ({
|
||||||
|
selectedAction: { actionId: '', actionName: '' },
|
||||||
|
setSelectedAction: (actionId, actionName) => {
|
||||||
|
set((state) => {
|
||||||
|
state.selectedAction.actionId = actionId;
|
||||||
|
state.selectedAction.actionName = actionName;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
clearSelectedAction: () => {
|
||||||
|
set((state) => {
|
||||||
|
state.selectedAction.actionId = '';
|
||||||
|
state.selectedAction.actionName = '';
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}))
|
||||||
);
|
);
|
Loading…
Reference in New Issue