658 lines
33 KiB
TypeScript
658 lines
33 KiB
TypeScript
import { useParams } from "react-router-dom";
|
|
import React, { useState, useRef, useEffect } from "react";
|
|
import { dataModelManager } from "./data/dataModel";
|
|
import ControlPanel from "./ControlPanel";
|
|
import SwapModal from "./SwapModal";
|
|
import { Block } from "../../types/exportedTypes";
|
|
import DataModelPanel from "./components/models/DataModelPanel";
|
|
import AnalyzerManager from "./AnalyzerManager";
|
|
|
|
import { useSceneContext } from "../../modules/scene/sceneContext";
|
|
import useModuleStore from "../../store/ui/useModuleStore";
|
|
import { usePlayButtonStore } from "../../store/ui/usePlayButtonStore";
|
|
import { calculateMinBlockSize } from "./functions/block/calculateMinBlockSize";
|
|
import { handleElementDragStart, handleElementResizeStart, handleBlockResizeStart, handleSwapStart, handleSwapTarget, handleBlockClick, handleElementClick } from "./functions/eventHandlers";
|
|
import BlockGrid from "./components/block/BlockGrid";
|
|
import BlockEditor from "./components/block/BlockEditor";
|
|
import ElementEditor from "./components/element/ElementEditor";
|
|
import useCallBackOnKey from "../../utils/hooks/useCallBackOnKey";
|
|
import { handleBlockDragStart } from "./functions/block/handleBlockDragStart";
|
|
|
|
import { getDashBoardBlocksApi } from "../../services/visulization/dashBoard/getDashBoardBlocks";
|
|
import { upsetDashBoardBlocksApi } from "../../services/visulization/dashBoard/upsertDashBoardBlocks";
|
|
import { deleteDashBoardBlocksApi } from "../../services/visulization/dashBoard/deleteDashBoardBlocks";
|
|
import { deleteDashBoardElementsApi } from "../../services/visulization/dashBoard/deleteDashBoardElements";
|
|
|
|
const DashboardEditor: React.FC = () => {
|
|
const { simulationDashBoardStore, versionStore } = useSceneContext();
|
|
const { selectedVersion } = versionStore();
|
|
const { projectId } = useParams();
|
|
const { activeModule } = useModuleStore();
|
|
const { isPlaying } = usePlayButtonStore();
|
|
const {
|
|
blocks,
|
|
selectedBlock,
|
|
setSelectedBlock,
|
|
selectedElement,
|
|
setSelectedElement,
|
|
addBlock,
|
|
setBlocks,
|
|
removeBlock,
|
|
removeElement,
|
|
getBlockById,
|
|
updateBlock,
|
|
// Peek methods
|
|
peekAddBlock,
|
|
peekRemoveBlock,
|
|
peekAddElement,
|
|
peekRemoveElement,
|
|
peekUpdateBlockStyle,
|
|
peekUpdateBlockSize,
|
|
peekUpdateBlockPosition,
|
|
peekUpdateBlockPositionType,
|
|
peekUpdateBlockZIndex,
|
|
peekUpdateElementStyle,
|
|
peekUpdateElementSize,
|
|
peekUpdateElementPosition,
|
|
peekUpdateElementPositionType,
|
|
peekUpdateElementZIndex,
|
|
peekUpdateElementData,
|
|
peekUpdateGraphData,
|
|
peekUpdateGraphTitle,
|
|
peekUpdateGraphType,
|
|
peekUpdateDataType,
|
|
peekUpdateCommonValue,
|
|
peekUpdateDataValue,
|
|
peekUpdateDataSource,
|
|
peekSwapElements,
|
|
} = simulationDashBoardStore();
|
|
|
|
const [editMode, setEditMode] = useState(false);
|
|
const [draggingElement, setDraggingElement] = useState<string | null>(null);
|
|
const [resizingElement, setResizingElement] = useState<string | null>(null);
|
|
const [resizingBlock, setResizingBlock] = useState<string | null>(null);
|
|
const [resizeStart, setResizeStart] = useState<{
|
|
x: number;
|
|
y: number;
|
|
width: number;
|
|
height: number;
|
|
} | null>(null);
|
|
const [showSwapUI, setShowSwapUI] = useState(false);
|
|
const [swapSource, setSwapSource] = useState<string | null>(null);
|
|
const [dataModel, setDataModel] = useState<DataModel>(dataModelManager.getDataSnapshot());
|
|
const [showDataModelPanel, setShowDataModelPanel] = useState(false);
|
|
const [showElementDropdown, setShowElementDropdown] = useState<string | null>(null);
|
|
const [draggingBlock, setDraggingBlock] = useState<string | null>(null);
|
|
const [elementDragOffset, setElementDragOffset] = useState<Position>({ x: 0, y: 0 });
|
|
const [blockDragOffset, setBlockDragOffset] = useState<Position>({ x: 0, y: 0 });
|
|
|
|
const editorRef = useRef<HTMLDivElement>(null);
|
|
const blockEditorRef = useRef<HTMLDivElement>(null);
|
|
const elementEditorRef = useRef<HTMLDivElement>(null);
|
|
const dropdownRef = useRef<HTMLDivElement>(null);
|
|
const blockRef = useRef<HTMLDivElement>(null);
|
|
|
|
const currentBlock = blocks.find((b) => b.blockUuid === selectedBlock);
|
|
const currentElement = currentBlock?.elements.find((el) => el.elementUuid === selectedElement);
|
|
|
|
// Helper function to send updates to backend - only sends the specific block that changed
|
|
const updateBackend = async (updatedBlock: Block) => {
|
|
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(() => {
|
|
if (!projectId || !selectedVersion) return;
|
|
getDashBoardBlocksApi(projectId, selectedVersion.versionId).then((data) => {
|
|
if (data.data?.blocks) {
|
|
setBlocks(data.data.blocks);
|
|
}
|
|
});
|
|
}, [projectId, selectedVersion]);
|
|
|
|
useCallBackOnKey(
|
|
() => {
|
|
if (!projectId || !selectedVersion) return;
|
|
// For Ctrl+S, send all blocks
|
|
upsetDashBoardBlocksApi({
|
|
projectId,
|
|
versionId: selectedVersion.versionId,
|
|
blocks: blocks,
|
|
});
|
|
},
|
|
"Ctrl+S",
|
|
{ dependencies: [blocks, projectId, selectedVersion], noRepeat: true, allowOnInput: true }
|
|
);
|
|
|
|
// Subscribe to data model changes
|
|
useEffect(() => {
|
|
const handleDataChange = (): void => {
|
|
setDataModel(dataModelManager.getDataSnapshot());
|
|
};
|
|
|
|
const keys = dataModelManager.getAvailableKeys();
|
|
const subscriptions: Array<[string, () => void]> = [];
|
|
|
|
for (const key of keys) {
|
|
const callback = () => handleDataChange();
|
|
dataModelManager.subscribe(key, callback);
|
|
subscriptions.push([key, callback]);
|
|
}
|
|
|
|
const interval = setInterval(() => {
|
|
const currentKeys = dataModelManager.getAvailableKeys();
|
|
const newKeys = currentKeys.filter((key) => !keys.includes(key));
|
|
|
|
for (const key of newKeys) {
|
|
const callback = () => handleDataChange();
|
|
dataModelManager.subscribe(key, callback);
|
|
subscriptions.push([key, callback]);
|
|
}
|
|
}, 1000);
|
|
|
|
return () => {
|
|
for (const [key, callback] of subscriptions) {
|
|
dataModelManager.unsubscribe(key, callback);
|
|
}
|
|
clearInterval(interval);
|
|
};
|
|
}, []);
|
|
|
|
// Click outside handler
|
|
useEffect(() => {
|
|
const handleClickOutside = (event: MouseEvent): void => {
|
|
const target = event.target as Node;
|
|
|
|
const isInsideBlockEditor = blockEditorRef.current?.contains(target);
|
|
const isInsideElementEditor = elementEditorRef.current?.contains(target);
|
|
const isInsideDropdown = dropdownRef.current?.contains(target);
|
|
const isInsideEditor = editorRef.current?.contains(target);
|
|
|
|
if (!isInsideEditor) {
|
|
setSelectedBlock(null);
|
|
setSelectedElement(null);
|
|
setShowSwapUI(false);
|
|
return;
|
|
}
|
|
|
|
if (isInsideEditor && !isInsideBlockEditor && !isInsideElementEditor && !isInsideDropdown) {
|
|
const clickedElement = event.target as HTMLElement;
|
|
const isBlock = clickedElement.closest("[data-block-id]");
|
|
const isElement = clickedElement.closest("[data-element-id]");
|
|
const isButton = clickedElement.closest("button");
|
|
const isResizeHandle = clickedElement.closest(".resize-handle");
|
|
|
|
if (!isBlock && !isElement && !isButton && !isResizeHandle) {
|
|
setSelectedBlock(null);
|
|
setSelectedElement(null);
|
|
setShowSwapUI(false);
|
|
setShowElementDropdown(null);
|
|
}
|
|
}
|
|
};
|
|
|
|
// document.addEventListener("mousedown", handleClickOutside);
|
|
return () => {
|
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
};
|
|
}, [selectedBlock, selectedElement]);
|
|
|
|
// Drag and drop handler
|
|
useEffect(() => {
|
|
const handleMouseMove = (e: MouseEvent): void => {
|
|
// Element dragging - direct DOM manipulation
|
|
if (draggingElement && selectedBlock && currentElement?.positionType === "absolute") {
|
|
const blockElement = document.querySelector(`[data-block-id="${selectedBlock}"]`) as HTMLElement;
|
|
const elementToDrag = document.querySelector(`[data-element-id="${draggingElement}"]`) as HTMLElement;
|
|
|
|
if (blockElement && elementToDrag) {
|
|
const blockRect = blockElement.getBoundingClientRect();
|
|
const newX = e.clientX - blockRect.left - elementDragOffset.x;
|
|
const newY = e.clientY - blockRect.top - elementDragOffset.y;
|
|
|
|
// Direct DOM manipulation
|
|
elementToDrag.style.left = `${Math.max(0, Math.min(blockRect.width - 50, newX))}px`;
|
|
elementToDrag.style.top = `${Math.max(0, Math.min(blockRect.height - 30, newY))}px`;
|
|
}
|
|
}
|
|
|
|
// Block dragging - direct DOM manipulation
|
|
if (draggingBlock && currentBlock?.positionType && (currentBlock.positionType === "absolute" || currentBlock.positionType === "fixed")) {
|
|
const editorElement = editorRef.current;
|
|
const blockToDrag = document.querySelector(`[data-block-id="${draggingBlock}"]`) as HTMLElement;
|
|
|
|
if (editorElement && blockToDrag) {
|
|
const editorRect = editorElement.getBoundingClientRect();
|
|
const newX = e.clientX - editorRect.left - blockDragOffset.x;
|
|
const newY = e.clientY - editorRect.top - blockDragOffset.y;
|
|
|
|
// Direct DOM manipulation
|
|
blockToDrag.style.left = `${Math.max(0, Math.min(editorRect.width - (currentBlock.size?.width || 400), newX))}px`;
|
|
blockToDrag.style.top = `${Math.max(0, Math.min(editorRect.height - (currentBlock.size?.height || 300), newY))}px`;
|
|
}
|
|
}
|
|
|
|
// Resizing - direct DOM manipulation
|
|
if ((resizingElement || resizingBlock) && resizeStart) {
|
|
if (resizingElement && selectedBlock) {
|
|
const elementToResize = document.querySelector(`[data-element-id="${resizingElement}"]`) as HTMLElement;
|
|
if (elementToResize) {
|
|
const deltaX = e.clientX - resizeStart.x;
|
|
const deltaY = e.clientY - resizeStart.y;
|
|
|
|
const newWidth = Math.max(100, resizeStart.width + deltaX);
|
|
const newHeight = Math.max(50, resizeStart.height + deltaY);
|
|
|
|
// Direct DOM manipulation
|
|
elementToResize.style.width = `${newWidth}px`;
|
|
elementToResize.style.height = `${newHeight}px`;
|
|
}
|
|
} else if (resizingBlock) {
|
|
const blockToResize = document.querySelector(`[data-block-id="${resizingBlock}"]`) as HTMLElement;
|
|
if (blockToResize) {
|
|
const deltaX = e.clientX - resizeStart.x;
|
|
const deltaY = e.clientY - resizeStart.y;
|
|
|
|
const currentBlock = blocks.find((b) => b.blockUuid === resizingBlock);
|
|
const minSize = currentBlock ? calculateMinBlockSize(currentBlock) : { width: 100, height: 50 };
|
|
|
|
const newWidth = Math.max(minSize.width, resizeStart.width + deltaX);
|
|
const newHeight = Math.max(minSize.height, resizeStart.height + deltaY);
|
|
|
|
// Direct DOM manipulation
|
|
blockToResize.style.width = `${newWidth}px`;
|
|
blockToResize.style.height = `${newHeight}px`;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
const handleMouseUp = async (): Promise<void> => {
|
|
// Update backend using peek methods, then update state from response
|
|
if (draggingElement && selectedBlock && currentElement?.positionType === "absolute") {
|
|
const blockElement = document.querySelector(`[data-block-id="${selectedBlock}"]`) as HTMLElement;
|
|
const elementToDrag = document.querySelector(`[data-element-id="${draggingElement}"]`) as HTMLElement;
|
|
|
|
if (blockElement && elementToDrag) {
|
|
const computedStyle = window.getComputedStyle(elementToDrag);
|
|
const x = parseFloat(computedStyle.left);
|
|
const y = parseFloat(computedStyle.top);
|
|
|
|
// 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 backend for block drag
|
|
if (draggingBlock && currentBlock?.positionType && (currentBlock.positionType === "absolute" || currentBlock.positionType === "fixed")) {
|
|
const blockToDrag = document.querySelector(`[data-block-id="${draggingBlock}"]`) as HTMLElement;
|
|
|
|
if (blockToDrag) {
|
|
const computedStyle = window.getComputedStyle(blockToDrag);
|
|
const x = parseFloat(computedStyle.left);
|
|
const y = parseFloat(computedStyle.top);
|
|
|
|
// 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 backend for element resize
|
|
if (resizingElement && selectedBlock) {
|
|
const elementToResize = document.querySelector(`[data-element-id="${resizingElement}"]`) as HTMLElement;
|
|
if (elementToResize) {
|
|
const computedStyle = window.getComputedStyle(elementToResize);
|
|
const width = parseFloat(computedStyle.width);
|
|
const height = parseFloat(computedStyle.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) {
|
|
const blockToResize = document.querySelector(`[data-block-id="${resizingBlock}"]`) as HTMLElement;
|
|
if (blockToResize) {
|
|
const computedStyle = window.getComputedStyle(blockToResize);
|
|
const width = parseFloat(computedStyle.width);
|
|
const height = parseFloat(computedStyle.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);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reset all dragging states
|
|
setDraggingElement(null);
|
|
setResizingElement(null);
|
|
setDraggingBlock(null);
|
|
setResizingBlock(null);
|
|
setResizeStart(null);
|
|
};
|
|
|
|
if (draggingElement || draggingBlock || resizingElement || resizingBlock) {
|
|
document.addEventListener("mousemove", handleMouseMove);
|
|
document.addEventListener("mouseup", handleMouseUp);
|
|
}
|
|
|
|
return () => {
|
|
document.removeEventListener("mousemove", handleMouseMove);
|
|
document.removeEventListener("mouseup", handleMouseUp);
|
|
};
|
|
}, [draggingElement, resizingElement, draggingBlock, resizingBlock, elementDragOffset, blockDragOffset, selectedBlock, currentElement, resizeStart, currentBlock, blocks]);
|
|
|
|
return (
|
|
<div ref={editorRef} className="dashboard-editor">
|
|
{activeModule === "visualization" && (
|
|
<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}
|
|
/>
|
|
)}
|
|
|
|
{activeModule === "simulation" && isPlaying && <AnalyzerManager />}
|
|
|
|
{/* BlockGrid */}
|
|
|
|
<div className="block-grid-container">
|
|
<BlockGrid
|
|
blocks={blocks}
|
|
handleAddElement={async (blockId, type, graphType) => {
|
|
const updatedBlocks = peekAddElement(blockId, type, graphType);
|
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
|
if (updatedBlock) {
|
|
await updateBackend(updatedBlock);
|
|
}
|
|
}}
|
|
editMode={editMode}
|
|
selectedBlock={selectedBlock}
|
|
selectedElement={selectedElement}
|
|
showSwapUI={showSwapUI}
|
|
swapSource={swapSource}
|
|
calculateMinBlockSize={calculateMinBlockSize}
|
|
handleBlockClick={(blockId, event) => handleBlockClick(blockId, event, editMode, setSelectedBlock, setSelectedElement, setShowSwapUI, setShowElementDropdown, showElementDropdown)}
|
|
handleElementClick={(blockId, elementId, event) =>
|
|
handleElementClick(blockId, elementId, event, editMode, setSelectedElement, setSelectedBlock, setShowSwapUI, setShowElementDropdown)
|
|
}
|
|
handleElementDragStart={(elementId, event) => handleElementDragStart(elementId, event, currentElement, setDraggingElement, setElementDragOffset)}
|
|
handleElementResizeStart={(elementId, event) => handleElementResizeStart(elementId, event, setResizingElement, setResizeStart)}
|
|
handleBlockResizeStart={(blockId, event) => handleBlockResizeStart(blockId, event, setResizingBlock, setResizeStart)}
|
|
handleSwapStart={(elementId, event) => handleSwapStart(elementId, event, setSwapSource, setShowSwapUI)}
|
|
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)}
|
|
setShowElementDropdown={setShowElementDropdown}
|
|
showElementDropdown={showElementDropdown}
|
|
blockRef={blockRef}
|
|
/>
|
|
|
|
{/* BlockEditor */}
|
|
|
|
{selectedBlock && editMode && !selectedElement && currentBlock && (
|
|
<BlockEditor
|
|
blockEditorRef={blockEditorRef}
|
|
currentBlock={currentBlock}
|
|
selectedBlock={selectedBlock}
|
|
updateBlockStyle={async (blockId, style) => {
|
|
const updatedBlocks = peekUpdateBlockStyle(blockId, style);
|
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
|
if (updatedBlock) {
|
|
await updateBackend(updatedBlock);
|
|
}
|
|
}}
|
|
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);
|
|
if (!block) return;
|
|
|
|
try {
|
|
const data = await deleteDashBoardBlocksApi({
|
|
projectId: projectId!,
|
|
versionId: selectedVersion!.versionId,
|
|
blocks: [block],
|
|
});
|
|
|
|
if (data.blocks.length > 0) {
|
|
data.blocks.forEach((updatedBlock: any) => {
|
|
if (updatedBlock.message === "Block deleted successfully") {
|
|
removeBlock(updatedBlock.blockUuid);
|
|
}
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error("Failed to delete block:", error);
|
|
}
|
|
}}
|
|
/>
|
|
)}
|
|
|
|
{selectedElement && editMode && selectedBlock && currentElement && (
|
|
<ElementEditor
|
|
elementEditorRef={elementEditorRef}
|
|
currentElement={currentElement}
|
|
selectedBlock={selectedBlock}
|
|
selectedElement={selectedElement}
|
|
updateElementStyle={async (blockId, elementId, style) => {
|
|
const updatedBlocks = peekUpdateElementStyle(blockId, elementId, style);
|
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
|
if (updatedBlock) {
|
|
await updateBackend(updatedBlock);
|
|
}
|
|
}}
|
|
updateElementSize={async (blockId, elementId, size) => {
|
|
const updatedBlocks = peekUpdateElementSize(blockId, elementId, size);
|
|
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);
|
|
}
|
|
}}
|
|
updateDataType={async (blockId, elementId, dataType) => {
|
|
const updatedBlocks = peekUpdateDataType(blockId, elementId, dataType);
|
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
|
if (updatedBlock) {
|
|
await updateBackend(updatedBlock);
|
|
}
|
|
}}
|
|
updateCommonValue={async (blockId, elementId, commonValue) => {
|
|
const updatedBlocks = peekUpdateCommonValue(blockId, elementId, commonValue);
|
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
|
if (updatedBlock) {
|
|
await updateBackend(updatedBlock);
|
|
}
|
|
}}
|
|
updateDataValue={async (blockId, elementId, dataValue) => {
|
|
const updatedBlocks = peekUpdateDataValue(blockId, elementId, dataValue);
|
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
|
if (updatedBlock) {
|
|
await updateBackend(updatedBlock);
|
|
}
|
|
}}
|
|
updateDataSource={async (blockId, elementId, dataSource) => {
|
|
const updatedBlocks = peekUpdateDataSource(blockId, elementId, dataSource);
|
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
|
if (updatedBlock) {
|
|
await updateBackend(updatedBlock);
|
|
}
|
|
}}
|
|
handleRemoveElement={async (blockId, elementId) => {
|
|
try {
|
|
const data = await deleteDashBoardElementsApi({
|
|
projectId: projectId!,
|
|
versionId: selectedVersion!.versionId,
|
|
elementDatas: [{ blockUuid: blockId, elementUuid: elementId }],
|
|
});
|
|
|
|
if (data.elements.length > 0) {
|
|
data.elements.forEach((element: any) => {
|
|
if (element.message === "Element deleted successfully") {
|
|
removeElement(element.blockUuid, element.elementUuid);
|
|
}
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error("Failed to delete element:", error);
|
|
}
|
|
}}
|
|
setSwapSource={setSwapSource}
|
|
setShowSwapUI={setShowSwapUI}
|
|
/>
|
|
)}
|
|
</div>
|
|
|
|
{showDataModelPanel && editMode && <DataModelPanel dataModel={dataModel} dataModelManager={dataModelManager} />}
|
|
|
|
{showSwapUI && <SwapModal setShowSwapUI={setShowSwapUI} setSwapSource={setSwapSource} />}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default DashboardEditor;
|