feat: Refactor DashboardEditor and simulation store with peek methods for optimized block and element updates
This commit is contained in:
@@ -33,26 +33,30 @@ const DashboardEditor: React.FC = () => {
|
|||||||
setSelectedElement,
|
setSelectedElement,
|
||||||
addBlock,
|
addBlock,
|
||||||
setBlocks,
|
setBlocks,
|
||||||
updateBlockPosition,
|
|
||||||
updateElementPosition,
|
|
||||||
updateBlockSize,
|
|
||||||
updateElementSize,
|
|
||||||
updateBlockStyle,
|
|
||||||
updateBlockPositionType,
|
|
||||||
updateBlockZIndex,
|
|
||||||
addElement,
|
|
||||||
updateElementStyle,
|
|
||||||
updateElementPositionType,
|
|
||||||
updateElementZIndex,
|
|
||||||
updateElementData,
|
|
||||||
updateGraphData,
|
|
||||||
updateGraphTitle,
|
|
||||||
updateGraphType,
|
|
||||||
swapElements,
|
|
||||||
removeBlock,
|
removeBlock,
|
||||||
removeElement,
|
removeElement,
|
||||||
getBlockById,
|
getBlockById,
|
||||||
subscribe,
|
updateBlock,
|
||||||
|
// Peek methods
|
||||||
|
peekAddBlock,
|
||||||
|
peekRemoveBlock,
|
||||||
|
peekAddElement,
|
||||||
|
peekRemoveElement,
|
||||||
|
peekUpdateBlockStyle,
|
||||||
|
peekUpdateBlockSize,
|
||||||
|
peekUpdateBlockPosition,
|
||||||
|
peekUpdateBlockPositionType,
|
||||||
|
peekUpdateBlockZIndex,
|
||||||
|
peekUpdateElementStyle,
|
||||||
|
peekUpdateElementSize,
|
||||||
|
peekUpdateElementPosition,
|
||||||
|
peekUpdateElementPositionType,
|
||||||
|
peekUpdateElementZIndex,
|
||||||
|
peekUpdateElementData,
|
||||||
|
peekUpdateGraphData,
|
||||||
|
peekUpdateGraphTitle,
|
||||||
|
peekUpdateGraphType,
|
||||||
|
peekSwapElements,
|
||||||
} = simulationDashBoardStore();
|
} = simulationDashBoardStore();
|
||||||
|
|
||||||
const [editMode, setEditMode] = useState(false);
|
const [editMode, setEditMode] = useState(false);
|
||||||
@@ -83,9 +87,49 @@ const DashboardEditor: React.FC = () => {
|
|||||||
const currentBlock = blocks.find((b) => b.blockUuid === selectedBlock);
|
const currentBlock = blocks.find((b) => b.blockUuid === selectedBlock);
|
||||||
const currentElement = currentBlock?.elements.find((el) => el.elementUuid === selectedElement);
|
const currentElement = currentBlock?.elements.find((el) => el.elementUuid === selectedElement);
|
||||||
|
|
||||||
useEffect(() => {
|
// Helper function to send updates to backend - only sends the specific block that changed
|
||||||
// console.log("blocks: ", blocks);
|
const updateBackend = async (updatedBlock: Block) => {
|
||||||
}, [blocks]);
|
if (!projectId || !selectedVersion) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await upsetDashBoardBlocksApi({
|
||||||
|
projectId,
|
||||||
|
versionId: selectedVersion.versionId,
|
||||||
|
blocks: [updatedBlock], // Send only the updated block
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.data?.blocks) {
|
||||||
|
// Update only the blocks that have success messages
|
||||||
|
response.data.blocks.forEach((responseBlock: any) => {
|
||||||
|
if (responseBlock.message === "Block updated successfully") {
|
||||||
|
// Update the specific block in the store
|
||||||
|
const { message, elements, ...blockData } = responseBlock;
|
||||||
|
|
||||||
|
// Process elements to remove their messages
|
||||||
|
const cleanedElements =
|
||||||
|
elements?.map((el: any) => {
|
||||||
|
const { message: elementMessage, ...elementData } = el;
|
||||||
|
return elementData;
|
||||||
|
}) || [];
|
||||||
|
|
||||||
|
updateBlock(responseBlock.blockUuid, {
|
||||||
|
...blockData,
|
||||||
|
elements: cleanedElements,
|
||||||
|
});
|
||||||
|
} else if (responseBlock.message === "Block created successfully") {
|
||||||
|
addBlock(responseBlock);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to update backend:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper function to get a specific block from peeked blocks
|
||||||
|
const getBlockFromPeekedBlocks = (peekedBlocks: Block[], blockId: string): Block | undefined => {
|
||||||
|
return peekedBlocks.find((b) => b.blockUuid === blockId);
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!projectId || !selectedVersion) return;
|
if (!projectId || !selectedVersion) return;
|
||||||
@@ -96,31 +140,15 @@ const DashboardEditor: React.FC = () => {
|
|||||||
});
|
});
|
||||||
}, [projectId, selectedVersion]);
|
}, [projectId, selectedVersion]);
|
||||||
|
|
||||||
const updateBackend = (blocks: Block[]) => {
|
|
||||||
if (!projectId || !selectedVersion) return;
|
|
||||||
|
|
||||||
upsetDashBoardBlocksApi({ projectId, versionId: selectedVersion.versionId, blocks }).then((data) => {
|
|
||||||
if (data.data?.blocks) {
|
|
||||||
setBlocks(data.data.blocks);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const unsubscribe = subscribe(() => {
|
|
||||||
if (!projectId || !selectedVersion) return;
|
|
||||||
updateBackend(blocks);
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
unsubscribe();
|
|
||||||
};
|
|
||||||
}, [blocks, projectId, selectedVersion]);
|
|
||||||
|
|
||||||
useCallBackOnKey(
|
useCallBackOnKey(
|
||||||
() => {
|
() => {
|
||||||
if (!projectId || !selectedVersion) return;
|
if (!projectId || !selectedVersion) return;
|
||||||
updateBackend(blocks);
|
// For Ctrl+S, send all blocks
|
||||||
|
upsetDashBoardBlocksApi({
|
||||||
|
projectId,
|
||||||
|
versionId: selectedVersion.versionId,
|
||||||
|
blocks: blocks,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
"Ctrl+S",
|
"Ctrl+S",
|
||||||
{ dependencies: [blocks, projectId, selectedVersion], noRepeat: true, allowOnInput: true }
|
{ dependencies: [blocks, projectId, selectedVersion], noRepeat: true, allowOnInput: true }
|
||||||
@@ -269,8 +297,8 @@ const DashboardEditor: React.FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseUp = (): void => {
|
const handleMouseUp = async (): Promise<void> => {
|
||||||
// Update state only on mouse up for elements
|
// Update backend using peek methods, then update state from response
|
||||||
if (draggingElement && selectedBlock && currentElement?.positionType === "absolute") {
|
if (draggingElement && selectedBlock && currentElement?.positionType === "absolute") {
|
||||||
const blockElement = document.querySelector(`[data-block-id="${selectedBlock}"]`) as HTMLElement;
|
const blockElement = document.querySelector(`[data-block-id="${selectedBlock}"]`) as HTMLElement;
|
||||||
const elementToDrag = document.querySelector(`[data-element-id="${draggingElement}"]`) as HTMLElement;
|
const elementToDrag = document.querySelector(`[data-element-id="${draggingElement}"]`) as HTMLElement;
|
||||||
@@ -280,11 +308,16 @@ const DashboardEditor: React.FC = () => {
|
|||||||
const x = parseFloat(computedStyle.left);
|
const x = parseFloat(computedStyle.left);
|
||||||
const y = parseFloat(computedStyle.top);
|
const y = parseFloat(computedStyle.top);
|
||||||
|
|
||||||
updateElementPosition(selectedBlock, draggingElement, { x, y });
|
// Use peek to get updated blocks and send only the affected block to backend
|
||||||
|
const updatedBlocks = peekUpdateElementPosition(selectedBlock, draggingElement, { x, y });
|
||||||
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, selectedBlock);
|
||||||
|
if (updatedBlock) {
|
||||||
|
await updateBackend(updatedBlock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update state only on mouse up for blocks
|
// Update backend for block drag
|
||||||
if (draggingBlock && currentBlock?.positionType && (currentBlock.positionType === "absolute" || currentBlock.positionType === "fixed")) {
|
if (draggingBlock && currentBlock?.positionType && (currentBlock.positionType === "absolute" || currentBlock.positionType === "fixed")) {
|
||||||
const blockToDrag = document.querySelector(`[data-block-id="${draggingBlock}"]`) as HTMLElement;
|
const blockToDrag = document.querySelector(`[data-block-id="${draggingBlock}"]`) as HTMLElement;
|
||||||
|
|
||||||
@@ -293,11 +326,16 @@ const DashboardEditor: React.FC = () => {
|
|||||||
const x = parseFloat(computedStyle.left);
|
const x = parseFloat(computedStyle.left);
|
||||||
const y = parseFloat(computedStyle.top);
|
const y = parseFloat(computedStyle.top);
|
||||||
|
|
||||||
updateBlockPosition(draggingBlock, { x, y });
|
// Use peek to get updated blocks and send only the affected block to backend
|
||||||
|
const updatedBlocks = peekUpdateBlockPosition(draggingBlock, { x, y });
|
||||||
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, draggingBlock);
|
||||||
|
if (updatedBlock) {
|
||||||
|
await updateBackend(updatedBlock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update state only on mouse up for resizing
|
// Update backend for element resize
|
||||||
if (resizingElement && selectedBlock) {
|
if (resizingElement && selectedBlock) {
|
||||||
const elementToResize = document.querySelector(`[data-element-id="${resizingElement}"]`) as HTMLElement;
|
const elementToResize = document.querySelector(`[data-element-id="${resizingElement}"]`) as HTMLElement;
|
||||||
if (elementToResize) {
|
if (elementToResize) {
|
||||||
@@ -305,10 +343,16 @@ const DashboardEditor: React.FC = () => {
|
|||||||
const width = parseFloat(computedStyle.width);
|
const width = parseFloat(computedStyle.width);
|
||||||
const height = parseFloat(computedStyle.height);
|
const height = parseFloat(computedStyle.height);
|
||||||
|
|
||||||
updateElementSize(selectedBlock, resizingElement, { width, height });
|
// Use peek to get updated blocks and send only the affected block to backend
|
||||||
|
const updatedBlocks = peekUpdateElementSize(selectedBlock, resizingElement, { width, height });
|
||||||
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, selectedBlock);
|
||||||
|
if (updatedBlock) {
|
||||||
|
await updateBackend(updatedBlock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update backend for block resize
|
||||||
if (resizingBlock) {
|
if (resizingBlock) {
|
||||||
const blockToResize = document.querySelector(`[data-block-id="${resizingBlock}"]`) as HTMLElement;
|
const blockToResize = document.querySelector(`[data-block-id="${resizingBlock}"]`) as HTMLElement;
|
||||||
if (blockToResize) {
|
if (blockToResize) {
|
||||||
@@ -316,7 +360,12 @@ const DashboardEditor: React.FC = () => {
|
|||||||
const width = parseFloat(computedStyle.width);
|
const width = parseFloat(computedStyle.width);
|
||||||
const height = parseFloat(computedStyle.height);
|
const height = parseFloat(computedStyle.height);
|
||||||
|
|
||||||
updateBlockSize(resizingBlock, { width, height });
|
// Use peek to get updated blocks and send only the affected block to backend
|
||||||
|
const updatedBlocks = peekUpdateBlockSize(resizingBlock, { width, height });
|
||||||
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, resizingBlock);
|
||||||
|
if (updatedBlock) {
|
||||||
|
await updateBackend(updatedBlock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,7 +391,19 @@ const DashboardEditor: React.FC = () => {
|
|||||||
return (
|
return (
|
||||||
<div ref={editorRef} className="dashboard-editor">
|
<div ref={editorRef} className="dashboard-editor">
|
||||||
{activeModule === "visualization" && (
|
{activeModule === "visualization" && (
|
||||||
<ControlPanel editMode={editMode} setEditMode={setEditMode} addBlock={() => addBlock()} showDataModelPanel={showDataModelPanel} setShowDataModelPanel={setShowDataModelPanel} />
|
<ControlPanel
|
||||||
|
editMode={editMode}
|
||||||
|
setEditMode={setEditMode}
|
||||||
|
addBlock={async () => {
|
||||||
|
const updatedBlocks = peekAddBlock();
|
||||||
|
const newBlock = updatedBlocks[updatedBlocks.length - 1]; // Get the newly added block
|
||||||
|
if (newBlock) {
|
||||||
|
await updateBackend(newBlock);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
showDataModelPanel={showDataModelPanel}
|
||||||
|
setShowDataModelPanel={setShowDataModelPanel}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* BlockGrid */}
|
{/* BlockGrid */}
|
||||||
@@ -350,8 +411,12 @@ const DashboardEditor: React.FC = () => {
|
|||||||
<div className="block-grid-container">
|
<div className="block-grid-container">
|
||||||
<BlockGrid
|
<BlockGrid
|
||||||
blocks={blocks}
|
blocks={blocks}
|
||||||
handleAddElement={(blockId, type, graphType) => {
|
handleAddElement={async (blockId, type, graphType) => {
|
||||||
addElement(blockId, type, graphType);
|
const updatedBlocks = peekAddElement(blockId, type, graphType);
|
||||||
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
||||||
|
if (updatedBlock) {
|
||||||
|
await updateBackend(updatedBlock);
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
editMode={editMode}
|
editMode={editMode}
|
||||||
selectedBlock={selectedBlock}
|
selectedBlock={selectedBlock}
|
||||||
@@ -367,7 +432,16 @@ const DashboardEditor: React.FC = () => {
|
|||||||
handleElementResizeStart={(elementId, event) => handleElementResizeStart(elementId, event, setResizingElement, setResizeStart)}
|
handleElementResizeStart={(elementId, event) => handleElementResizeStart(elementId, event, setResizingElement, setResizeStart)}
|
||||||
handleBlockResizeStart={(blockId, event) => handleBlockResizeStart(blockId, event, setResizingBlock, setResizeStart)}
|
handleBlockResizeStart={(blockId, event) => handleBlockResizeStart(blockId, event, setResizingBlock, setResizeStart)}
|
||||||
handleSwapStart={(elementId, event) => handleSwapStart(elementId, event, setSwapSource, setShowSwapUI)}
|
handleSwapStart={(elementId, event) => handleSwapStart(elementId, event, setSwapSource, setShowSwapUI)}
|
||||||
handleSwapTarget={(elementId, event) => handleSwapTarget(elementId, event, swapSource, selectedBlock, swapElements)}
|
handleSwapTarget={async (elementId, event) => {
|
||||||
|
if (!selectedBlock) return;
|
||||||
|
handleSwapTarget(elementId, event, swapSource, selectedBlock, async (blockId, el1, el2) => {
|
||||||
|
const updatedBlocks = peekSwapElements(blockId, el1, el2);
|
||||||
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
||||||
|
if (updatedBlock) {
|
||||||
|
await updateBackend(updatedBlock);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
handleBlockDragStart={(blockId, event) => handleBlockDragStart(blockId, event, setDraggingBlock, setBlockDragOffset)}
|
handleBlockDragStart={(blockId, event) => handleBlockDragStart(blockId, event, setDraggingBlock, setBlockDragOffset)}
|
||||||
setShowElementDropdown={setShowElementDropdown}
|
setShowElementDropdown={setShowElementDropdown}
|
||||||
showElementDropdown={showElementDropdown}
|
showElementDropdown={showElementDropdown}
|
||||||
@@ -381,15 +455,52 @@ const DashboardEditor: React.FC = () => {
|
|||||||
blockEditorRef={blockEditorRef}
|
blockEditorRef={blockEditorRef}
|
||||||
currentBlock={currentBlock}
|
currentBlock={currentBlock}
|
||||||
selectedBlock={selectedBlock}
|
selectedBlock={selectedBlock}
|
||||||
updateBlockStyle={(blockId, style) => updateBlockStyle(blockId, style)}
|
updateBlockStyle={async (blockId, style) => {
|
||||||
updateBlockSize={(blockId, size) => updateBlockSize(blockId, size)}
|
const updatedBlocks = peekUpdateBlockStyle(blockId, style);
|
||||||
updateBlockPosition={(blockId, position) => updateBlockPosition(blockId, position)}
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
||||||
updateBlockPositionType={(blockId, positionType) => updateBlockPositionType(blockId, positionType)}
|
if (updatedBlock) {
|
||||||
updateBlockZIndex={(blockId, zIndex) => updateBlockZIndex(blockId, zIndex)}
|
await updateBackend(updatedBlock);
|
||||||
handleRemoveBlock={(blockId) => {
|
}
|
||||||
|
}}
|
||||||
|
updateBlockSize={async (blockId, size) => {
|
||||||
|
const updatedBlocks = peekUpdateBlockSize(blockId, size);
|
||||||
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
||||||
|
if (updatedBlock) {
|
||||||
|
await updateBackend(updatedBlock);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
updateBlockPosition={async (blockId, position) => {
|
||||||
|
const updatedBlocks = peekUpdateBlockPosition(blockId, position);
|
||||||
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
||||||
|
if (updatedBlock) {
|
||||||
|
await updateBackend(updatedBlock);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
updateBlockPositionType={async (blockId, positionType) => {
|
||||||
|
const updatedBlocks = peekUpdateBlockPositionType(blockId, positionType);
|
||||||
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
||||||
|
if (updatedBlock) {
|
||||||
|
await updateBackend(updatedBlock);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
updateBlockZIndex={async (blockId, zIndex) => {
|
||||||
|
const updatedBlocks = peekUpdateBlockZIndex(blockId, zIndex);
|
||||||
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
||||||
|
if (updatedBlock) {
|
||||||
|
await updateBackend(updatedBlock);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
handleRemoveBlock={async (blockId) => {
|
||||||
const block = getBlockById(blockId);
|
const block = getBlockById(blockId);
|
||||||
if (!block) return;
|
if (!block) return;
|
||||||
deleteDashBoardBlocksApi({ projectId: projectId!, versionId: selectedVersion!.versionId, blocks: [block] }).then((data) => {
|
|
||||||
|
try {
|
||||||
|
const data = await deleteDashBoardBlocksApi({
|
||||||
|
projectId: projectId!,
|
||||||
|
versionId: selectedVersion!.versionId,
|
||||||
|
blocks: [block],
|
||||||
|
});
|
||||||
|
|
||||||
if (data.blocks.length > 0) {
|
if (data.blocks.length > 0) {
|
||||||
data.blocks.forEach((updatedBlock: any) => {
|
data.blocks.forEach((updatedBlock: any) => {
|
||||||
if (updatedBlock.message === "Block deleted successfully") {
|
if (updatedBlock.message === "Block deleted successfully") {
|
||||||
@@ -397,7 +508,9 @@ const DashboardEditor: React.FC = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
} catch (error) {
|
||||||
|
console.error("Failed to delete block:", error);
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -408,16 +521,76 @@ const DashboardEditor: React.FC = () => {
|
|||||||
currentElement={currentElement}
|
currentElement={currentElement}
|
||||||
selectedBlock={selectedBlock}
|
selectedBlock={selectedBlock}
|
||||||
selectedElement={selectedElement}
|
selectedElement={selectedElement}
|
||||||
updateElementStyle={(blockId, elementId, style) => updateElementStyle(blockId, elementId, style)}
|
updateElementStyle={async (blockId, elementId, style) => {
|
||||||
updateElementSize={(blockId, elementId, size) => updateElementSize(blockId, elementId, size)}
|
const updatedBlocks = peekUpdateElementStyle(blockId, elementId, style);
|
||||||
updateElementPosition={(blockId, elementId, position) => updateElementPosition(blockId, elementId, position)}
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
||||||
updateElementPositionType={(blockId, elementId, positionType) => updateElementPositionType(blockId, elementId, positionType)}
|
if (updatedBlock) {
|
||||||
updateElementZIndex={(blockId, elementId, zIndex) => updateElementZIndex(blockId, elementId, zIndex)}
|
await updateBackend(updatedBlock);
|
||||||
updateElementData={(blockId, elementId, updates) => updateElementData(blockId, elementId, updates)}
|
}
|
||||||
updateGraphData={(blockId, elementId, newData) => updateGraphData(blockId, elementId, newData)}
|
}}
|
||||||
updateGraphTitle={(blockId, elementId, title) => updateGraphTitle(blockId, elementId, title)}
|
updateElementSize={async (blockId, elementId, size) => {
|
||||||
updateGraphType={(blockId, elementId, type) => updateGraphType(blockId, elementId, type)}
|
const updatedBlocks = peekUpdateElementSize(blockId, elementId, size);
|
||||||
handleRemoveElement={(blockId, elementId) => removeElement(blockId, elementId)}
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
||||||
|
if (updatedBlock) {
|
||||||
|
await updateBackend(updatedBlock);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
updateElementPosition={async (blockId, elementId, position) => {
|
||||||
|
const updatedBlocks = peekUpdateElementPosition(blockId, elementId, position);
|
||||||
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
||||||
|
if (updatedBlock) {
|
||||||
|
await updateBackend(updatedBlock);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
updateElementPositionType={async (blockId, elementId, positionType) => {
|
||||||
|
const updatedBlocks = peekUpdateElementPositionType(blockId, elementId, positionType);
|
||||||
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
||||||
|
if (updatedBlock) {
|
||||||
|
await updateBackend(updatedBlock);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
updateElementZIndex={async (blockId, elementId, zIndex) => {
|
||||||
|
const updatedBlocks = peekUpdateElementZIndex(blockId, elementId, zIndex);
|
||||||
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
||||||
|
if (updatedBlock) {
|
||||||
|
await updateBackend(updatedBlock);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
updateElementData={async (blockId, elementId, updates) => {
|
||||||
|
const updatedBlocks = peekUpdateElementData(blockId, elementId, updates);
|
||||||
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
||||||
|
if (updatedBlock) {
|
||||||
|
await updateBackend(updatedBlock);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
updateGraphData={async (blockId, elementId, newData) => {
|
||||||
|
const updatedBlocks = peekUpdateGraphData(blockId, elementId, newData);
|
||||||
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
||||||
|
if (updatedBlock) {
|
||||||
|
await updateBackend(updatedBlock);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
updateGraphTitle={async (blockId, elementId, title) => {
|
||||||
|
const updatedBlocks = peekUpdateGraphTitle(blockId, elementId, title);
|
||||||
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
||||||
|
if (updatedBlock) {
|
||||||
|
await updateBackend(updatedBlock);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
updateGraphType={async (blockId, elementId, type) => {
|
||||||
|
const updatedBlocks = peekUpdateGraphType(blockId, elementId, type);
|
||||||
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
||||||
|
if (updatedBlock) {
|
||||||
|
await updateBackend(updatedBlock);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
handleRemoveElement={async (blockId, elementId) => {
|
||||||
|
const updatedBlocks = peekRemoveElement(blockId, elementId);
|
||||||
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
||||||
|
if (updatedBlock) {
|
||||||
|
await updateBackend(updatedBlock);
|
||||||
|
}
|
||||||
|
}}
|
||||||
setSwapSource={setSwapSource}
|
setSwapSource={setSwapSource}
|
||||||
setShowSwapUI={setShowSwapUI}
|
setShowSwapUI={setShowSwapUI}
|
||||||
dataModelManager={dataModelManager}
|
dataModelManager={dataModelManager}
|
||||||
|
|||||||
@@ -115,7 +115,6 @@ export const handleBlockClick = (
|
|||||||
setSelectedBlock(blockId);
|
setSelectedBlock(blockId);
|
||||||
setSelectedElement(null);
|
setSelectedElement(null);
|
||||||
setShowSwapUI(false);
|
setShowSwapUI(false);
|
||||||
console.log('showElementDropdown: ', showElementDropdown);
|
|
||||||
if (showElementDropdown && showElementDropdown !== blockId) {
|
if (showElementDropdown && showElementDropdown !== blockId) {
|
||||||
setShowElementDropdown(blockId);
|
setShowElementDropdown(blockId);
|
||||||
}
|
}
|
||||||
@@ -135,8 +134,8 @@ export const handleElementClick = (
|
|||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
if (editMode) {
|
if (editMode) {
|
||||||
setSelectedElement(elementId);
|
setSelectedElement(elementId);
|
||||||
setSelectedBlock(blockId);
|
// setSelectedBlock(blockId);
|
||||||
setShowSwapUI(false);
|
// setShowSwapUI(false);
|
||||||
// setShowElementDropdown(null);
|
// setShowElementDropdown(null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ interface SimulationDashboardStore {
|
|||||||
setSelectedElement: (elementId: string | null) => void;
|
setSelectedElement: (elementId: string | null) => void;
|
||||||
|
|
||||||
// Block operations
|
// Block operations
|
||||||
addBlock: () => void;
|
addBlock: (newBlock : Block) => void;
|
||||||
removeBlock: (blockId: string) => void;
|
removeBlock: (blockId: string) => void;
|
||||||
updateBlock: (blockId: string, updates: Partial<Block>) => void;
|
updateBlock: (blockId: string, updates: Partial<Block>) => void;
|
||||||
clearBlocks: () => void;
|
clearBlocks: () => void;
|
||||||
@@ -53,6 +53,29 @@ interface SimulationDashboardStore {
|
|||||||
// Element swapping
|
// Element swapping
|
||||||
swapElements: (blockId: string, elementId1: string, elementId2: string) => void;
|
swapElements: (blockId: string, elementId1: string, elementId2: string) => void;
|
||||||
|
|
||||||
|
// Peek operations (get updated value without setting state)
|
||||||
|
peekAddBlock: () => Block[];
|
||||||
|
peekRemoveBlock: (blockId: string) => Block[];
|
||||||
|
peekUpdateBlock: (blockId: string, updates: Partial<Block>) => Block[];
|
||||||
|
peekUpdateBlockStyle: (blockId: string, newStyle: React.CSSProperties) => Block[];
|
||||||
|
peekUpdateBlockSize: (blockId: string, size: Size) => Block[];
|
||||||
|
peekUpdateBlockPosition: (blockId: string, position: Position) => Block[];
|
||||||
|
peekUpdateBlockPositionType: (blockId: string, positionType: "relative" | "absolute" | "fixed") => Block[];
|
||||||
|
peekUpdateBlockZIndex: (blockId: string, zIndex: number) => Block[];
|
||||||
|
peekAddElement: (blockId: string, type: UIType, graphType?: GraphTypes, dataType?: DataType) => Block[];
|
||||||
|
peekRemoveElement: (blockId: string, elementId: string) => Block[];
|
||||||
|
peekUpdateElement: (blockId: string, elementId: string, updates: Partial<UIElement>) => Block[];
|
||||||
|
peekUpdateElementStyle: (blockId: string, elementId: string, newStyle: ExtendedCSSProperties) => Block[];
|
||||||
|
peekUpdateElementSize: (blockId: string, elementId: string, size: Size) => Block[];
|
||||||
|
peekUpdateElementPosition: (blockId: string, elementId: string, position: Position) => Block[];
|
||||||
|
peekUpdateElementPositionType: (blockId: string, elementId: string, positionType: "relative" | "absolute" | "fixed") => Block[];
|
||||||
|
peekUpdateElementZIndex: (blockId: string, elementId: string, zIndex: number) => Block[];
|
||||||
|
peekUpdateElementData: (blockId: string, elementId: string, updates: Partial<DataBinding>) => Block[];
|
||||||
|
peekUpdateGraphData: (blockId: string, elementId: string, newData: GraphDataPoint[]) => Block[];
|
||||||
|
peekUpdateGraphTitle: (blockId: string, elementId: string, title: string) => Block[];
|
||||||
|
peekUpdateGraphType: (blockId: string, elementId: string, graphType: GraphTypes) => Block[];
|
||||||
|
peekSwapElements: (blockId: string, elementId1: string, elementId2: string) => Block[];
|
||||||
|
|
||||||
// Helper functions
|
// Helper functions
|
||||||
getBlockById: (blockId: string) => Block | undefined;
|
getBlockById: (blockId: string) => Block | undefined;
|
||||||
getElementById: (blockId: string, elementId: string) => UIElement | undefined;
|
getElementById: (blockId: string, elementId: string) => UIElement | undefined;
|
||||||
@@ -64,6 +87,11 @@ interface SimulationDashboardStore {
|
|||||||
|
|
||||||
const subscribers = new Set<() => void>();
|
const subscribers = new Set<() => void>();
|
||||||
|
|
||||||
|
// Helper function to deep clone blocks
|
||||||
|
const cloneBlocks = (blocks: Block[]): Block[] => {
|
||||||
|
return JSON.parse(JSON.stringify(blocks));
|
||||||
|
};
|
||||||
|
|
||||||
export const createSimulationDashboardStore = () => {
|
export const createSimulationDashboardStore = () => {
|
||||||
return create<SimulationDashboardStore>()(
|
return create<SimulationDashboardStore>()(
|
||||||
immer((set, get) => ({
|
immer((set, get) => ({
|
||||||
@@ -96,7 +124,6 @@ export const createSimulationDashboardStore = () => {
|
|||||||
setSelectedBlock: (blockId) => {
|
setSelectedBlock: (blockId) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.selectedBlock = blockId;
|
state.selectedBlock = blockId;
|
||||||
// Clear element selection when selecting a block
|
|
||||||
if (blockId) {
|
if (blockId) {
|
||||||
state.selectedElement = null;
|
state.selectedElement = null;
|
||||||
}
|
}
|
||||||
@@ -110,26 +137,8 @@ export const createSimulationDashboardStore = () => {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Block operations
|
// Block operations
|
||||||
addBlock: () => {
|
addBlock: (newBlock) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const newBlock: Block = {
|
|
||||||
blockUuid: MathUtils.generateUUID(),
|
|
||||||
style: {
|
|
||||||
backgroundColor: "rgba(50, 50, 50, 0.8)",
|
|
||||||
backdropFilter: "blur(10px)",
|
|
||||||
padding: 10,
|
|
||||||
borderRadius: 8,
|
|
||||||
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
||||||
position: "relative",
|
|
||||||
minHeight: "200px",
|
|
||||||
minWidth: "300px",
|
|
||||||
},
|
|
||||||
elements: [],
|
|
||||||
zIndex: 1,
|
|
||||||
size: { width: 400, height: 300 },
|
|
||||||
position: { x: 0, y: 0 },
|
|
||||||
positionType: "relative",
|
|
||||||
};
|
|
||||||
state.blocks.push(newBlock);
|
state.blocks.push(newBlock);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -292,7 +301,6 @@ export const createSimulationDashboardStore = () => {
|
|||||||
commonValue: "metric-1",
|
commonValue: "metric-1",
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
// Default to single-machine
|
|
||||||
newElement = {
|
newElement = {
|
||||||
...baseGraphProps,
|
...baseGraphProps,
|
||||||
dataType: "single-machine" as const,
|
dataType: "single-machine" as const,
|
||||||
@@ -334,7 +342,7 @@ export const createSimulationDashboardStore = () => {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return; // Should not happen
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
block.elements.push(newElement);
|
block.elements.push(newElement);
|
||||||
@@ -471,7 +479,6 @@ export const createSimulationDashboardStore = () => {
|
|||||||
if (element && element.type === "graph") {
|
if (element && element.type === "graph") {
|
||||||
element.graphType = graphType;
|
element.graphType = graphType;
|
||||||
element.graphTitle = `${graphType.charAt(0).toUpperCase() + graphType.slice(1)} Chart`;
|
element.graphTitle = `${graphType.charAt(0).toUpperCase() + graphType.slice(1)} Chart`;
|
||||||
|
|
||||||
element.graphData = defaultGraphData;
|
element.graphData = defaultGraphData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -498,6 +505,367 @@ export const createSimulationDashboardStore = () => {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Peek operations - return updated blocks without setting state
|
||||||
|
peekAddBlock: () => {
|
||||||
|
const blocks = cloneBlocks(get().blocks);
|
||||||
|
const newBlock: Block = {
|
||||||
|
blockUuid: MathUtils.generateUUID(),
|
||||||
|
style: {
|
||||||
|
backgroundColor: "rgba(50, 50, 50, 0.8)",
|
||||||
|
backdropFilter: "blur(10px)",
|
||||||
|
padding: 10,
|
||||||
|
borderRadius: 8,
|
||||||
|
border: "1px solid rgba(255, 255, 255, 0.1)",
|
||||||
|
position: "relative",
|
||||||
|
minHeight: "200px",
|
||||||
|
minWidth: "300px",
|
||||||
|
},
|
||||||
|
elements: [],
|
||||||
|
zIndex: 1,
|
||||||
|
size: { width: 400, height: 300 },
|
||||||
|
position: { x: 0, y: 0 },
|
||||||
|
positionType: "relative",
|
||||||
|
};
|
||||||
|
blocks.push(newBlock);
|
||||||
|
return blocks;
|
||||||
|
},
|
||||||
|
|
||||||
|
peekRemoveBlock: (blockId) => {
|
||||||
|
const blocks = cloneBlocks(get().blocks);
|
||||||
|
return blocks.filter((block) => block.blockUuid !== blockId);
|
||||||
|
},
|
||||||
|
|
||||||
|
peekUpdateBlock: (blockId, updates) => {
|
||||||
|
const blocks = cloneBlocks(get().blocks);
|
||||||
|
const block = blocks.find((b) => b.blockUuid === blockId);
|
||||||
|
if (block) {
|
||||||
|
Object.assign(block, updates);
|
||||||
|
}
|
||||||
|
return blocks;
|
||||||
|
},
|
||||||
|
|
||||||
|
peekUpdateBlockStyle: (blockId, newStyle) => {
|
||||||
|
const blocks = cloneBlocks(get().blocks);
|
||||||
|
const block = blocks.find((b) => b.blockUuid === blockId);
|
||||||
|
if (block) {
|
||||||
|
block.style = { ...block.style, ...newStyle };
|
||||||
|
}
|
||||||
|
return blocks;
|
||||||
|
},
|
||||||
|
|
||||||
|
peekUpdateBlockSize: (blockId, size) => {
|
||||||
|
const blocks = cloneBlocks(get().blocks);
|
||||||
|
const block = blocks.find((b) => b.blockUuid === blockId);
|
||||||
|
if (block) {
|
||||||
|
block.size = size;
|
||||||
|
}
|
||||||
|
return blocks;
|
||||||
|
},
|
||||||
|
|
||||||
|
peekUpdateBlockPosition: (blockId, position) => {
|
||||||
|
const blocks = cloneBlocks(get().blocks);
|
||||||
|
const block = blocks.find((b) => b.blockUuid === blockId);
|
||||||
|
if (block) {
|
||||||
|
block.position = position;
|
||||||
|
}
|
||||||
|
return blocks;
|
||||||
|
},
|
||||||
|
|
||||||
|
peekUpdateBlockPositionType: (blockId, positionType) => {
|
||||||
|
const blocks = cloneBlocks(get().blocks);
|
||||||
|
const block = blocks.find((b) => b.blockUuid === blockId);
|
||||||
|
if (block) {
|
||||||
|
block.positionType = positionType;
|
||||||
|
}
|
||||||
|
return blocks;
|
||||||
|
},
|
||||||
|
|
||||||
|
peekUpdateBlockZIndex: (blockId, zIndex) => {
|
||||||
|
const blocks = cloneBlocks(get().blocks);
|
||||||
|
const block = blocks.find((b) => b.blockUuid === blockId);
|
||||||
|
if (block) {
|
||||||
|
block.zIndex = zIndex;
|
||||||
|
}
|
||||||
|
return blocks;
|
||||||
|
},
|
||||||
|
|
||||||
|
peekAddElement: (blockId, type, graphType, dataType?: DataType) => {
|
||||||
|
const blocks = cloneBlocks(get().blocks);
|
||||||
|
const block = blocks.find((b) => b.blockUuid === blockId);
|
||||||
|
if (!block) return blocks;
|
||||||
|
|
||||||
|
let newElement: UIElement;
|
||||||
|
|
||||||
|
const commonProps = {
|
||||||
|
elementUuid: MathUtils.generateUUID(),
|
||||||
|
positionType: "relative" as const,
|
||||||
|
position: { x: 0, y: 0 },
|
||||||
|
zIndex: 1,
|
||||||
|
data: {
|
||||||
|
key: MathUtils.generateUUID(),
|
||||||
|
dataSource: "static" as const,
|
||||||
|
staticValue: "",
|
||||||
|
label: undefined,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case "label-value":
|
||||||
|
newElement = {
|
||||||
|
...commonProps,
|
||||||
|
type: "label-value",
|
||||||
|
title: "Label Value",
|
||||||
|
dataSource: "machine-1",
|
||||||
|
dataValue: "metric-1",
|
||||||
|
style: {
|
||||||
|
color: "#ffffff",
|
||||||
|
fontSize: 14,
|
||||||
|
textAlign: "left" as const,
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
gap: "4px",
|
||||||
|
alignItems: "flex-start",
|
||||||
|
justifyContent: "center",
|
||||||
|
labelColor: "#ffffff",
|
||||||
|
valueColor: "#ffffff",
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
...commonProps.data,
|
||||||
|
staticValue: "Value",
|
||||||
|
label: "Label",
|
||||||
|
},
|
||||||
|
size: { width: 200, height: 60 },
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "graph":
|
||||||
|
const baseGraphProps = {
|
||||||
|
...commonProps,
|
||||||
|
type: "graph" as const,
|
||||||
|
graphType: graphType,
|
||||||
|
graphTitle: "Graph Title",
|
||||||
|
style: {
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
minHeight: "120px",
|
||||||
|
color: "#ffffff",
|
||||||
|
fontSize: 14,
|
||||||
|
textAlign: "left" as const,
|
||||||
|
backgroundColor: "rgba(0, 0, 0, 0.2)",
|
||||||
|
borderRadius: "4px",
|
||||||
|
padding: "8px",
|
||||||
|
},
|
||||||
|
graphData: defaultGraphData,
|
||||||
|
size: { width: 400, height: 200 },
|
||||||
|
};
|
||||||
|
|
||||||
|
if (dataType === "multiple-machine") {
|
||||||
|
newElement = {
|
||||||
|
...baseGraphProps,
|
||||||
|
dataType: "multiple-machine" as const,
|
||||||
|
title: "Multi Machine Chart",
|
||||||
|
dataSource: ["machine-1", "machine-2", "machine-3"],
|
||||||
|
commonValue: "metric-1",
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
newElement = {
|
||||||
|
...baseGraphProps,
|
||||||
|
dataType: "single-machine" as const,
|
||||||
|
title: "Single Machine Chart",
|
||||||
|
dataSource: "machine-1",
|
||||||
|
dataValue: ["metric-1", "metric-2", "metric-3"],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "text":
|
||||||
|
newElement = {
|
||||||
|
...commonProps,
|
||||||
|
type: "text",
|
||||||
|
style: {
|
||||||
|
color: "#ffffff",
|
||||||
|
fontSize: 14,
|
||||||
|
textAlign: "left" as const,
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
...commonProps.data,
|
||||||
|
staticValue: "Text",
|
||||||
|
},
|
||||||
|
size: { width: 200, height: 40 },
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "icon":
|
||||||
|
newElement = {
|
||||||
|
...commonProps,
|
||||||
|
type: "icon",
|
||||||
|
style: {
|
||||||
|
color: "#ffffff",
|
||||||
|
fontSize: 14,
|
||||||
|
textAlign: "center" as const,
|
||||||
|
},
|
||||||
|
size: { width: 40, height: 40 },
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
block.elements.push(newElement);
|
||||||
|
return blocks;
|
||||||
|
},
|
||||||
|
|
||||||
|
peekRemoveElement: (blockId, elementId) => {
|
||||||
|
const blocks = cloneBlocks(get().blocks);
|
||||||
|
const block = blocks.find((b) => b.blockUuid === blockId);
|
||||||
|
if (block) {
|
||||||
|
block.elements = block.elements.filter((el) => el.elementUuid !== elementId);
|
||||||
|
}
|
||||||
|
return blocks;
|
||||||
|
},
|
||||||
|
|
||||||
|
peekUpdateElement: (blockId, elementId, updates) => {
|
||||||
|
const blocks = cloneBlocks(get().blocks);
|
||||||
|
const block = blocks.find((b) => b.blockUuid === blockId);
|
||||||
|
if (block) {
|
||||||
|
const element = block.elements.find((el) => el.elementUuid === elementId);
|
||||||
|
if (element) {
|
||||||
|
Object.assign(element, updates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return blocks;
|
||||||
|
},
|
||||||
|
|
||||||
|
peekUpdateElementStyle: (blockId, elementId, newStyle) => {
|
||||||
|
const blocks = cloneBlocks(get().blocks);
|
||||||
|
const block = blocks.find((b) => b.blockUuid === blockId);
|
||||||
|
if (block) {
|
||||||
|
const element = block.elements.find((el) => el.elementUuid === elementId);
|
||||||
|
if (element) {
|
||||||
|
element.style = { ...element.style, ...newStyle };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return blocks;
|
||||||
|
},
|
||||||
|
|
||||||
|
peekUpdateElementSize: (blockId, elementId, size) => {
|
||||||
|
const blocks = cloneBlocks(get().blocks);
|
||||||
|
const block = blocks.find((b) => b.blockUuid === blockId);
|
||||||
|
if (block) {
|
||||||
|
const element = block.elements.find((el) => el.elementUuid === elementId);
|
||||||
|
if (element) {
|
||||||
|
element.size = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return blocks;
|
||||||
|
},
|
||||||
|
|
||||||
|
peekUpdateElementPosition: (blockId, elementId, position) => {
|
||||||
|
const blocks = cloneBlocks(get().blocks);
|
||||||
|
const block = blocks.find((b) => b.blockUuid === blockId);
|
||||||
|
if (block) {
|
||||||
|
const element = block.elements.find((el) => el.elementUuid === elementId);
|
||||||
|
if (element) {
|
||||||
|
element.position = position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return blocks;
|
||||||
|
},
|
||||||
|
|
||||||
|
peekUpdateElementPositionType: (blockId, elementId, positionType) => {
|
||||||
|
const blocks = cloneBlocks(get().blocks);
|
||||||
|
const block = blocks.find((b) => b.blockUuid === blockId);
|
||||||
|
if (block) {
|
||||||
|
const element = block.elements.find((el) => el.elementUuid === elementId);
|
||||||
|
if (element) {
|
||||||
|
element.positionType = positionType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return blocks;
|
||||||
|
},
|
||||||
|
|
||||||
|
peekUpdateElementZIndex: (blockId, elementId, zIndex) => {
|
||||||
|
const blocks = cloneBlocks(get().blocks);
|
||||||
|
const block = blocks.find((b) => b.blockUuid === blockId);
|
||||||
|
if (block) {
|
||||||
|
const element = block.elements.find((el) => el.elementUuid === elementId);
|
||||||
|
if (element) {
|
||||||
|
element.zIndex = zIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return blocks;
|
||||||
|
},
|
||||||
|
|
||||||
|
peekUpdateElementData: (blockId, elementId, updates) => {
|
||||||
|
const blocks = cloneBlocks(get().blocks);
|
||||||
|
const block = blocks.find((b) => b.blockUuid === blockId);
|
||||||
|
if (block) {
|
||||||
|
const element = block.elements.find((el) => el.elementUuid === elementId);
|
||||||
|
if (element?.data) {
|
||||||
|
element.data = { ...element.data, ...updates };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return blocks;
|
||||||
|
},
|
||||||
|
|
||||||
|
peekUpdateGraphData: (blockId, elementId, newData) => {
|
||||||
|
const blocks = cloneBlocks(get().blocks);
|
||||||
|
const block = blocks.find((b) => b.blockUuid === blockId);
|
||||||
|
if (block) {
|
||||||
|
const element = block.elements.find((el) => el.elementUuid === elementId);
|
||||||
|
if (element) {
|
||||||
|
element.graphData = newData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return blocks;
|
||||||
|
},
|
||||||
|
|
||||||
|
peekUpdateGraphTitle: (blockId, elementId, title) => {
|
||||||
|
const blocks = cloneBlocks(get().blocks);
|
||||||
|
const block = blocks.find((b) => b.blockUuid === blockId);
|
||||||
|
if (block) {
|
||||||
|
const element = block.elements.find((el) => el.elementUuid === elementId);
|
||||||
|
if (element) {
|
||||||
|
element.graphTitle = title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return blocks;
|
||||||
|
},
|
||||||
|
|
||||||
|
peekUpdateGraphType: (blockId, elementId, graphType) => {
|
||||||
|
const blocks = cloneBlocks(get().blocks);
|
||||||
|
const block = blocks.find((b) => b.blockUuid === blockId);
|
||||||
|
if (block) {
|
||||||
|
const element = block.elements.find((el) => el.elementUuid === elementId);
|
||||||
|
if (element && element.type === "graph") {
|
||||||
|
element.graphType = graphType;
|
||||||
|
element.graphTitle = `${graphType.charAt(0).toUpperCase() + graphType.slice(1)} Chart`;
|
||||||
|
element.graphData = defaultGraphData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return blocks;
|
||||||
|
},
|
||||||
|
|
||||||
|
peekSwapElements: (blockId, elementId1, elementId2) => {
|
||||||
|
const blocks = cloneBlocks(get().blocks);
|
||||||
|
const block = blocks.find((b) => b.blockUuid === blockId);
|
||||||
|
if (block) {
|
||||||
|
block.elements = block.elements.map((el) => {
|
||||||
|
if (el.elementUuid === elementId1) {
|
||||||
|
const targetElement = block.elements.find((e) => e.elementUuid === elementId2);
|
||||||
|
return targetElement ? { ...targetElement, elementUuid: elementId1 } : el;
|
||||||
|
}
|
||||||
|
if (el.elementUuid === elementId2) {
|
||||||
|
const sourceElement = block.elements.find((e) => e.elementUuid === elementId1);
|
||||||
|
return sourceElement ? { ...sourceElement, elementUuid: elementId2 } : el;
|
||||||
|
}
|
||||||
|
return el;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return blocks;
|
||||||
|
},
|
||||||
|
|
||||||
// Helper functions
|
// Helper functions
|
||||||
getBlockById: (blockId) => {
|
getBlockById: (blockId) => {
|
||||||
return get().blocks.find((b) => b.blockUuid === blockId);
|
return get().blocks.find((b) => b.blockUuid === blockId);
|
||||||
|
|||||||
Reference in New Issue
Block a user