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 EyeDropInput from "../../../../../ui/inputs/EyeDropInput";
|
||||
|
||||
const PickAndPlaceAction: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<EyeDropInput label="Pick Point" value="na" onChange={() => {}} />
|
||||
<EyeDropInput label="Unload Point" value="na" onChange={() => {}} />
|
||||
</>
|
||||
);
|
||||
interface PickAndPlaceActionProps {
|
||||
pickPointValue: string;
|
||||
pickPointOnChange: (value: string) => void;
|
||||
placePointValue: string;
|
||||
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;
|
||||
|
|
|
@ -4,7 +4,7 @@ import InputWithDropDown from '../../../../../ui/inputs/InputWithDropDown'
|
|||
import RenameInput from '../../../../../ui/inputs/RenameInput'
|
||||
import LabledDropdown from '../../../../../ui/inputs/LabledDropdown'
|
||||
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 { AddIcon, RemoveIcon, ResizeHeightIcon } from '../../../../../icons/ExportCommonIcons'
|
||||
import { handleResize } from '../../../../../../functions/handleResizePannel'
|
||||
|
@ -12,159 +12,263 @@ import PickAndPlaceAction from '../actions/PickAndPlaceAction'
|
|||
|
||||
function RoboticArmMechanics() {
|
||||
const actionsContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const [activeOption, setActiveOption] = useState("pickAndPlace");
|
||||
const [selectedItem, setSelectedItem] = useState<{ item: { uuid: string; name: string } | null; }>({ item: null });
|
||||
const [activeOption, setActiveOption] = useState<"default" | "pickAndPlace">("default");
|
||||
const [selectedPointData, setSelectedPointData] = useState<RoboticArmPointSchema | undefined>();
|
||||
const { selectedEventData } = useSelectedEventData();
|
||||
const { getEventByModelUuid, addAction } = useProductStore();
|
||||
const { getPointByUuid, updateEvent, updateAction, addAction, removeAction } = useProductStore();
|
||||
const { selectedProduct } = useSelectedProduct();
|
||||
|
||||
const availableActions = {
|
||||
defaultOption: "pickAndPlace",
|
||||
options: ["pickAndPlace"]
|
||||
};
|
||||
const [actions, setActions] = useState<{ uuid: string; name: string }[]>([]);
|
||||
const { selectedAction, setSelectedAction, clearSelectedAction } = useSelectedAction();
|
||||
|
||||
useEffect(() => {
|
||||
const event = getCurrentEventData();
|
||||
const actionList = getActionList(event as RoboticArmEventSchema);
|
||||
setActions(actionList);
|
||||
|
||||
if (actionList.length > 0 && !selectedItem.item) {
|
||||
setSelectedItem({ item: actionList[0] });
|
||||
if (selectedEventData) {
|
||||
const point = getPointByUuid(
|
||||
selectedProduct.productId,
|
||||
selectedEventData.data.modelUuid,
|
||||
selectedEventData.selectedPoint
|
||||
) 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]);
|
||||
|
||||
const getCurrentEventData = () => {
|
||||
if (!selectedEventData?.data || !selectedProduct) return null;
|
||||
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 handleActionSelect = (actionUuid: string, actionName: string) => {
|
||||
setSelectedAction(actionUuid, actionName);
|
||||
};
|
||||
|
||||
const handleAddAction = () => {
|
||||
if (selectedEventData) {
|
||||
const newEvent = {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: `Action ${actions.length + 1}`,
|
||||
actionType: "pickAndPlace" as const,
|
||||
process: {
|
||||
startPoint: null as [number, number, number] | null,
|
||||
endPoint: null as [number, number, number] | null
|
||||
},
|
||||
triggers: [] as TriggerSchema[]
|
||||
}
|
||||
addAction(
|
||||
selectedProduct.productId,
|
||||
selectedEventData?.data.modelUuid,
|
||||
selectedEventData?.selectedPoint,
|
||||
newEvent
|
||||
)
|
||||
}
|
||||
if (!selectedEventData || !selectedPointData) return;
|
||||
|
||||
const newAction = {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: `Action ${selectedPointData.actions.length + 1}`,
|
||||
actionType: "pickAndPlace" as "pickAndPlace",
|
||||
process: {
|
||||
startPoint: null,
|
||||
endPoint: null
|
||||
},
|
||||
triggers: [] as TriggerSchema[]
|
||||
};
|
||||
|
||||
addAction(
|
||||
selectedProduct.productId,
|
||||
selectedEventData.data.modelUuid,
|
||||
selectedEventData.selectedPoint,
|
||||
newAction
|
||||
);
|
||||
|
||||
const updatedPoint = {
|
||||
...selectedPointData,
|
||||
actions: [...selectedPointData.actions, newAction]
|
||||
};
|
||||
setSelectedPointData(updatedPoint);
|
||||
setSelectedAction(newAction.actionUuid, newAction.actionName);
|
||||
};
|
||||
|
||||
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 (
|
||||
<>
|
||||
<div className="global-props">
|
||||
<div className="property-list-container">
|
||||
<div className="property-item">
|
||||
<InputWithDropDown
|
||||
label="Speed"
|
||||
value="0.5"
|
||||
min={0}
|
||||
step={0.1}
|
||||
defaultValue={'0.5'}
|
||||
max={10}
|
||||
activeOption="s"
|
||||
onClick={() => { }}
|
||||
onChange={(value) => console.log(value)}
|
||||
/>
|
||||
</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
|
||||
{selectedEventData && selectedPointData && (
|
||||
<>
|
||||
<div className="global-props">
|
||||
<div className="property-list-container">
|
||||
<div className="property-item">
|
||||
<InputWithDropDown
|
||||
label="Speed"
|
||||
value={currentSpeed}
|
||||
min={0}
|
||||
step={0.1}
|
||||
defaultValue={"0.5"}
|
||||
max={10}
|
||||
activeOption="m/s"
|
||||
onClick={() => { }}
|
||||
onChange={handleSpeedChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="lists-main-container"
|
||||
ref={actionsContainerRef}
|
||||
style={{ height: "120px" }}
|
||||
>
|
||||
<div className="list-container">
|
||||
{actions.map((action) => (
|
||||
<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 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
|
||||
className="resize-icon"
|
||||
id="action-resize"
|
||||
onMouseDown={(e) => handleResize(e, actionsContainerRef)}
|
||||
>
|
||||
<ResizeHeightIcon />
|
||||
</div>
|
||||
<div
|
||||
className="lists-main-container"
|
||||
ref={actionsContainerRef}
|
||||
style={{ height: "120px" }}
|
||||
>
|
||||
<div className="list-container">
|
||||
{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 className="selected-actions-details">
|
||||
<div className="selected-actions-header">
|
||||
<RenameInput value={selectedItem.item?.name || "Action Name"} />
|
||||
</div>
|
||||
<div className="selected-actions-list">
|
||||
<LabledDropdown
|
||||
defaultOption={availableActions.defaultOption}
|
||||
options={availableActions.options}
|
||||
onSelect={(option) => setActiveOption(option)}
|
||||
/>
|
||||
{activeOption === "pickAndPlace" && <PickAndPlaceAction />}
|
||||
</div>
|
||||
</div>
|
||||
<div className="tirgger">
|
||||
<Trigger />
|
||||
</div>
|
||||
|
||||
{selectedAction.actionId && currentAction && (
|
||||
<div className="selected-actions-details">
|
||||
<div className="selected-actions-header">
|
||||
<RenameInput
|
||||
value={selectedAction.actionName}
|
||||
onRename={handleRenameAction}
|
||||
/>
|
||||
</div>
|
||||
<div className="selected-actions-list">
|
||||
<LabledDropdown
|
||||
defaultOption={activeOption}
|
||||
options={availableActions.options}
|
||||
onSelect={() => { }}
|
||||
disabled={true}
|
||||
/>
|
||||
<PickAndPlaceAction
|
||||
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) => {
|
||||
return zones.some(
|
||||
|
|
|
@ -94,6 +94,8 @@ function RoboticArm() {
|
|||
|
||||
<RoboticArmInstances />
|
||||
|
||||
<></>
|
||||
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ function Simulation() {
|
|||
}, [events])
|
||||
|
||||
useEffect(() => {
|
||||
// console.log('products: ', products);
|
||||
console.log('products: ', products);
|
||||
}, [products])
|
||||
|
||||
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