added undo redo for builder (not for simulation data)
This commit is contained in:
@@ -30,11 +30,11 @@ export function useModelEventHandlers({
|
|||||||
const { toggleView } = useToggleView();
|
const { toggleView } = useToggleView();
|
||||||
const { subModule } = useSubModuleStore();
|
const { subModule } = useSubModuleStore();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const { eventStore, productStore, assetStore } = useSceneContext();
|
const { eventStore, productStore, assetStore, undoRedo3DStore } = useSceneContext();
|
||||||
|
const { push3D } = undoRedo3DStore();
|
||||||
const { removeAsset } = assetStore();
|
const { removeAsset } = assetStore();
|
||||||
const { removeEvent } = eventStore();
|
const { removeEvent, getEventByModelUuid } = eventStore();
|
||||||
const { getIsEventInProduct, addPoint, deleteEvent } = productStore();
|
const { getIsEventInProduct, addPoint, deleteEvent } = productStore();
|
||||||
const { getEventByModelUuid } = eventStore();
|
|
||||||
const { setSelectedAsset, clearSelectedAsset } = useSelectedAsset();
|
const { setSelectedAsset, clearSelectedAsset } = useSelectedAsset();
|
||||||
const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
|
const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
|
||||||
const { setSelectedFloorItem } = useSelectedFloorItem();
|
const { setSelectedFloorItem } = useSelectedFloorItem();
|
||||||
@@ -152,6 +152,21 @@ export function useModelEventHandlers({
|
|||||||
|
|
||||||
removeAsset(asset.modelUuid);
|
removeAsset(asset.modelUuid);
|
||||||
|
|
||||||
|
push3D({
|
||||||
|
type: 'Scene',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
module: "builder",
|
||||||
|
actionType: "Asset-Delete",
|
||||||
|
asset: {
|
||||||
|
type: "Asset",
|
||||||
|
assetData: asset,
|
||||||
|
timeStap: new Date().toISOString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
echo.success("Model Removed!");
|
echo.success("Model Removed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import useModuleStore from '../../../../../store/useModuleStore';
|
|||||||
import { useSceneContext } from '../../../../scene/sceneContext';
|
import { useSceneContext } from '../../../../scene/sceneContext';
|
||||||
import { SkeletonUtils } from 'three-stdlib';
|
import { SkeletonUtils } from 'three-stdlib';
|
||||||
|
|
||||||
import { getAssetIksApi } from '../../../../../services/simulation/ik/getAssetIKs';
|
import { getAssetFieldApi } from '../../../../../services/factoryBuilder/asset/floorAsset/getAssetField';
|
||||||
import { ModelAnimator } from './animator/modelAnimator';
|
import { ModelAnimator } from './animator/modelAnimator';
|
||||||
import { useModelEventHandlers } from './eventHandlers/useEventHandlers';
|
import { useModelEventHandlers } from './eventHandlers/useEventHandlers';
|
||||||
|
|
||||||
@@ -26,19 +26,31 @@ function Model({ asset, isRendered, loader }: { readonly asset: Asset, isRendere
|
|||||||
const [boundingBox, setBoundingBox] = useState<THREE.Box3 | null>(null);
|
const [boundingBox, setBoundingBox] = useState<THREE.Box3 | null>(null);
|
||||||
const [isSelected, setIsSelected] = useState(false);
|
const [isSelected, setIsSelected] = useState(false);
|
||||||
const groupRef = useRef<THREE.Group>(null);
|
const groupRef = useRef<THREE.Group>(null);
|
||||||
const [ikData, setIkData] = useState<any>();
|
const [fieldData, setFieldData] = useState<any>();
|
||||||
const { selectedAssets } = useSelectedAssets();
|
const { selectedAssets } = useSelectedAssets();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!ikData && asset.eventData && asset.eventData.type === 'ArmBot') {
|
if (!fieldData && asset.eventData) {
|
||||||
getAssetIksApi(asset.assetId).then((data) => {
|
getAssetFieldApi(asset.assetId).then((data) => {
|
||||||
if (data.iks) {
|
if (data.type === 'ArmBot') {
|
||||||
const iks: IK[] = data.iks;
|
if (data.data) {
|
||||||
setIkData(iks);
|
const fieldData: IK[] = data.data;
|
||||||
|
setFieldData(fieldData);
|
||||||
|
}
|
||||||
|
} else if (data.type === 'Conveyor') {
|
||||||
|
if (data.data) {
|
||||||
|
const fieldData = data.data;
|
||||||
|
setFieldData(fieldData);
|
||||||
|
}
|
||||||
|
} else if (data.type === 'Crane') {
|
||||||
|
if (data.data) {
|
||||||
|
const fieldData = data.data;
|
||||||
|
setFieldData(fieldData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, [asset.modelUuid, ikData])
|
}, [asset.modelUuid, fieldData])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setDeletableFloorItem(null);
|
setDeletableFloorItem(null);
|
||||||
@@ -157,7 +169,7 @@ function Model({ asset, isRendered, loader }: { readonly asset: Asset, isRendere
|
|||||||
position={asset.position}
|
position={asset.position}
|
||||||
rotation={asset.rotation}
|
rotation={asset.rotation}
|
||||||
visible={asset.isVisible}
|
visible={asset.isVisible}
|
||||||
userData={{ ...asset, iks: ikData }}
|
userData={{ ...asset, fieldData: fieldData }}
|
||||||
castShadow
|
castShadow
|
||||||
receiveShadow
|
receiveShadow
|
||||||
onDoubleClick={(e) => {
|
onDoubleClick={(e) => {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { getUserData } from "../../../functions/getUserData";
|
|||||||
|
|
||||||
import SelectionControls2D from "./selectionControls/selection2D/selectionControls2D";
|
import SelectionControls2D from "./selectionControls/selection2D/selectionControls2D";
|
||||||
import UndoRedo2DControls from "./undoRedoControls/undoRedo2D/undoRedo2DControls";
|
import UndoRedo2DControls from "./undoRedoControls/undoRedo2D/undoRedo2DControls";
|
||||||
|
import UndoRedo3DControls from "./undoRedoControls/undoRedo3D/undoRedo3DControls";
|
||||||
|
|
||||||
export default function Controls() {
|
export default function Controls() {
|
||||||
const controlsRef = useRef<CameraControls>(null);
|
const controlsRef = useRef<CameraControls>(null);
|
||||||
@@ -144,6 +145,8 @@ export default function Controls() {
|
|||||||
|
|
||||||
<UndoRedo2DControls />
|
<UndoRedo2DControls />
|
||||||
|
|
||||||
|
<UndoRedo3DControls />
|
||||||
|
|
||||||
<TransformControl />
|
<TransformControl />
|
||||||
|
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ const CopyPasteControls3D = ({
|
|||||||
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
||||||
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const { assetStore, eventStore } = useSceneContext();
|
const { assetStore, eventStore, undoRedo3DStore } = useSceneContext();
|
||||||
|
const { push3D } = undoRedo3DStore();
|
||||||
const { addEvent } = eventStore();
|
const { addEvent } = eventStore();
|
||||||
const { projectId } = useParams();
|
const { projectId } = useParams();
|
||||||
const { assets, addAsset, updateAsset, removeAsset, getAssetById } = assetStore();
|
const { assets, addAsset, updateAsset, removeAsset, getAssetById } = assetStore();
|
||||||
@@ -198,6 +199,9 @@ const CopyPasteControls3D = ({
|
|||||||
const addPastedObjects = () => {
|
const addPastedObjects = () => {
|
||||||
if (pastedObjects.length === 0) return;
|
if (pastedObjects.length === 0) return;
|
||||||
|
|
||||||
|
const undoActions: UndoRedo3DAction[] = [];
|
||||||
|
const assetsToCopy: AssetData[] = [];
|
||||||
|
|
||||||
pastedObjects.forEach(async (pastedAsset: THREE.Object3D) => {
|
pastedObjects.forEach(async (pastedAsset: THREE.Object3D) => {
|
||||||
if (pastedAsset) {
|
if (pastedAsset) {
|
||||||
const assetUuid = pastedAsset.userData.modelUuid;
|
const assetUuid = pastedAsset.userData.modelUuid;
|
||||||
@@ -529,9 +533,45 @@ const CopyPasteControls3D = ({
|
|||||||
|
|
||||||
updateAsset(asset.modelUuid, asset);
|
updateAsset(asset.modelUuid, asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assetsToCopy.push({
|
||||||
|
type: "Asset",
|
||||||
|
assetData: {
|
||||||
|
modelUuid: newFloorItem.modelUuid,
|
||||||
|
modelName: newFloorItem.modelName,
|
||||||
|
assetId: newFloorItem.assetId,
|
||||||
|
position: [position.x, position.y, position.z],
|
||||||
|
rotation: [pastedAsset.rotation.x, pastedAsset.rotation.y, pastedAsset.rotation.z],
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
isCollidable: false,
|
||||||
|
opacity: 1,
|
||||||
|
eventData: newFloorItem.eventData || undefined
|
||||||
|
},
|
||||||
|
timeStap: new Date().toISOString()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (assetsToCopy.length === 1) {
|
||||||
|
undoActions.push({
|
||||||
|
module: "builder",
|
||||||
|
actionType: "Asset-Copied",
|
||||||
|
asset: assetsToCopy[0]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
undoActions.push({
|
||||||
|
module: "builder",
|
||||||
|
actionType: "Assets-Copied",
|
||||||
|
assets: assetsToCopy
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
push3D({
|
||||||
|
type: 'Scene',
|
||||||
|
actions: undoActions
|
||||||
|
});
|
||||||
|
|
||||||
echo.success("Object added!");
|
echo.success("Object added!");
|
||||||
clearSelection();
|
clearSelection();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ const DuplicationControls3D = ({
|
|||||||
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
||||||
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const { assetStore, eventStore } = useSceneContext();
|
const { assetStore, eventStore, undoRedo3DStore } = useSceneContext();
|
||||||
|
const { push3D } = undoRedo3DStore();
|
||||||
const { addEvent } = eventStore();
|
const { addEvent } = eventStore();
|
||||||
const { projectId } = useParams();
|
const { projectId } = useParams();
|
||||||
const { assets, addAsset, updateAsset, removeAsset, getAssetById } = assetStore();
|
const { assets, addAsset, updateAsset, removeAsset, getAssetById } = assetStore();
|
||||||
@@ -199,6 +200,9 @@ const DuplicationControls3D = ({
|
|||||||
const addDuplicatedAssets = () => {
|
const addDuplicatedAssets = () => {
|
||||||
if (duplicatedObjects.length === 0) return;
|
if (duplicatedObjects.length === 0) return;
|
||||||
|
|
||||||
|
const undoActions: UndoRedo3DAction[] = [];
|
||||||
|
const assetsToDuplicate: AssetData[] = [];
|
||||||
|
|
||||||
duplicatedObjects.forEach(async (duplicatedAsset: THREE.Object3D) => {
|
duplicatedObjects.forEach(async (duplicatedAsset: THREE.Object3D) => {
|
||||||
if (duplicatedAsset) {
|
if (duplicatedAsset) {
|
||||||
const assetUuid = duplicatedAsset.userData.modelUuid;
|
const assetUuid = duplicatedAsset.userData.modelUuid;
|
||||||
@@ -530,9 +534,45 @@ const DuplicationControls3D = ({
|
|||||||
|
|
||||||
updateAsset(asset.modelUuid, asset);
|
updateAsset(asset.modelUuid, asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assetsToDuplicate.push({
|
||||||
|
type: "Asset",
|
||||||
|
assetData: {
|
||||||
|
modelUuid: newFloorItem.modelUuid,
|
||||||
|
modelName: newFloorItem.modelName,
|
||||||
|
assetId: newFloorItem.assetId,
|
||||||
|
position: [position.x, position.y, position.z],
|
||||||
|
rotation: [duplicatedAsset.rotation.x, duplicatedAsset.rotation.y, duplicatedAsset.rotation.z],
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
isCollidable: false,
|
||||||
|
opacity: 1,
|
||||||
|
eventData: newFloorItem.eventData || undefined
|
||||||
|
},
|
||||||
|
timeStap: new Date().toISOString()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (assetsToDuplicate.length === 1) {
|
||||||
|
undoActions.push({
|
||||||
|
module: "builder",
|
||||||
|
actionType: "Asset-Copied",
|
||||||
|
asset: assetsToDuplicate[0]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
undoActions.push({
|
||||||
|
module: "builder",
|
||||||
|
actionType: "Assets-Copied",
|
||||||
|
assets: assetsToDuplicate
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
push3D({
|
||||||
|
type: 'Scene',
|
||||||
|
actions: undoActions
|
||||||
|
});
|
||||||
|
|
||||||
echo.success("Object duplicated!");
|
echo.success("Object duplicated!");
|
||||||
clearSelection();
|
clearSelection();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ function MoveControls3D({
|
|||||||
const [keyEvent, setKeyEvent] = useState<"Ctrl" | "Shift" | "Ctrl+Shift" | "">("");
|
const [keyEvent, setKeyEvent] = useState<"Ctrl" | "Shift" | "Ctrl+Shift" | "">("");
|
||||||
const { userId, organization } = getUserData();
|
const { userId, organization } = getUserData();
|
||||||
const { projectId } = useParams();
|
const { projectId } = useParams();
|
||||||
const { assetStore, eventStore, productStore } = useSceneContext();
|
const { assetStore, eventStore, productStore, undoRedo3DStore } = useSceneContext();
|
||||||
|
const { push3D } = undoRedo3DStore();
|
||||||
const { updateAsset, getAssetById } = assetStore();
|
const { updateAsset, getAssetById } = assetStore();
|
||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
const { selectedVersion } = selectedVersionStore();
|
const { selectedVersion } = selectedVersionStore();
|
||||||
@@ -284,6 +285,9 @@ function MoveControls3D({
|
|||||||
const placeMovedAssets = () => {
|
const placeMovedAssets = () => {
|
||||||
if (movedObjects.length === 0) return;
|
if (movedObjects.length === 0) return;
|
||||||
|
|
||||||
|
const undoActions: UndoRedo3DAction[] = [];
|
||||||
|
const assetsToUpdate: AssetData[] = [];
|
||||||
|
|
||||||
movedObjects.forEach(async (movedAsset: THREE.Object3D) => {
|
movedObjects.forEach(async (movedAsset: THREE.Object3D) => {
|
||||||
if (movedAsset) {
|
if (movedAsset) {
|
||||||
const assetUuid = movedAsset.userData.modelUuid;
|
const assetUuid = movedAsset.userData.modelUuid;
|
||||||
@@ -291,6 +295,32 @@ function MoveControls3D({
|
|||||||
const model = scene.getObjectByProperty("uuid", movedAsset.userData.modelUuid);
|
const model = scene.getObjectByProperty("uuid", movedAsset.userData.modelUuid);
|
||||||
if (!asset || !model) return;
|
if (!asset || !model) return;
|
||||||
const position = new THREE.Vector3().copy(model.position);
|
const position = new THREE.Vector3().copy(model.position);
|
||||||
|
const initialState = initialStates[movedAsset.uuid];
|
||||||
|
|
||||||
|
if (initialState) {
|
||||||
|
assetsToUpdate.push({
|
||||||
|
type: "Asset",
|
||||||
|
assetData: {
|
||||||
|
...asset,
|
||||||
|
position: [
|
||||||
|
initialState.position.x,
|
||||||
|
initialState.position.y,
|
||||||
|
initialState.position.z
|
||||||
|
],
|
||||||
|
rotation: [
|
||||||
|
initialState.rotation?.x || 0,
|
||||||
|
initialState.rotation?.y || 0,
|
||||||
|
initialState.rotation?.z || 0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
newData: {
|
||||||
|
...asset,
|
||||||
|
position: [position.x, position.y, position.z],
|
||||||
|
rotation: [movedAsset.rotation.x, movedAsset.rotation.y, movedAsset.rotation.z]
|
||||||
|
},
|
||||||
|
timeStap: new Date().toISOString()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const newFloorItem: Types.FloorItemType = {
|
const newFloorItem: Types.FloorItemType = {
|
||||||
modelUuid: movedAsset.userData.modelUuid,
|
modelUuid: movedAsset.userData.modelUuid,
|
||||||
@@ -368,6 +398,27 @@ function MoveControls3D({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (assetsToUpdate.length > 0) {
|
||||||
|
if (assetsToUpdate.length === 1) {
|
||||||
|
undoActions.push({
|
||||||
|
module: "builder",
|
||||||
|
actionType: "Asset-Update",
|
||||||
|
asset: assetsToUpdate[0]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
undoActions.push({
|
||||||
|
module: "builder",
|
||||||
|
actionType: "Assets-Update",
|
||||||
|
assets: assetsToUpdate
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
push3D({
|
||||||
|
type: 'Scene',
|
||||||
|
actions: undoActions
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
echo.success("Object moved!");
|
echo.success("Object moved!");
|
||||||
setIsMoving(false);
|
setIsMoving(false);
|
||||||
clearSelection();
|
clearSelection();
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ function RotateControls3D({
|
|||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const { userId, organization } = getUserData();
|
const { userId, organization } = getUserData();
|
||||||
const { projectId } = useParams();
|
const { projectId } = useParams();
|
||||||
const { assetStore, eventStore, productStore } = useSceneContext();
|
const { assetStore, eventStore, productStore, undoRedo3DStore } = useSceneContext();
|
||||||
|
const { push3D } = undoRedo3DStore();
|
||||||
const { updateAsset } = assetStore();
|
const { updateAsset } = assetStore();
|
||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
const { selectedVersion } = selectedVersionStore();
|
const { selectedVersion } = selectedVersionStore();
|
||||||
@@ -222,12 +223,43 @@ function RotateControls3D({
|
|||||||
const placeRotatedAssets = useCallback(() => {
|
const placeRotatedAssets = useCallback(() => {
|
||||||
if (rotatedObjects.length === 0) return;
|
if (rotatedObjects.length === 0) return;
|
||||||
|
|
||||||
|
const undoActions: UndoRedo3DAction[] = [];
|
||||||
|
const assetsToUpdate: AssetData[] = [];
|
||||||
|
|
||||||
rotatedObjects.forEach((obj: THREE.Object3D) => {
|
rotatedObjects.forEach((obj: THREE.Object3D) => {
|
||||||
if (obj && obj.userData.modelUuid) {
|
if (obj && obj.userData.modelUuid) {
|
||||||
|
const asset = assetStore.getState().getAssetById(obj.userData.modelUuid);
|
||||||
|
if (!asset) return;
|
||||||
|
|
||||||
const rotationArray: [number, number, number] = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
|
const rotationArray: [number, number, number] = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
|
||||||
|
|
||||||
const positionArray: [number, number, number] = [obj.position.x, obj.position.y, obj.position.z];
|
const positionArray: [number, number, number] = [obj.position.x, obj.position.y, obj.position.z];
|
||||||
|
|
||||||
|
if (initialRotations[obj.uuid] && initialPositions[obj.uuid]) {
|
||||||
|
assetsToUpdate.push({
|
||||||
|
type: "Asset",
|
||||||
|
assetData: {
|
||||||
|
...asset,
|
||||||
|
position: [
|
||||||
|
initialPositions[obj.uuid].x,
|
||||||
|
initialPositions[obj.uuid].y,
|
||||||
|
initialPositions[obj.uuid].z
|
||||||
|
],
|
||||||
|
rotation: [
|
||||||
|
initialRotations[obj.uuid].x,
|
||||||
|
initialRotations[obj.uuid].y,
|
||||||
|
initialRotations[obj.uuid].z
|
||||||
|
]
|
||||||
|
},
|
||||||
|
newData: {
|
||||||
|
...asset,
|
||||||
|
position: positionArray,
|
||||||
|
rotation: rotationArray
|
||||||
|
},
|
||||||
|
timeStap: new Date().toISOString()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const newFloorItem: Types.FloorItemType = {
|
const newFloorItem: Types.FloorItemType = {
|
||||||
modelUuid: obj.userData.modelUuid,
|
modelUuid: obj.userData.modelUuid,
|
||||||
modelName: obj.userData.modelName,
|
modelName: obj.userData.modelName,
|
||||||
@@ -305,6 +337,27 @@ function RotateControls3D({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (assetsToUpdate.length > 0) {
|
||||||
|
if (assetsToUpdate.length === 1) {
|
||||||
|
undoActions.push({
|
||||||
|
module: "builder",
|
||||||
|
actionType: "Asset-Update",
|
||||||
|
asset: assetsToUpdate[0]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
undoActions.push({
|
||||||
|
module: "builder",
|
||||||
|
actionType: "Assets-Update",
|
||||||
|
assets: assetsToUpdate
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
push3D({
|
||||||
|
type: 'Scene',
|
||||||
|
actions: undoActions
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
setIsRotating(false);
|
setIsRotating(false);
|
||||||
clearSelection();
|
clearSelection();
|
||||||
}, [rotatedObjects, eventStore, productStore, selectedProduct, updateBackend, projectId, updateAsset, organization, socket, selectedVersion, userId]);
|
}, [rotatedObjects, eventStore, productStore, selectedProduct, updateBackend, projectId, updateAsset, organization, socket, selectedVersion, userId]);
|
||||||
|
|||||||
@@ -31,8 +31,9 @@ const SelectionControls3D: React.FC = () => {
|
|||||||
const boundingBoxRef = useRef<THREE.Mesh>();
|
const boundingBoxRef = useRef<THREE.Mesh>();
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const { assetStore, eventStore, productStore } = useSceneContext();
|
const { assetStore, eventStore, productStore, undoRedo3DStore } = useSceneContext();
|
||||||
const { removeAsset } = assetStore();
|
const { push3D } = undoRedo3DStore();
|
||||||
|
const { removeAsset, getAssetById } = assetStore();
|
||||||
const selectionBox = useMemo(() => new SelectionBox(camera, scene), [camera, scene]);
|
const selectionBox = useMemo(() => new SelectionBox(camera, scene), [camera, scene]);
|
||||||
const { toolMode } = useToolMode();
|
const { toolMode } = useToolMode();
|
||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
@@ -266,12 +267,18 @@ const SelectionControls3D: React.FC = () => {
|
|||||||
const deleteSelection = () => {
|
const deleteSelection = () => {
|
||||||
if (selectedAssets.length > 0 && duplicatedObjects.length === 0) {
|
if (selectedAssets.length > 0 && duplicatedObjects.length === 0) {
|
||||||
|
|
||||||
|
const undoActions: UndoRedo3DAction[] = [];
|
||||||
|
const assetsToDelete: AssetData[] = [];
|
||||||
|
|
||||||
const selectedUUIDs = selectedAssets.map((mesh: THREE.Object3D) => mesh.uuid);
|
const selectedUUIDs = selectedAssets.map((mesh: THREE.Object3D) => mesh.uuid);
|
||||||
|
|
||||||
selectedAssets.forEach((selectedMesh: THREE.Object3D) => {
|
selectedAssets.forEach((selectedMesh: THREE.Object3D) => {
|
||||||
|
const asset = getAssetById(selectedMesh.userData.modelUuid);
|
||||||
|
if (!asset) return;
|
||||||
|
|
||||||
//REST
|
//REST
|
||||||
|
|
||||||
// const response = await deleteFloorItem(organization, selectedMesh.userData.modelUuid, selectedMesh.userData.modelName);
|
// const response = deleteFloorItem(organization, selectedMesh.userData.modelUuid, selectedMesh.userData.modelName);
|
||||||
|
|
||||||
//SOCKET
|
//SOCKET
|
||||||
|
|
||||||
@@ -321,6 +328,31 @@ const SelectionControls3D: React.FC = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
assetsToDelete.push({
|
||||||
|
type: "Asset",
|
||||||
|
assetData: asset,
|
||||||
|
timeStap: new Date().toISOString()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (assetsToDelete.length === 1) {
|
||||||
|
undoActions.push({
|
||||||
|
module: "builder",
|
||||||
|
actionType: "Asset-Delete",
|
||||||
|
asset: assetsToDelete[0]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
undoActions.push({
|
||||||
|
module: "builder",
|
||||||
|
actionType: "Assets-Delete",
|
||||||
|
assets: assetsToDelete
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
push3D({
|
||||||
|
type: 'Scene',
|
||||||
|
actions: undoActions
|
||||||
});
|
});
|
||||||
|
|
||||||
selectedUUIDs.forEach((uuid: string) => {
|
selectedUUIDs.forEach((uuid: string) => {
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default function TransformControl() {
|
|||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const { selectedProductStore } = useProductContext();
|
const { selectedProductStore } = useProductContext();
|
||||||
const { selectedProduct } = selectedProductStore();
|
const { selectedProduct } = selectedProductStore();
|
||||||
const { assetStore, eventStore, productStore } = useSceneContext();
|
const { assetStore, eventStore, productStore, undoRedo3DStore } = useSceneContext();
|
||||||
|
const { push3D } = undoRedo3DStore();
|
||||||
const { updateAsset, getAssetById } = assetStore();
|
const { updateAsset, getAssetById } = assetStore();
|
||||||
const { userId, organization } = getUserData();
|
const { userId, organization } = getUserData();
|
||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
@@ -137,13 +138,37 @@ export default function TransformControl() {
|
|||||||
projectId
|
projectId
|
||||||
};
|
};
|
||||||
|
|
||||||
// console.log('data: ', data);
|
|
||||||
socket.emit("v1:model-asset:add", data);
|
socket.emit("v1:model-asset:add", data);
|
||||||
|
|
||||||
|
push3D({
|
||||||
|
type: 'Scene',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
module: "builder",
|
||||||
|
actionType: "Asset-Update",
|
||||||
|
asset: {
|
||||||
|
type: "Asset",
|
||||||
|
assetData: asset,
|
||||||
|
newData: {
|
||||||
|
...asset,
|
||||||
|
position: [selectedFloorItem.position.x, 0, selectedFloorItem.position.z],
|
||||||
|
rotation: [selectedFloorItem.rotation.x, selectedFloorItem.rotation.y, selectedFloorItem.rotation.z],
|
||||||
|
},
|
||||||
|
timeStap: new Date().toISOString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleKeyDown = (e: KeyboardEvent) => {
|
const handleKeyDown = (e: KeyboardEvent) => {
|
||||||
|
const isTextInput = (element: Element | null): boolean =>
|
||||||
|
element instanceof HTMLInputElement ||
|
||||||
|
element instanceof HTMLTextAreaElement ||
|
||||||
|
element?.getAttribute("contenteditable") === "true";
|
||||||
|
if (isTextInput(document.activeElement)) return;
|
||||||
const keyCombination = detectModifierKeys(e);
|
const keyCombination = detectModifierKeys(e);
|
||||||
if (!selectedFloorItem) return;
|
if (!selectedFloorItem) return;
|
||||||
if (keyCombination === "G") {
|
if (keyCombination === "G") {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { useSocketStore } from "../../../../../store/builder/store";
|
|||||||
// import { upsertAisleApi } from "../../../../../services/factoryBuilder/aisle/upsertAisleApi";
|
// import { upsertAisleApi } from "../../../../../services/factoryBuilder/aisle/upsertAisleApi";
|
||||||
// import { deleteAisleApi } from "../../../../../services/factoryBuilder/aisle/deleteAisleApi";
|
// import { deleteAisleApi } from "../../../../../services/factoryBuilder/aisle/deleteAisleApi";
|
||||||
|
|
||||||
function useRedoHandler() {
|
function use2DRedoHandler() {
|
||||||
const { undoRedo2DStore, wallStore, floorStore, zoneStore, aisleStore } = useSceneContext();
|
const { undoRedo2DStore, wallStore, floorStore, zoneStore, aisleStore } = useSceneContext();
|
||||||
const { redo2D, peekRedo2D } = undoRedo2DStore();
|
const { redo2D, peekRedo2D } = undoRedo2DStore();
|
||||||
const { addWall, removeWall, updateWall } = wallStore();
|
const { addWall, removeWall, updateWall } = wallStore();
|
||||||
@@ -352,4 +352,4 @@ function useRedoHandler() {
|
|||||||
return { handleRedo };
|
return { handleRedo };
|
||||||
}
|
}
|
||||||
|
|
||||||
export default useRedoHandler;
|
export default use2DRedoHandler;
|
||||||
@@ -16,7 +16,7 @@ import { useSocketStore } from "../../../../../store/builder/store";
|
|||||||
// import { upsertAisleApi } from "../../../../../services/factoryBuilder/aisle/upsertAisleApi";
|
// import { upsertAisleApi } from "../../../../../services/factoryBuilder/aisle/upsertAisleApi";
|
||||||
// import { deleteAisleApi } from "../../../../../services/factoryBuilder/aisle/deleteAisleApi";
|
// import { deleteAisleApi } from "../../../../../services/factoryBuilder/aisle/deleteAisleApi";
|
||||||
|
|
||||||
function useUndoHandler() {
|
function use2DUndoHandler() {
|
||||||
const { undoRedo2DStore, wallStore, floorStore, zoneStore, aisleStore } = useSceneContext();
|
const { undoRedo2DStore, wallStore, floorStore, zoneStore, aisleStore } = useSceneContext();
|
||||||
const { undo2D, peekUndo2D } = undoRedo2DStore();
|
const { undo2D, peekUndo2D } = undoRedo2DStore();
|
||||||
const { addWall, removeWall, updateWall } = wallStore();
|
const { addWall, removeWall, updateWall } = wallStore();
|
||||||
@@ -67,38 +67,37 @@ function useUndoHandler() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
undo2D();
|
undo2D();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCreate = (point: UndoRedo2DDataTypeSchema) => {
|
const handleCreate = (point: UndoRedo2DDataTypeSchema) => {
|
||||||
switch (point.type) {
|
switch (point.type) {
|
||||||
case 'Wall': createWallFromBackend(point.lineData); break;
|
case 'Wall': createWallToBackend(point.lineData); break;
|
||||||
case 'Floor': createFloorFromBackend(point.lineData); break;
|
case 'Floor': createFloorToBackend(point.lineData); break;
|
||||||
case 'Zone': createZoneFromBackend(point.lineData); break;
|
case 'Zone': createZoneToBackend(point.lineData); break;
|
||||||
case 'Aisle': createAisleFromBackend(point.lineData); break;
|
case 'Aisle': createAisleToBackend(point.lineData); break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemove = (point: UndoRedo2DDataTypeSchema) => {
|
const handleRemove = (point: UndoRedo2DDataTypeSchema) => {
|
||||||
switch (point.type) {
|
switch (point.type) {
|
||||||
case 'Wall': removeWallFromBackend(point.lineData.wallUuid); break;
|
case 'Wall': removeWallToBackend(point.lineData.wallUuid); break;
|
||||||
case 'Floor': removeFloorFromBackend(point.lineData.floorUuid); break;
|
case 'Floor': removeFloorToBackend(point.lineData.floorUuid); break;
|
||||||
case 'Zone': removeZoneFromBackend(point.lineData.zoneUuid); break;
|
case 'Zone': removeZoneToBackend(point.lineData.zoneUuid); break;
|
||||||
case 'Aisle': removeAisleFromBackend(point.lineData.aisleUuid); break;
|
case 'Aisle': removeAisleToBackend(point.lineData.aisleUuid); break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUpdate = (point: UndoRedo2DDataTypeSchema) => {
|
const handleUpdate = (point: UndoRedo2DDataTypeSchema) => {
|
||||||
switch (point.type) {
|
switch (point.type) {
|
||||||
case 'Wall': updateWallFromBackend(point.lineData.wallUuid, point.lineData); break;
|
case 'Wall': updateWallToBackend(point.lineData.wallUuid, point.lineData); break;
|
||||||
case 'Floor': updateFloorFromBackend(point.lineData.floorUuid, point.lineData); break;
|
case 'Floor': updateFloorToBackend(point.lineData.floorUuid, point.lineData); break;
|
||||||
case 'Zone': updateZoneFromBackend(point.lineData.zoneUuid, point.lineData); break;
|
case 'Zone': updateZoneToBackend(point.lineData.zoneUuid, point.lineData); break;
|
||||||
case 'Aisle': updateAisleFromBackend(point.lineData.aisleUuid, point.lineData); break;
|
case 'Aisle': updateAisleToBackend(point.lineData.aisleUuid, point.lineData); break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const createWallFromBackend = (wallData: Wall) => {
|
const createWallToBackend = (wallData: Wall) => {
|
||||||
addWall(wallData);
|
addWall(wallData);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
// API
|
// API
|
||||||
@@ -119,7 +118,7 @@ function useUndoHandler() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeWallFromBackend = (wallUuid: string) => {
|
const removeWallToBackend = (wallUuid: string) => {
|
||||||
removeWall(wallUuid);
|
removeWall(wallUuid);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
// API
|
// API
|
||||||
@@ -140,7 +139,7 @@ function useUndoHandler() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateWallFromBackend = (wallUuid: string, updatedData: Wall) => {
|
const updateWallToBackend = (wallUuid: string, updatedData: Wall) => {
|
||||||
updateWall(wallUuid, updatedData);
|
updateWall(wallUuid, updatedData);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
// API
|
// API
|
||||||
@@ -161,7 +160,7 @@ function useUndoHandler() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const createFloorFromBackend = (floorData: Floor) => {
|
const createFloorToBackend = (floorData: Floor) => {
|
||||||
addFloor(floorData);
|
addFloor(floorData);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
// API
|
// API
|
||||||
@@ -182,7 +181,7 @@ function useUndoHandler() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeFloorFromBackend = (floorUuid: string) => {
|
const removeFloorToBackend = (floorUuid: string) => {
|
||||||
removeFloor(floorUuid);
|
removeFloor(floorUuid);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
// API
|
// API
|
||||||
@@ -203,7 +202,7 @@ function useUndoHandler() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateFloorFromBackend = (floorUuid: string, updatedData: Floor) => {
|
const updateFloorToBackend = (floorUuid: string, updatedData: Floor) => {
|
||||||
updateFloor(floorUuid, updatedData);
|
updateFloor(floorUuid, updatedData);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
// API
|
// API
|
||||||
@@ -224,7 +223,7 @@ function useUndoHandler() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const createZoneFromBackend = (zoneData: Zone) => {
|
const createZoneToBackend = (zoneData: Zone) => {
|
||||||
addZone(zoneData);
|
addZone(zoneData);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
// API
|
// API
|
||||||
@@ -245,7 +244,7 @@ function useUndoHandler() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeZoneFromBackend = (zoneUuid: string) => {
|
const removeZoneToBackend = (zoneUuid: string) => {
|
||||||
removeZone(zoneUuid);
|
removeZone(zoneUuid);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
// API
|
// API
|
||||||
@@ -266,7 +265,7 @@ function useUndoHandler() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateZoneFromBackend = (zoneUuid: string, updatedData: Zone) => {
|
const updateZoneToBackend = (zoneUuid: string, updatedData: Zone) => {
|
||||||
updateZone(zoneUuid, updatedData);
|
updateZone(zoneUuid, updatedData);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
// API
|
// API
|
||||||
@@ -287,7 +286,7 @@ function useUndoHandler() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const createAisleFromBackend = (aisleData: Aisle) => {
|
const createAisleToBackend = (aisleData: Aisle) => {
|
||||||
addAisle(aisleData);
|
addAisle(aisleData);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
// API
|
// API
|
||||||
@@ -308,7 +307,7 @@ function useUndoHandler() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeAisleFromBackend = (aisleUuid: string) => {
|
const removeAisleToBackend = (aisleUuid: string) => {
|
||||||
removeAisle(aisleUuid);
|
removeAisle(aisleUuid);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
// API
|
// API
|
||||||
@@ -329,7 +328,7 @@ function useUndoHandler() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateAisleFromBackend = (aisleUuid: string, updatedData: Aisle) => {
|
const updateAisleToBackend = (aisleUuid: string, updatedData: Aisle) => {
|
||||||
updateAisle(aisleUuid, updatedData);
|
updateAisle(aisleUuid, updatedData);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
// API
|
// API
|
||||||
@@ -353,4 +352,4 @@ function useUndoHandler() {
|
|||||||
return { handleUndo };
|
return { handleUndo };
|
||||||
}
|
}
|
||||||
|
|
||||||
export default useUndoHandler;
|
export default use2DUndoHandler;
|
||||||
@@ -0,0 +1,318 @@
|
|||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
import { getUserData } from "../../../../../functions/getUserData";
|
||||||
|
import { useVersionContext } from "../../../../builder/version/versionContext";
|
||||||
|
import { useSceneContext } from "../../../sceneContext";
|
||||||
|
import { useProductContext } from "../../../../simulation/products/productContext";
|
||||||
|
import { useSocketStore } from "../../../../../store/builder/store";
|
||||||
|
|
||||||
|
import { upsertProductOrEventApi } from "../../../../../services/simulation/products/UpsertProductOrEventApi";
|
||||||
|
|
||||||
|
// import { setAssetsApi } from "../../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi";
|
||||||
|
// import { deleteFloorItem } from "../../../../../services/factoryBuilder/asset/floorAsset/deleteFloorItemApi";
|
||||||
|
|
||||||
|
function use3DRedoHandler() {
|
||||||
|
const { undoRedo3DStore, assetStore, productStore, eventStore } = useSceneContext();
|
||||||
|
const { deleteEvent } = productStore();
|
||||||
|
const { addEvent, removeEvent } = eventStore();
|
||||||
|
const { updateAsset, removeAsset, addAsset } = assetStore();
|
||||||
|
const { redo3D, peekRedo3D } = undoRedo3DStore();
|
||||||
|
const { selectedVersionStore } = useVersionContext();
|
||||||
|
const { selectedVersion } = selectedVersionStore();
|
||||||
|
const { selectedProductStore } = useProductContext();
|
||||||
|
const { selectedProduct } = selectedProductStore();
|
||||||
|
const { userId, organization } = getUserData();
|
||||||
|
const { projectId } = useParams();
|
||||||
|
const { socket } = useSocketStore();
|
||||||
|
|
||||||
|
const updateBackend = (
|
||||||
|
productName: string,
|
||||||
|
productUuid: string,
|
||||||
|
projectId: string,
|
||||||
|
eventData: EventsSchema
|
||||||
|
) => {
|
||||||
|
upsertProductOrEventApi({
|
||||||
|
productName: productName,
|
||||||
|
productUuid: productUuid,
|
||||||
|
projectId: projectId,
|
||||||
|
eventDatas: eventData,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRedo = () => {
|
||||||
|
const redoData = peekRedo3D();
|
||||||
|
if (!redoData) return;
|
||||||
|
|
||||||
|
if (redoData.type === 'Scene') {
|
||||||
|
const { actions } = redoData;
|
||||||
|
|
||||||
|
actions.forEach(action => {
|
||||||
|
const { actionType } = action;
|
||||||
|
|
||||||
|
if ('asset' in action) {
|
||||||
|
const asset = action.asset;
|
||||||
|
|
||||||
|
if (actionType === 'Asset-Add') {
|
||||||
|
handleAdd(asset);
|
||||||
|
} else if (actionType === 'Asset-Delete') {
|
||||||
|
handleDelete(asset);
|
||||||
|
} else if (actionType === 'Asset-Update') {
|
||||||
|
handleUpdate(asset);
|
||||||
|
} else if (actionType === 'Asset-Copied') {
|
||||||
|
handleCopy(asset);
|
||||||
|
} else if (actionType === 'Asset-Duplicated') {
|
||||||
|
handleDuplicate(asset);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if ('assets' in action) {
|
||||||
|
const assets = action.assets;
|
||||||
|
|
||||||
|
if (actionType === 'Assets-Add') {
|
||||||
|
assets.forEach(handleAdd);
|
||||||
|
} else if (actionType === 'Assets-Delete') {
|
||||||
|
assets.forEach(handleDelete);
|
||||||
|
} else if (actionType === 'Assets-Update') {
|
||||||
|
assets.forEach(handleUpdate);
|
||||||
|
} else if (actionType === 'Assets-Copied') {
|
||||||
|
assets.forEach(handleCopy);
|
||||||
|
} else if (actionType === 'Assets-Duplicated') {
|
||||||
|
assets.forEach(handleDuplicate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (redoData.type === 'UI') {
|
||||||
|
// Handle UI actions if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
redo3D();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const handleAdd = (asset: AssetData) => {
|
||||||
|
switch (asset.type) {
|
||||||
|
case 'Asset': addAssetToBackend(asset.assetData); break;
|
||||||
|
case 'WallAsset': addWallAssetToBackend(asset.assetData); break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelete = (asset: AssetData) => {
|
||||||
|
switch (asset.type) {
|
||||||
|
case 'Asset': deleteAssetToBackend(asset.assetData); break;
|
||||||
|
case 'WallAsset': deleteWallAssetToBackend(asset.assetData); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleUpdate = (asset: AssetData) => {
|
||||||
|
if (!asset.newData) return;
|
||||||
|
switch (asset.type) {
|
||||||
|
case 'Asset': updateAssetToBackend(asset.newData.modelUuid, asset.newData); break;
|
||||||
|
case 'WallAsset': updateWallAssetToBackend(asset.newData.modelUuid, asset.newData); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCopy = (asset: AssetData) => {
|
||||||
|
switch (asset.type) {
|
||||||
|
case 'Asset': copyAssetToBackend(asset.assetData); break;
|
||||||
|
case 'WallAsset': copyWallAssetToBackend(asset.assetData); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDuplicate = (asset: AssetData) => {
|
||||||
|
switch (asset.type) {
|
||||||
|
case 'Asset': duplicateAssetToBackend(asset.assetData); break;
|
||||||
|
case 'WallAsset': duplicateWallAssetToBackend(asset.assetData); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const addAssetToBackend = (assetData: Asset) => {
|
||||||
|
addAsset(assetData);
|
||||||
|
if (projectId) {
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modelUuid: assetData.modelUuid,
|
||||||
|
modelName: assetData.modelName,
|
||||||
|
assetId: assetData.assetId,
|
||||||
|
position: assetData.position,
|
||||||
|
rotation: { x: assetData.rotation[0], y: assetData.rotation[1], z: assetData.rotation[2] },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
eventData: {},
|
||||||
|
socketId: socket.id,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
projectId,
|
||||||
|
userId
|
||||||
|
};
|
||||||
|
|
||||||
|
if (assetData.eventData) {
|
||||||
|
data.eventData = assetData.eventData;
|
||||||
|
addEvent(assetData.eventData as EventsSchema);
|
||||||
|
}
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// setAssetsApi(data);
|
||||||
|
|
||||||
|
//SOCKET
|
||||||
|
|
||||||
|
socket.emit("v1:model-asset:add", data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteAssetToBackend = (assetData: Asset) => {
|
||||||
|
//REST
|
||||||
|
|
||||||
|
// const response = deleteFloorItem(organization, assetData.modelUuid, assetData.modelName);
|
||||||
|
|
||||||
|
//SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modelUuid: assetData.modelUuid,
|
||||||
|
modelName: assetData.modelName,
|
||||||
|
socketId: socket.id,
|
||||||
|
userId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
projectId
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = socket.emit('v1:model-asset:delete', data)
|
||||||
|
|
||||||
|
removeEvent(assetData.modelUuid);
|
||||||
|
const updatedEvents = deleteEvent(assetData.modelUuid);
|
||||||
|
|
||||||
|
updatedEvents.forEach((event) => {
|
||||||
|
updateBackend(
|
||||||
|
selectedProduct.productName,
|
||||||
|
selectedProduct.productUuid,
|
||||||
|
projectId || '',
|
||||||
|
event
|
||||||
|
);
|
||||||
|
})
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
|
||||||
|
removeAsset(assetData.modelUuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateAssetToBackend = (modelUuid: string, updatedData: Asset) => {
|
||||||
|
updateAsset(modelUuid, updatedData);
|
||||||
|
if (projectId) {
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modelUuid: updatedData.modelUuid,
|
||||||
|
modelName: updatedData.modelName,
|
||||||
|
assetId: updatedData.assetId,
|
||||||
|
position: updatedData.position,
|
||||||
|
rotation: { x: updatedData.rotation[0], y: updatedData.rotation[1], z: updatedData.rotation[2] },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
socketId: socket.id,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
projectId,
|
||||||
|
userId
|
||||||
|
};
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// setAssetsApi(data);
|
||||||
|
|
||||||
|
//SOCKET
|
||||||
|
|
||||||
|
socket.emit("v1:model-asset:add", data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const copyAssetToBackend = (assetData: Asset) => {
|
||||||
|
addAsset(assetData);
|
||||||
|
if (projectId) {
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modelUuid: assetData.modelUuid,
|
||||||
|
modelName: assetData.modelName,
|
||||||
|
assetId: assetData.assetId,
|
||||||
|
position: assetData.position,
|
||||||
|
rotation: { x: assetData.rotation[0], y: assetData.rotation[1], z: assetData.rotation[2] },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
eventData: {},
|
||||||
|
socketId: socket.id,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
projectId,
|
||||||
|
userId
|
||||||
|
};
|
||||||
|
|
||||||
|
if (assetData.eventData) {
|
||||||
|
data.eventData = assetData.eventData;
|
||||||
|
addEvent(assetData.eventData as EventsSchema);
|
||||||
|
}
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// setAssetsApi(data);
|
||||||
|
|
||||||
|
//SOCKET
|
||||||
|
|
||||||
|
socket.emit("v1:model-asset:add", data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const duplicateAssetToBackend = (assetData: Asset) => {
|
||||||
|
addAsset(assetData);
|
||||||
|
if (projectId) {
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modelUuid: assetData.modelUuid,
|
||||||
|
modelName: assetData.modelName,
|
||||||
|
assetId: assetData.assetId,
|
||||||
|
position: assetData.position,
|
||||||
|
rotation: { x: assetData.rotation[0], y: assetData.rotation[1], z: assetData.rotation[2] },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
eventData: {},
|
||||||
|
socketId: socket.id,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
projectId,
|
||||||
|
userId
|
||||||
|
};
|
||||||
|
|
||||||
|
if (assetData.eventData) {
|
||||||
|
data.eventData = assetData.eventData;
|
||||||
|
addEvent(assetData.eventData as EventsSchema);
|
||||||
|
}
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// setAssetsApi(data);
|
||||||
|
|
||||||
|
//SOCKET
|
||||||
|
|
||||||
|
socket.emit("v1:model-asset:add", data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const addWallAssetToBackend = (assetData: WallAsset) => {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteWallAssetToBackend = (assetData: WallAsset) => {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateWallAssetToBackend = (modelUuid: string, updatedData: WallAsset) => {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const copyWallAssetToBackend = (assetData: WallAsset) => {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const duplicateWallAssetToBackend = (assetData: WallAsset) => {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return { handleRedo };
|
||||||
|
}
|
||||||
|
|
||||||
|
export default use3DRedoHandler;
|
||||||
@@ -0,0 +1,323 @@
|
|||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
import { getUserData } from "../../../../../functions/getUserData";
|
||||||
|
import { useVersionContext } from "../../../../builder/version/versionContext";
|
||||||
|
import { useSceneContext } from "../../../sceneContext";
|
||||||
|
import { useProductContext } from "../../../../simulation/products/productContext";
|
||||||
|
import { useSocketStore } from "../../../../../store/builder/store";
|
||||||
|
|
||||||
|
import { upsertProductOrEventApi } from "../../../../../services/simulation/products/UpsertProductOrEventApi";
|
||||||
|
|
||||||
|
// import { setAssetsApi } from "../../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi";
|
||||||
|
// import { deleteFloorItem } from "../../../../../services/factoryBuilder/asset/floorAsset/deleteFloorItemApi";
|
||||||
|
|
||||||
|
function use3DUndoHandler() {
|
||||||
|
const { undoRedo3DStore, assetStore, productStore, eventStore } = useSceneContext();
|
||||||
|
const { deleteEvent } = productStore();
|
||||||
|
const { addEvent, removeEvent } = eventStore();
|
||||||
|
const { updateAsset, removeAsset, addAsset } = assetStore();
|
||||||
|
const { undo3D, peekUndo3D } = undoRedo3DStore();
|
||||||
|
const { selectedVersionStore } = useVersionContext();
|
||||||
|
const { selectedVersion } = selectedVersionStore();
|
||||||
|
const { selectedProductStore } = useProductContext();
|
||||||
|
const { selectedProduct } = selectedProductStore();
|
||||||
|
const { userId, organization } = getUserData();
|
||||||
|
const { projectId } = useParams();
|
||||||
|
const { socket } = useSocketStore();
|
||||||
|
|
||||||
|
const updateBackend = (
|
||||||
|
productName: string,
|
||||||
|
productUuid: string,
|
||||||
|
projectId: string,
|
||||||
|
eventData: EventsSchema
|
||||||
|
) => {
|
||||||
|
upsertProductOrEventApi({
|
||||||
|
productName: productName,
|
||||||
|
productUuid: productUuid,
|
||||||
|
projectId: projectId,
|
||||||
|
eventDatas: eventData,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleUndo = () => {
|
||||||
|
const unDoData = peekUndo3D();
|
||||||
|
if (!unDoData) return;
|
||||||
|
|
||||||
|
if (unDoData.type === 'Scene') {
|
||||||
|
const { actions } = unDoData;
|
||||||
|
|
||||||
|
actions.forEach(action => {
|
||||||
|
const { actionType } = action;
|
||||||
|
|
||||||
|
if ('asset' in action) {
|
||||||
|
const asset = action.asset;
|
||||||
|
|
||||||
|
if (actionType === 'Asset-Add') {
|
||||||
|
handleDelete(asset);
|
||||||
|
} else if (actionType === 'Asset-Delete') {
|
||||||
|
handleAdd(asset);
|
||||||
|
} else if (actionType === 'Asset-Update') {
|
||||||
|
handleUpdate(asset);
|
||||||
|
} else if (actionType === 'Asset-Copied') {
|
||||||
|
handleCopy(asset);
|
||||||
|
} else if (actionType === 'Asset-Duplicated') {
|
||||||
|
handleDuplicate(asset);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if ('assets' in action) {
|
||||||
|
const assets = action.assets;
|
||||||
|
|
||||||
|
if (actionType === 'Assets-Add') {
|
||||||
|
assets.forEach(handleDelete);
|
||||||
|
} else if (actionType === 'Assets-Delete') {
|
||||||
|
assets.forEach(handleAdd);
|
||||||
|
} else if (actionType === 'Assets-Update') {
|
||||||
|
assets.forEach(handleUpdate);
|
||||||
|
} else if (actionType === 'Assets-Copied') {
|
||||||
|
assets.forEach(handleCopy);
|
||||||
|
} else if (actionType === 'Assets-Duplicated') {
|
||||||
|
assets.forEach(handleDuplicate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (unDoData.type === 'UI') {
|
||||||
|
// Handle UI actions if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
undo3D();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const handleAdd = (asset: AssetData) => {
|
||||||
|
switch (asset.type) {
|
||||||
|
case 'Asset': addAssetToBackend(asset.assetData); break;
|
||||||
|
case 'WallAsset': addWallAssetToBackend(asset.assetData); break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelete = (asset: AssetData) => {
|
||||||
|
switch (asset.type) {
|
||||||
|
case 'Asset': deleteAssetToBackend(asset.assetData); break;
|
||||||
|
case 'WallAsset': deleteWallAssetToBackend(asset.assetData); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleUpdate = (asset: AssetData) => {
|
||||||
|
switch (asset.type) {
|
||||||
|
case 'Asset': updateAssetToBackend(asset.assetData.modelUuid, asset.assetData); break;
|
||||||
|
case 'WallAsset': updateWallAssetToBackend(asset.assetData.modelUuid, asset.assetData); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCopy = (asset: AssetData) => {
|
||||||
|
switch (asset.type) {
|
||||||
|
case 'Asset': copyAssetToBackend(asset.assetData); break;
|
||||||
|
case 'WallAsset': copyWallAssetToBackend(asset.assetData); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDuplicate = (asset: AssetData) => {
|
||||||
|
switch (asset.type) {
|
||||||
|
case 'Asset': duplicateAssetToBackend(asset.assetData); break;
|
||||||
|
case 'WallAsset': duplicateWallAssetToBackend(asset.assetData); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const addAssetToBackend = (assetData: Asset) => {
|
||||||
|
addAsset(assetData);
|
||||||
|
if (projectId) {
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modelUuid: assetData.modelUuid,
|
||||||
|
modelName: assetData.modelName,
|
||||||
|
assetId: assetData.assetId,
|
||||||
|
position: assetData.position,
|
||||||
|
rotation: { x: assetData.rotation[0], y: assetData.rotation[1], z: assetData.rotation[2] },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
eventData: {},
|
||||||
|
socketId: socket.id,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
projectId,
|
||||||
|
userId
|
||||||
|
};
|
||||||
|
|
||||||
|
if (assetData.eventData) {
|
||||||
|
data.eventData = assetData.eventData;
|
||||||
|
addEvent(assetData.eventData as EventsSchema);
|
||||||
|
}
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// setAssetsApi(data);
|
||||||
|
|
||||||
|
//SOCKET
|
||||||
|
|
||||||
|
socket.emit("v1:model-asset:add", data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteAssetToBackend = (assetData: Asset) => {
|
||||||
|
//REST
|
||||||
|
|
||||||
|
// const response = deleteFloorItem(organization, assetData.modelUuid, assetData.modelName);
|
||||||
|
|
||||||
|
//SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modelUuid: assetData.modelUuid,
|
||||||
|
modelName: assetData.modelName,
|
||||||
|
socketId: socket.id,
|
||||||
|
userId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
projectId
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = socket.emit('v1:model-asset:delete', data)
|
||||||
|
|
||||||
|
removeEvent(assetData.modelUuid);
|
||||||
|
const updatedEvents = deleteEvent(assetData.modelUuid);
|
||||||
|
|
||||||
|
updatedEvents.forEach((event) => {
|
||||||
|
updateBackend(
|
||||||
|
selectedProduct.productName,
|
||||||
|
selectedProduct.productUuid,
|
||||||
|
projectId || '',
|
||||||
|
event
|
||||||
|
);
|
||||||
|
})
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
|
||||||
|
removeAsset(assetData.modelUuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateAssetToBackend = (modelUuid: string, updatedData: Asset) => {
|
||||||
|
updateAsset(modelUuid, updatedData);
|
||||||
|
if (projectId) {
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modelUuid: updatedData.modelUuid,
|
||||||
|
modelName: updatedData.modelName,
|
||||||
|
assetId: updatedData.assetId,
|
||||||
|
position: updatedData.position,
|
||||||
|
rotation: { x: updatedData.rotation[0], y: updatedData.rotation[1], z: updatedData.rotation[2] },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
socketId: socket.id,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
projectId,
|
||||||
|
userId
|
||||||
|
};
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// setAssetsApi(data);
|
||||||
|
|
||||||
|
//SOCKET
|
||||||
|
|
||||||
|
socket.emit("v1:model-asset:add", data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const copyAssetToBackend = (assetData: Asset) => {
|
||||||
|
//REST
|
||||||
|
|
||||||
|
// const response = deleteFloorItem(organization, assetData.modelUuid, assetData.modelName);
|
||||||
|
|
||||||
|
//SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modelUuid: assetData.modelUuid,
|
||||||
|
modelName: assetData.modelName,
|
||||||
|
socketId: socket.id,
|
||||||
|
userId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
projectId
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = socket.emit('v1:model-asset:delete', data)
|
||||||
|
|
||||||
|
removeEvent(assetData.modelUuid);
|
||||||
|
const updatedEvents = deleteEvent(assetData.modelUuid);
|
||||||
|
|
||||||
|
updatedEvents.forEach((event) => {
|
||||||
|
updateBackend(
|
||||||
|
selectedProduct.productName,
|
||||||
|
selectedProduct.productUuid,
|
||||||
|
projectId || '',
|
||||||
|
event
|
||||||
|
);
|
||||||
|
})
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
|
||||||
|
removeAsset(assetData.modelUuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const duplicateAssetToBackend = (assetData: Asset) => {
|
||||||
|
//REST
|
||||||
|
|
||||||
|
// const response = deleteFloorItem(organization, assetData.modelUuid, assetData.modelName);
|
||||||
|
|
||||||
|
//SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modelUuid: assetData.modelUuid,
|
||||||
|
modelName: assetData.modelName,
|
||||||
|
socketId: socket.id,
|
||||||
|
userId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
projectId
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = socket.emit('v1:model-asset:delete', data)
|
||||||
|
|
||||||
|
removeEvent(assetData.modelUuid);
|
||||||
|
const updatedEvents = deleteEvent(assetData.modelUuid);
|
||||||
|
|
||||||
|
updatedEvents.forEach((event) => {
|
||||||
|
updateBackend(
|
||||||
|
selectedProduct.productName,
|
||||||
|
selectedProduct.productUuid,
|
||||||
|
projectId || '',
|
||||||
|
event
|
||||||
|
);
|
||||||
|
})
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
|
||||||
|
removeAsset(assetData.modelUuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const addWallAssetToBackend = (assetData: WallAsset) => {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteWallAssetToBackend = (assetData: WallAsset) => {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateWallAssetToBackend = (modelUuid: string, updatedData: WallAsset) => {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const copyWallAssetToBackend = (assetData: WallAsset) => {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const duplicateWallAssetToBackend = (assetData: WallAsset) => {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return { handleUndo };
|
||||||
|
}
|
||||||
|
|
||||||
|
export default use3DUndoHandler;
|
||||||
@@ -4,21 +4,21 @@ import { detectModifierKeys } from '../../../../../utils/shortcutkeys/detectModi
|
|||||||
import { useSocketStore, useToggleView } from '../../../../../store/builder/store';
|
import { useSocketStore, useToggleView } from '../../../../../store/builder/store';
|
||||||
import { useVersionContext } from '../../../../builder/version/versionContext';
|
import { useVersionContext } from '../../../../builder/version/versionContext';
|
||||||
|
|
||||||
import useUndoHandler from '../handlers/useUndoHandler';
|
import use2DUndoHandler from '../handlers/use2DUndoHandler';
|
||||||
import useRedoHandler from '../handlers/useRedoHandler';
|
import use2DRedoHandler from '../handlers/use2DRedoHandler';
|
||||||
|
|
||||||
function UndoRedo2DControls() {
|
function UndoRedo2DControls() {
|
||||||
const { undoRedo2DStore } = useSceneContext();
|
const { undoRedo2DStore } = useSceneContext();
|
||||||
const { undoStack, redoStack } = undoRedo2DStore();
|
const { undoStack, redoStack } = undoRedo2DStore();
|
||||||
const { toggleView } = useToggleView();
|
const { toggleView } = useToggleView();
|
||||||
const { handleUndo } = useUndoHandler();
|
const { handleUndo } = use2DUndoHandler();
|
||||||
const { handleRedo } = useRedoHandler();
|
const { handleRedo } = use2DRedoHandler();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
const { selectedVersion } = selectedVersionStore();
|
const { selectedVersion } = selectedVersionStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log(undoStack, redoStack);
|
// console.log(undoStack, redoStack);
|
||||||
}, [undoStack, redoStack]);
|
}, [undoStack, redoStack]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import { useEffect } from 'react'
|
||||||
|
import { useSceneContext } from '../../../sceneContext'
|
||||||
|
import { detectModifierKeys } from '../../../../../utils/shortcutkeys/detectModifierKeys';
|
||||||
|
import { useSocketStore, useToggleView } from '../../../../../store/builder/store';
|
||||||
|
import { useVersionContext } from '../../../../builder/version/versionContext';
|
||||||
|
import useModuleStore from '../../../../../store/useModuleStore';
|
||||||
|
|
||||||
|
import use3DUndoHandler from '../handlers/use3DUndoHandler';
|
||||||
|
import use3DRedoHandler from '../handlers/use3DRedoHandler';
|
||||||
|
|
||||||
|
function UndoRedo3DControls() {
|
||||||
|
const { undoRedo3DStore } = useSceneContext();
|
||||||
|
const { undoStack, redoStack } = undoRedo3DStore();
|
||||||
|
const { toggleView } = useToggleView();
|
||||||
|
const { activeModule } = useModuleStore();
|
||||||
|
const { handleUndo } = use3DUndoHandler();
|
||||||
|
const { handleRedo } = use3DRedoHandler();
|
||||||
|
const { socket } = useSocketStore();
|
||||||
|
const { selectedVersionStore } = useVersionContext();
|
||||||
|
const { selectedVersion } = selectedVersionStore();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log(undoStack, redoStack);
|
||||||
|
}, [undoStack, redoStack]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleKeyDown = (event: KeyboardEvent) => {
|
||||||
|
const keyCombination = detectModifierKeys(event);
|
||||||
|
|
||||||
|
if (keyCombination === 'Ctrl+Z') {
|
||||||
|
handleUndo();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyCombination === 'Ctrl+Y') {
|
||||||
|
handleRedo();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!toggleView) {
|
||||||
|
window.addEventListener('keydown', handleKeyDown);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('keydown', handleKeyDown);
|
||||||
|
};
|
||||||
|
}, [toggleView, undoStack, redoStack, socket, selectedVersion, activeModule]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UndoRedo3DControls;
|
||||||
@@ -8,6 +8,7 @@ import { createZoneStore, ZoneStoreType } from '../../store/builder/useZoneStore
|
|||||||
import { createFloorStore, FloorStoreType } from '../../store/builder/useFloorStore';
|
import { createFloorStore, FloorStoreType } from '../../store/builder/useFloorStore';
|
||||||
|
|
||||||
import { createUndoRedo2DStore, UndoRedo2DStoreType } from '../../store/builder/useUndoRedo2DStore';
|
import { createUndoRedo2DStore, UndoRedo2DStoreType } from '../../store/builder/useUndoRedo2DStore';
|
||||||
|
import { createUndoRedo3DStore, UndoRedo3DStoreType } from '../../store/builder/useUndoRedo3DStore';
|
||||||
|
|
||||||
import { createEventStore, EventStoreType } from '../../store/simulation/useEventsStore';
|
import { createEventStore, EventStoreType } from '../../store/simulation/useEventsStore';
|
||||||
import { createProductStore, ProductStoreType } from '../../store/simulation/useProductStore';
|
import { createProductStore, ProductStoreType } from '../../store/simulation/useProductStore';
|
||||||
@@ -31,6 +32,7 @@ type SceneContextValue = {
|
|||||||
floorStore: FloorStoreType,
|
floorStore: FloorStoreType,
|
||||||
|
|
||||||
undoRedo2DStore: UndoRedo2DStoreType,
|
undoRedo2DStore: UndoRedo2DStoreType,
|
||||||
|
undoRedo3DStore: UndoRedo3DStoreType,
|
||||||
|
|
||||||
eventStore: EventStoreType,
|
eventStore: EventStoreType,
|
||||||
productStore: ProductStoreType,
|
productStore: ProductStoreType,
|
||||||
@@ -70,6 +72,7 @@ export function SceneProvider({
|
|||||||
const floorStore = useMemo(() => createFloorStore(), []);
|
const floorStore = useMemo(() => createFloorStore(), []);
|
||||||
|
|
||||||
const undoRedo2DStore = useMemo(() => createUndoRedo2DStore(), []);
|
const undoRedo2DStore = useMemo(() => createUndoRedo2DStore(), []);
|
||||||
|
const undoRedo3DStore = useMemo(() => createUndoRedo3DStore(), []);
|
||||||
|
|
||||||
const eventStore = useMemo(() => createEventStore(), []);
|
const eventStore = useMemo(() => createEventStore(), []);
|
||||||
const productStore = useMemo(() => createProductStore(), []);
|
const productStore = useMemo(() => createProductStore(), []);
|
||||||
@@ -94,6 +97,7 @@ export function SceneProvider({
|
|||||||
zoneStore.getState().clearZones();
|
zoneStore.getState().clearZones();
|
||||||
floorStore.getState().clearFloors();
|
floorStore.getState().clearFloors();
|
||||||
undoRedo2DStore.getState().clearUndoRedo2D();
|
undoRedo2DStore.getState().clearUndoRedo2D();
|
||||||
|
undoRedo3DStore.getState().clearUndoRedo3D();
|
||||||
eventStore.getState().clearEvents();
|
eventStore.getState().clearEvents();
|
||||||
productStore.getState().clearProducts();
|
productStore.getState().clearProducts();
|
||||||
materialStore.getState().clearMaterials();
|
materialStore.getState().clearMaterials();
|
||||||
@@ -106,7 +110,7 @@ export function SceneProvider({
|
|||||||
craneStore.getState().clearCranes();
|
craneStore.getState().clearCranes();
|
||||||
humanEventManagerRef.current.humanStates = [];
|
humanEventManagerRef.current.humanStates = [];
|
||||||
craneEventManagerRef.current.craneStates = [];
|
craneEventManagerRef.current.craneStates = [];
|
||||||
}, [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, undoRedo2DStore, floorStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, craneStore]);
|
}, [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, undoRedo2DStore, undoRedo3DStore, floorStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, craneStore]);
|
||||||
|
|
||||||
const contextValue = useMemo(() => (
|
const contextValue = useMemo(() => (
|
||||||
{
|
{
|
||||||
@@ -117,6 +121,7 @@ export function SceneProvider({
|
|||||||
zoneStore,
|
zoneStore,
|
||||||
floorStore,
|
floorStore,
|
||||||
undoRedo2DStore,
|
undoRedo2DStore,
|
||||||
|
undoRedo3DStore,
|
||||||
eventStore,
|
eventStore,
|
||||||
productStore,
|
productStore,
|
||||||
materialStore,
|
materialStore,
|
||||||
@@ -132,7 +137,7 @@ export function SceneProvider({
|
|||||||
clearStores,
|
clearStores,
|
||||||
layout
|
layout
|
||||||
}
|
}
|
||||||
), [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, floorStore, undoRedo2DStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, craneStore, clearStores, layout]);
|
), [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, floorStore, undoRedo2DStore, undoRedo3DStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, craneStore, clearStores, layout]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SceneContext.Provider value={contextValue}>
|
<SceneContext.Provider value={contextValue}>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ function IKInstance({ setIkSolver, armBot }: IKInstanceProps) {
|
|||||||
const trySetup = () => {
|
const trySetup = () => {
|
||||||
const targetMesh = scene?.getObjectByProperty("uuid", armBot.modelUuid);
|
const targetMesh = scene?.getObjectByProperty("uuid", armBot.modelUuid);
|
||||||
|
|
||||||
if (!targetMesh || !targetMesh.userData.iks || targetMesh.userData.iks.length < 1) {
|
if (!targetMesh || !targetMesh.userData.fieldData || targetMesh.userData.fieldData.length < 1) {
|
||||||
retryId = setTimeout(trySetup, 100);
|
retryId = setTimeout(trySetup, 100);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -34,8 +34,8 @@ function IKInstance({ setIkSolver, armBot }: IKInstanceProps) {
|
|||||||
});
|
});
|
||||||
if (!OOI.Target_Bone || !OOI.Skinned_Mesh) return;
|
if (!OOI.Target_Bone || !OOI.Skinned_Mesh) return;
|
||||||
|
|
||||||
const rawIks: IK[] = targetMesh.userData.iks;
|
const rawIks: IK[] = targetMesh.userData.fieldData;
|
||||||
const iks = rawIks.map((ik) => ({
|
const fieldData = rawIks.map((ik) => ({
|
||||||
target: ik.target,
|
target: ik.target,
|
||||||
effector: ik.effector,
|
effector: ik.effector,
|
||||||
links: ik.links.map((link) => ({
|
links: ik.links.map((link) => ({
|
||||||
@@ -51,10 +51,10 @@ function IKInstance({ setIkSolver, armBot }: IKInstanceProps) {
|
|||||||
minheight: ik.minheight,
|
minheight: ik.minheight,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const solver = new CCDIKSolver(OOI.Skinned_Mesh, iks);
|
const solver = new CCDIKSolver(OOI.Skinned_Mesh, fieldData);
|
||||||
setIkSolver(solver);
|
setIkSolver(solver);
|
||||||
|
|
||||||
// const helper = new CCDIKHelper(OOI.Skinned_Mesh, iks, 0.05)
|
// const helper = new CCDIKHelper(OOI.Skinned_Mesh, fieldData, 0.05)
|
||||||
// scene.add(helper);
|
// scene.add(helper);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -173,8 +173,8 @@ const ArmBotUI = () => {
|
|||||||
|
|
||||||
const targetMesh = scene?.getObjectByProperty("uuid", selectedArmBotData?.modelUuid || '');
|
const targetMesh = scene?.getObjectByProperty("uuid", selectedArmBotData?.modelUuid || '');
|
||||||
|
|
||||||
const iks = targetMesh?.userData?.iks;
|
const fieldData = targetMesh?.userData?.fieldData;
|
||||||
const firstIK = Array.isArray(iks) && iks.length > 0 ? iks[0] : {};
|
const firstIK = Array.isArray(fieldData) && fieldData.length > 0 ? fieldData[0] : {};
|
||||||
|
|
||||||
const { handlePointerDown } = useDraggableGLTF(
|
const { handlePointerDown } = useDraggableGLTF(
|
||||||
updatePointToState,
|
updatePointToState,
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||||
|
|
||||||
export const getAssetIksApi = async (assetId: string) => {
|
export const getAssetFieldApi = async (assetId: string) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`${url_Backend_dwinzo}/api/v2/getAssetIks/${assetId}`,
|
`${url_Backend_dwinzo}/api/v2/getAssetField/${assetId}`,
|
||||||
{
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
@@ -20,13 +20,13 @@ export const getAssetIksApi = async (assetId: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
console.error("Failed to fetch assetIks");
|
console.error("Failed to fetch asset field");
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
return result;
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
echo.error("Failed to get assetIks");
|
echo.error("Failed to get asset field");
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
console.log(error.message);
|
console.log(error.message);
|
||||||
} else {
|
} else {
|
||||||
78
app/src/store/builder/useUndoRedo3DStore.ts
Normal file
78
app/src/store/builder/useUndoRedo3DStore.ts
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import { create } from 'zustand';
|
||||||
|
import { immer } from 'zustand/middleware/immer';
|
||||||
|
import { undoRedoConfig } from '../../types/world/worldConstants';
|
||||||
|
|
||||||
|
type UndoRedo3DStore = {
|
||||||
|
undoStack: UndoRedo3DTypes[];
|
||||||
|
redoStack: UndoRedo3DTypes[];
|
||||||
|
|
||||||
|
push3D: (entry: UndoRedo3DTypes) => void;
|
||||||
|
undo3D: () => UndoRedo3DTypes | undefined;
|
||||||
|
redo3D: () => UndoRedo3DTypes | undefined;
|
||||||
|
clearUndoRedo3D: () => void;
|
||||||
|
|
||||||
|
peekUndo3D: () => UndoRedo3DTypes | undefined;
|
||||||
|
peekRedo3D: () => UndoRedo3DTypes | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createUndoRedo3DStore = () => {
|
||||||
|
return create<UndoRedo3DStore>()(
|
||||||
|
immer((set, get) => ({
|
||||||
|
undoStack: [],
|
||||||
|
redoStack: [],
|
||||||
|
|
||||||
|
push3D: (entry) => {
|
||||||
|
set((state) => {
|
||||||
|
state.undoStack.push(entry);
|
||||||
|
|
||||||
|
if (state.undoStack.length > undoRedoConfig.undoRedoCount) {
|
||||||
|
state.undoStack.shift();
|
||||||
|
}
|
||||||
|
|
||||||
|
state.redoStack = [];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
undo3D: () => {
|
||||||
|
let lastAction: UndoRedo3DTypes | undefined;
|
||||||
|
set((state) => {
|
||||||
|
lastAction = state.undoStack.pop();
|
||||||
|
if (lastAction) {
|
||||||
|
state.redoStack.unshift(lastAction);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return lastAction;
|
||||||
|
},
|
||||||
|
|
||||||
|
redo3D: () => {
|
||||||
|
let redoAction: UndoRedo3DTypes | undefined;
|
||||||
|
set((state) => {
|
||||||
|
redoAction = state.redoStack.shift();
|
||||||
|
if (redoAction) {
|
||||||
|
state.undoStack.push(redoAction);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return redoAction;
|
||||||
|
},
|
||||||
|
|
||||||
|
clearUndoRedo3D: () => {
|
||||||
|
set((state) => {
|
||||||
|
state.undoStack = [];
|
||||||
|
state.redoStack = [];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
peekUndo3D: () => {
|
||||||
|
const stack = get().undoStack;
|
||||||
|
return stack.length > 0 ? stack[stack.length - 1] : undefined;
|
||||||
|
},
|
||||||
|
|
||||||
|
peekRedo3D: () => {
|
||||||
|
const stack = get().redoStack;
|
||||||
|
return stack.length > 0 ? stack[0] : undefined;
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UndoRedo3DStoreType = ReturnType<typeof createUndoRedo3DStore>;
|
||||||
65
app/src/types/builderTypes.d.ts
vendored
65
app/src/types/builderTypes.d.ts
vendored
@@ -253,4 +253,69 @@ type UndoRedo2DTypes = UndoRedo2DDraw | UndoRedo2DUi
|
|||||||
type UndoRedo2D = {
|
type UndoRedo2D = {
|
||||||
undoStack: UndoRedo2DTypes[];
|
undoStack: UndoRedo2DTypes[];
|
||||||
redoStack: UndoRedo2DTypes[];
|
redoStack: UndoRedo2DTypes[];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Undo/Redo 3D
|
||||||
|
|
||||||
|
type AssetType = {
|
||||||
|
type: "Asset";
|
||||||
|
assetData: Asset;
|
||||||
|
newData?: Asset;
|
||||||
|
eventMetaData?: EventsSchema;
|
||||||
|
timeStap: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type WallAssetType = {
|
||||||
|
type: "WallAsset";
|
||||||
|
assetData: WallAsset;
|
||||||
|
newData?: WallAsset;
|
||||||
|
timeStap: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type AssetData = AssetType | WallAssetType;
|
||||||
|
|
||||||
|
type UndoRedo3DActionBuilderSchema = {
|
||||||
|
module: "builder";
|
||||||
|
actionType: "Asset-Add" | "Asset-Delete" | "Asset-Update" | "Asset-Duplicated" | "Asset-Copied" | "Wall-Asset-Add" | "Wall-Asset-Delete" | "Wall-Asset-Update";
|
||||||
|
asset: AssetData;
|
||||||
|
}
|
||||||
|
|
||||||
|
type UndoRedo3DActionSimulationSchema = {
|
||||||
|
module: "simulation";
|
||||||
|
actionType: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
type UndoRedo3DActionSchema = UndoRedo3DActionBuilderSchema | UndoRedo3DActionSimulationSchema;
|
||||||
|
|
||||||
|
type UndoRedo3DActionsBuilderSchema = {
|
||||||
|
module: "builder";
|
||||||
|
actionType: "Assets-Add" | "Assets-Delete" | "Assets-Update" | "Assets-Duplicated" | "Assets-Copied" | "Wall-Assets-Add" | "Wall-Assets-Delete" | "Wall-Assets-Update";
|
||||||
|
assets: AssetData[];
|
||||||
|
}
|
||||||
|
|
||||||
|
type UndoRedo3DActionsSimulationSchema = {
|
||||||
|
module: "simulation";
|
||||||
|
actionType: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
type UndoRedo3DActionsSchema = UndoRedo3DActionsBuilderSchema | UndoRedo3DActionsSimulationSchema;
|
||||||
|
|
||||||
|
type UndoRedo3DAction = UndoRedo3DActionSchema | UndoRedo3DActionsSchema;
|
||||||
|
|
||||||
|
type UndoRedo3DDraw = {
|
||||||
|
type: 'Scene';
|
||||||
|
actions: UndoRedo3DAction[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type UndoRedo3DUi = {
|
||||||
|
type: 'UI';
|
||||||
|
action: any; // Define UI actions as needed
|
||||||
|
}
|
||||||
|
|
||||||
|
type UndoRedo3DTypes = UndoRedo3DDraw | UndoRedo3DUi;
|
||||||
|
|
||||||
|
type UndoRedo3D = {
|
||||||
|
undoStack: UndoRedo3DTypes[];
|
||||||
|
redoStack: UndoRedo3DTypes[];
|
||||||
};
|
};
|
||||||
@@ -189,12 +189,9 @@ const KeyPressListener: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleKeyPress = (event: KeyboardEvent) => {
|
const handleKeyPress = (event: KeyboardEvent) => {
|
||||||
if (isTextInput(document.activeElement)) return;
|
|
||||||
|
|
||||||
const keyCombination = detectModifierKeys(event);
|
const keyCombination = detectModifierKeys(event);
|
||||||
|
|
||||||
if (isTextInput(document.activeElement) && keyCombination !== "ESCAPE")
|
if (isTextInput(document.activeElement) && keyCombination !== "ESCAPE") return;
|
||||||
return;
|
|
||||||
|
|
||||||
if (keyCombination === "ESCAPE") {
|
if (keyCombination === "ESCAPE") {
|
||||||
setWalkMode(false);
|
setWalkMode(false);
|
||||||
|
|||||||
Reference in New Issue
Block a user