feat: Implement block and element removal functionality in DashboardEditor

- Added deleteDashBoardBlocksApi service to handle block deletion from the dashboard.
- Integrated block removal functionality in DashboardEditor, allowing users to delete blocks.
- Updated BlockEditor and ElementEditor components to include remove block and element handlers.
- Enhanced Zustand store to manage block and element states effectively.
- Updated exported types to accommodate new data structures for blocks and elements.
This commit is contained in:
2025-12-16 11:13:30 +05:30
parent 89c2339012
commit 2f12b35951
8 changed files with 593 additions and 529 deletions

View File

@@ -18,6 +18,7 @@ import { handleBlockDragStart } from "./functions/block/handleBlockDragStart";
import { getDashBoardBlocksApi } from "../../services/visulization/dashBoard/getDashBoardBlocks"; import { getDashBoardBlocksApi } from "../../services/visulization/dashBoard/getDashBoardBlocks";
import { upsetDashBoardBlocksApi } from "../../services/visulization/dashBoard/upsertDashBoardBlocks"; import { upsetDashBoardBlocksApi } from "../../services/visulization/dashBoard/upsertDashBoardBlocks";
import { deleteDashBoardBlocksApi } from "../../services/visulization/dashBoard/deleteDashBoardBlocks";
const DashboardEditor: React.FC = () => { const DashboardEditor: React.FC = () => {
const { simulationDashBoardStore, versionStore } = useSceneContext(); const { simulationDashBoardStore, versionStore } = useSceneContext();
@@ -43,6 +44,9 @@ const DashboardEditor: React.FC = () => {
updateGraphTitle, updateGraphTitle,
updateGraphType, updateGraphType,
swapElements, swapElements,
removeBlock,
removeElement,
getBlockById,
subscribe, subscribe,
} = simulationDashBoardStore(); } = simulationDashBoardStore();
@@ -83,6 +87,7 @@ const DashboardEditor: React.FC = () => {
useEffect(() => { useEffect(() => {
if (!projectId || !selectedVersion) return; if (!projectId || !selectedVersion) return;
getDashBoardBlocksApi(projectId, selectedVersion.versionId).then((data) => { getDashBoardBlocksApi(projectId, selectedVersion.versionId).then((data) => {
console.log("data: ", data);
if (data.data?.blocks) { if (data.data?.blocks) {
setBlocks(data.data.blocks); setBlocks(data.data.blocks);
} }
@@ -102,6 +107,7 @@ const DashboardEditor: React.FC = () => {
useEffect(() => { useEffect(() => {
const unsubscribe = subscribe(() => { const unsubscribe = subscribe(() => {
if (!projectId || !selectedVersion) return; if (!projectId || !selectedVersion) return;
console.log("blocks: ", blocks);
updateBackend(blocks); updateBackend(blocks);
}); });
@@ -374,6 +380,19 @@ const DashboardEditor: React.FC = () => {
updateBlockPosition={(blockId, position) => updateBlockPosition(blockId, position)} updateBlockPosition={(blockId, position) => updateBlockPosition(blockId, position)}
updateBlockPositionType={(blockId, positionType) => updateBlockPositionType(blockId, positionType)} updateBlockPositionType={(blockId, positionType) => updateBlockPositionType(blockId, positionType)}
updateBlockZIndex={(blockId, zIndex) => updateBlockZIndex(blockId, zIndex)} updateBlockZIndex={(blockId, zIndex) => updateBlockZIndex(blockId, zIndex)}
handleRemoveBlock={(blockId) => {
const block = getBlockById(blockId);
if (!block) return;
deleteDashBoardBlocksApi({ projectId: projectId!, versionId: selectedVersion!.versionId, blocks: [block] }).then((data) => {
if (data.blocks.length>0) {
data.blocks.forEach((updatedBlock: any) => {
if (updatedBlock.message === "Block deleted successfully") {
removeBlock(updatedBlock.blockUuid);
}
});
}
});
}}
/> />
)} )}
{selectedElement && editMode && selectedBlock && currentElement && ( {selectedElement && editMode && selectedBlock && currentElement && (
@@ -391,6 +410,7 @@ const DashboardEditor: React.FC = () => {
updateGraphData={(blockId, elementId, newData) => updateGraphData(blockId, elementId, newData)} updateGraphData={(blockId, elementId, newData) => updateGraphData(blockId, elementId, newData)}
updateGraphTitle={(blockId, elementId, title) => updateGraphTitle(blockId, elementId, title)} updateGraphTitle={(blockId, elementId, title) => updateGraphTitle(blockId, elementId, title)}
updateGraphType={(blockId, elementId, type) => updateGraphType(blockId, elementId, type)} updateGraphType={(blockId, elementId, type) => updateGraphType(blockId, elementId, type)}
handleRemoveElement={(blockId, elementId) => removeElement(blockId, elementId)}
setSwapSource={setSwapSource} setSwapSource={setSwapSource}
setShowSwapUI={setShowSwapUI} setShowSwapUI={setShowSwapUI}
dataModelManager={dataModelManager} dataModelManager={dataModelManager}

View File

@@ -47,7 +47,7 @@ const BlockComponent: React.FC<BlockComponentProps> = ({
handleBlockDragStart, handleBlockDragStart,
}) => { }) => {
const { simulationDashBoardStore } = useSceneContext(); const { simulationDashBoardStore } = useSceneContext();
const { addElement } = simulationDashBoardStore() const { addElement } = simulationDashBoardStore();
const dropdownRef = useRef<HTMLDivElement>(null); const dropdownRef = useRef<HTMLDivElement>(null);
@@ -122,10 +122,11 @@ const BlockComponent: React.FC<BlockComponentProps> = ({
))} ))}
{/* Block resize handle */} {/* Block resize handle */}
{editMode && isSelected && {editMode && isSelected && (
<div className="resize-handle" onMouseDown={(e) => handleBlockResizeStart(block.blockUuid, e)}> <div className="resize-handle" onMouseDown={(e) => handleBlockResizeStart(block.blockUuid, e)}>
<ResizeIcon /> <ResizeIcon />
</div>} </div>
)}
{/* Drag handle indicator for absolute/fixed blocks */} {/* Drag handle indicator for absolute/fixed blocks */}
{isDraggable && editMode && ( {isDraggable && editMode && (
@@ -152,9 +153,6 @@ const BlockComponent: React.FC<BlockComponentProps> = ({
</div> </div>
)} )}
</div> </div>
); );
}; };

View File

@@ -18,6 +18,7 @@ interface BlockEditorProps {
updateBlockPosition: (blockId: string, position: { x: number; y: number }) => void; updateBlockPosition: (blockId: string, position: { x: number; y: number }) => void;
updateBlockPositionType: (blockId: string, positionType: "relative" | "absolute" | "fixed") => void; updateBlockPositionType: (blockId: string, positionType: "relative" | "absolute" | "fixed") => void;
updateBlockZIndex: (blockId: string, zIndex: number) => void; updateBlockZIndex: (blockId: string, zIndex: number) => void;
handleRemoveBlock: (blockId: string) => void;
} }
const BlockEditor: React.FC<BlockEditorProps> = ({ const BlockEditor: React.FC<BlockEditorProps> = ({
@@ -29,12 +30,18 @@ const BlockEditor: React.FC<BlockEditorProps> = ({
updateBlockPosition, updateBlockPosition,
updateBlockPositionType, updateBlockPositionType,
updateBlockZIndex, updateBlockZIndex,
handleRemoveBlock,
}) => { }) => {
return ( return (
<div ref={blockEditorRef} className="panel block-editor-panel"> <div ref={blockEditorRef} className="panel block-editor-panel">
<div className="header"> <div className="header">
<h4>Block Style</h4> <h4>Block Style</h4>
<div className="delete icon"> <div
className="delete icon"
onClick={() => {
handleRemoveBlock(selectedBlock);
}}
>
<DeleteIcon /> <DeleteIcon />
</div> </div>
</div> </div>

View File

@@ -18,6 +18,7 @@ interface ElementEditorProps {
updateGraphData: (blockId: string, elementId: string, newData: GraphDataPoint[]) => void; updateGraphData: (blockId: string, elementId: string, newData: GraphDataPoint[]) => void;
updateGraphTitle: (blockId: string, elementId: string, title: string) => void; updateGraphTitle: (blockId: string, elementId: string, title: string) => void;
updateGraphType: (blockId: string, elementId: string, type: GraphTypes) => void; updateGraphType: (blockId: string, elementId: string, type: GraphTypes) => void;
handleRemoveElement: (blockId: string, elementId: string) => void;
setSwapSource: (source: string | null) => void; setSwapSource: (source: string | null) => void;
setShowSwapUI: (show: boolean) => void; setShowSwapUI: (show: boolean) => void;
dataModelManager: DataModelManager; dataModelManager: DataModelManager;
@@ -37,6 +38,7 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
updateGraphData, updateGraphData,
updateGraphTitle, updateGraphTitle,
updateGraphType, updateGraphType,
handleRemoveElement,
setSwapSource, setSwapSource,
setShowSwapUI, setShowSwapUI,
dataModelManager, dataModelManager,
@@ -52,10 +54,16 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
return ( return (
<div ref={elementEditorRef} className="panel element-editor-panel"> <div ref={elementEditorRef} className="panel element-editor-panel">
<div className="header"> <div className="header">
<h4>Element Style</h4> <h4>Element Style</h4>
<div className="delete icon"><DeleteIcon /></div> <div
className="delete icon"
onClick={() => {
handleRemoveElement(selectedBlock, selectedElement);
}}
>
<DeleteIcon />
</div>
</div> </div>
{currentElement.type === "label-value" && ( {currentElement.type === "label-value" && (
<> <>
@@ -352,11 +360,7 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
<> <>
<div className="form-group"> <div className="form-group">
<label className="form-label">Chart Type: </label> <label className="form-label">Chart Type: </label>
<select <select value={currentElement.graphType || "line"} onChange={(e) => updateGraphType(selectedBlock, selectedElement, e.target.value as GraphTypes)} className="form-select">
value={currentElement.graphType || "line"}
onChange={(e) => updateGraphType(selectedBlock, selectedElement, e.target.value as GraphTypes)}
className="form-select"
>
<option value="line">Line Chart</option> <option value="line">Line Chart</option>
<option value="bar">Bar Chart</option> <option value="bar">Bar Chart</option>
<option value="area">Area Chart</option> <option value="area">Area Chart</option>

View File

@@ -0,0 +1,30 @@
import { Block } from "../../../types/exportedTypes";
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
export const deleteDashBoardBlocksApi = async ({ projectId, versionId, blocks }: { projectId: string; versionId: string; blocks: Block[] }) => {
try {
const response = await fetch(`${url_Backend_dwinzo}/api/V1/simulation/blocks`, {
method: "PATCH",
headers: {
Authorization: "Bearer <access_token>",
"Content-Type": "application/json",
token: localStorage.getItem("token") || "",
refresh_token: localStorage.getItem("refreshToken") || "",
},
body: JSON.stringify({ projectId, versionId, blocks }),
});
const newAccessToken = response.headers.get("x-access-token");
if (newAccessToken) {
localStorage.setItem("token", newAccessToken);
}
if (!response.ok) {
echo.error("Failed to delete dashBoardBlocks");
}
return await response.json();
} catch {
echo.error("Failed to delete dashBoardBlocks");
}
};

View File

@@ -2,11 +2,7 @@ import { MathUtils } from "three";
import { create } from "zustand"; import { create } from "zustand";
import { immer } from "zustand/middleware/immer"; import { immer } from "zustand/middleware/immer";
import { defaultGraphData } from "../../components/SimulationDashboard/data/defaultGraphData"; import { defaultGraphData } from "../../components/SimulationDashboard/data/defaultGraphData";
import { import { Block, UIElement, ExtendedCSSProperties } from "../../types/exportedTypes";
Block,
UIElement,
ExtendedCSSProperties,
} from "../../types/exportedTypes";
interface SimulationDashboardStore { interface SimulationDashboardStore {
blocks: Block[]; blocks: Block[];
@@ -29,72 +25,33 @@ interface SimulationDashboardStore {
updateBlockStyle: (blockId: string, newStyle: React.CSSProperties) => void; updateBlockStyle: (blockId: string, newStyle: React.CSSProperties) => void;
updateBlockSize: (blockId: string, size: Size) => void; updateBlockSize: (blockId: string, size: Size) => void;
updateBlockPosition: (blockId: string, position: Position) => void; updateBlockPosition: (blockId: string, position: Position) => void;
updateBlockPositionType: ( updateBlockPositionType: (blockId: string, positionType: "relative" | "absolute" | "fixed") => void;
blockId: string,
positionType: "relative" | "absolute" | "fixed"
) => void;
updateBlockZIndex: (blockId: string, zIndex: number) => void; updateBlockZIndex: (blockId: string, zIndex: number) => void;
// Element operations // Element operations
addElement: (blockId: string, type: UIType, graphType?: GraphTypes) => void; addElement: (blockId: string, type: UIType, graphType?: GraphTypes) => void;
removeElement: (blockId: string, elementId: string) => void; removeElement: (blockId: string, elementId: string) => void;
updateElement: ( updateElement: (blockId: string, elementId: string, updates: Partial<UIElement>) => void;
blockId: string,
elementId: string,
updates: Partial<UIElement>
) => void;
// Element styling and positioning // Element styling and positioning
updateElementStyle: ( updateElementStyle: (blockId: string, elementId: string, newStyle: ExtendedCSSProperties) => void;
blockId: string,
elementId: string,
newStyle: ExtendedCSSProperties
) => void;
updateElementSize: (blockId: string, elementId: string, size: Size) => void; updateElementSize: (blockId: string, elementId: string, size: Size) => void;
updateElementPosition: ( updateElementPosition: (blockId: string, elementId: string, position: Position) => void;
blockId: string, updateElementPositionType: (blockId: string, elementId: string, positionType: "relative" | "absolute" | "fixed") => void;
elementId: string, updateElementZIndex: (blockId: string, elementId: string, zIndex: number) => void;
position: Position
) => void;
updateElementPositionType: (
blockId: string,
elementId: string,
positionType: "relative" | "absolute" | "fixed"
) => void;
updateElementZIndex: (
blockId: string,
elementId: string,
zIndex: number
) => void;
// Element data operations // Element data operations
updateElementData: ( updateElementData: (blockId: string, elementId: string, updates: Partial<DataBinding>) => void;
blockId: string, updateGraphData: (blockId: string, elementId: string, newData: GraphDataPoint[]) => void;
elementId: string,
updates: Partial<DataBinding>
) => void;
updateGraphData: (
blockId: string,
elementId: string,
newData: GraphDataPoint[]
) => void;
updateGraphTitle: (blockId: string, elementId: string, title: string) => void; updateGraphTitle: (blockId: string, elementId: string, title: string) => void;
updateGraphType: ( updateGraphType: (blockId: string, elementId: string, graphType: GraphTypes) => void;
blockId: string,
elementId: string,
graphType: GraphTypes
) => void;
// Selection and hover management // Selection and hover management
setSelectedBlock: (blockId: string | null) => void; setSelectedBlock: (blockId: string | null) => void;
setSelectedElement: (elementId: string | null) => void; setSelectedElement: (elementId: string | null) => void;
// Element swapping // Element swapping
swapElements: ( swapElements: (blockId: string, elementId1: string, elementId2: string) => void;
blockId: string,
elementId1: string,
elementId2: string
) => void;
// Helper functions // Helper functions
getBlockById: (blockId: string) => Block | undefined; getBlockById: (blockId: string) => Block | undefined;
@@ -162,9 +119,7 @@ export const createSimulationDashboardStore = () => {
removeBlock: (blockId) => { removeBlock: (blockId) => {
set((state) => { set((state) => {
state.blocks = state.blocks.filter( state.blocks = state.blocks.filter((block) => block.blockUuid !== blockId);
(block) => block.blockUuid !== blockId
);
if (state.selectedBlockId === blockId) { if (state.selectedBlockId === blockId) {
state.selectedBlockId = null; state.selectedBlockId = null;
} }
@@ -241,34 +196,35 @@ export const createSimulationDashboardStore = () => {
}, },
// Element operations // Element operations
addElement: (blockId, type, graphType) => { addElement: (blockId, type, graphType, dataType?: DataType) => {
set((state) => { set((state) => {
const block = state.blocks.find((b) => b.blockUuid === blockId); const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) { if (!block) return;
const newElement: UIElement = {
let newElement: UIElement;
const commonProps = {
elementUuid: MathUtils.generateUUID(), elementUuid: MathUtils.generateUUID(),
type: type, positionType: "relative" as const,
graphType, position: { x: 0, y: 0 },
graphTitle: graphType zIndex: 1,
? `${ data: {
graphType.charAt(0).toUpperCase() + graphType.slice(1) key: MathUtils.generateUUID(),
} Chart` dataSource: "static" as const,
: undefined, staticValue: "",
style: label: undefined,
type === "graph" },
? { };
width: "100%",
height: "100%", switch (type) {
minHeight: "120px", case "label-value":
color: "#ffffff", newElement = {
fontSize: 14, ...commonProps,
textAlign: "left" as const, type: "label-value",
backgroundColor: "rgba(0, 0, 0, 0.2)", title: "Label Value",
borderRadius: "4px", dataSource: "machine-1",
padding: "8px", dataValue: "metric-1",
} style: {
: type === "label-value"
? {
color: "#ffffff", color: "#ffffff",
fontSize: 14, fontSize: 14,
textAlign: "left" as const, textAlign: "left" as const,
@@ -279,34 +235,92 @@ export const createSimulationDashboardStore = () => {
justifyContent: "center", justifyContent: "center",
labelColor: "#ffffff", labelColor: "#ffffff",
valueColor: "#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 {
// Default to single-machine
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", color: "#ffffff",
fontSize: 14, fontSize: 14,
textAlign: "left" as const, textAlign: "left" as const,
}, },
positionType: "relative",
position: { x: 0, y: 0 },
zIndex: 1,
data: { data: {
key: MathUtils.generateUUID(), ...commonProps.data,
dataSource: "static", staticValue: "Text",
staticValue:
type === "label-value"
? "Value"
: type === "text"
? "Text"
: "",
label: type === "label-value" ? "Label" : undefined,
}, },
graphData: type === "graph" ? defaultGraphData : undefined, size: { width: 200, height: 40 },
size:
type === "graph"
? { width: 400, height: 200 }
: { width: 200, height: 60 },
}; };
block.elements.push(newElement); break;
case "icon":
newElement = {
...commonProps,
type: "icon",
style: {
color: "#ffffff",
fontSize: 14,
textAlign: "center" as const,
},
size: { width: 40, height: 40 },
};
break;
default:
return; // Should not happen
} }
block.elements.push(newElement);
}); });
}, },
@@ -314,9 +328,7 @@ export const createSimulationDashboardStore = () => {
set((state) => { set((state) => {
const block = state.blocks.find((b) => b.blockUuid === blockId); const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) { if (block) {
block.elements = block.elements.filter( block.elements = block.elements.filter((el) => el.elementUuid !== elementId);
(el) => el.elementUuid !== elementId
);
if (state.selectedElementId === elementId) { if (state.selectedElementId === elementId) {
state.selectedElementId = null; state.selectedElementId = null;
} }
@@ -328,9 +340,7 @@ export const createSimulationDashboardStore = () => {
set((state) => { set((state) => {
const block = state.blocks.find((b) => b.blockUuid === blockId); const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) { if (block) {
const element = block.elements.find( const element = block.elements.find((el) => el.elementUuid === elementId);
(el) => el.elementUuid === elementId
);
if (element) { if (element) {
Object.assign(element, updates); Object.assign(element, updates);
} }
@@ -343,9 +353,7 @@ export const createSimulationDashboardStore = () => {
set((state) => { set((state) => {
const block = state.blocks.find((b) => b.blockUuid === blockId); const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) { if (block) {
const element = block.elements.find( const element = block.elements.find((el) => el.elementUuid === elementId);
(el) => el.elementUuid === elementId
);
if (element) { if (element) {
element.style = { ...element.style, ...newStyle }; element.style = { ...element.style, ...newStyle };
} }
@@ -357,9 +365,7 @@ export const createSimulationDashboardStore = () => {
set((state) => { set((state) => {
const block = state.blocks.find((b) => b.blockUuid === blockId); const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) { if (block) {
const element = block.elements.find( const element = block.elements.find((el) => el.elementUuid === elementId);
(el) => el.elementUuid === elementId
);
if (element) { if (element) {
element.size = size; element.size = size;
} }
@@ -371,9 +377,7 @@ export const createSimulationDashboardStore = () => {
set((state) => { set((state) => {
const block = state.blocks.find((b) => b.blockUuid === blockId); const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) { if (block) {
const element = block.elements.find( const element = block.elements.find((el) => el.elementUuid === elementId);
(el) => el.elementUuid === elementId
);
if (element) { if (element) {
element.position = position; element.position = position;
} }
@@ -385,9 +389,7 @@ export const createSimulationDashboardStore = () => {
set((state) => { set((state) => {
const block = state.blocks.find((b) => b.blockUuid === blockId); const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) { if (block) {
const element = block.elements.find( const element = block.elements.find((el) => el.elementUuid === elementId);
(el) => el.elementUuid === elementId
);
if (element) { if (element) {
element.positionType = positionType; element.positionType = positionType;
} }
@@ -399,9 +401,7 @@ export const createSimulationDashboardStore = () => {
set((state) => { set((state) => {
const block = state.blocks.find((b) => b.blockUuid === blockId); const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) { if (block) {
const element = block.elements.find( const element = block.elements.find((el) => el.elementUuid === elementId);
(el) => el.elementUuid === elementId
);
if (element) { if (element) {
element.zIndex = zIndex; element.zIndex = zIndex;
} }
@@ -414,9 +414,7 @@ export const createSimulationDashboardStore = () => {
set((state) => { set((state) => {
const block = state.blocks.find((b) => b.blockUuid === blockId); const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) { if (block) {
const element = block.elements.find( const element = block.elements.find((el) => el.elementUuid === elementId);
(el) => el.elementUuid === elementId
);
if (element?.data) { if (element?.data) {
element.data = { ...element.data, ...updates }; element.data = { ...element.data, ...updates };
} }
@@ -428,9 +426,7 @@ export const createSimulationDashboardStore = () => {
set((state) => { set((state) => {
const block = state.blocks.find((b) => b.blockUuid === blockId); const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) { if (block) {
const element = block.elements.find( const element = block.elements.find((el) => el.elementUuid === elementId);
(el) => el.elementUuid === elementId
);
if (element) { if (element) {
element.graphData = newData; element.graphData = newData;
} }
@@ -442,9 +438,7 @@ export const createSimulationDashboardStore = () => {
set((state) => { set((state) => {
const block = state.blocks.find((b) => b.blockUuid === blockId); const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) { if (block) {
const element = block.elements.find( const element = block.elements.find((el) => el.elementUuid === elementId);
(el) => el.elementUuid === elementId
);
if (element) { if (element) {
element.graphTitle = title; element.graphTitle = title;
} }
@@ -456,14 +450,10 @@ export const createSimulationDashboardStore = () => {
set((state) => { set((state) => {
const block = state.blocks.find((b) => b.blockUuid === blockId); const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) { if (block) {
const element = block.elements.find( const element = block.elements.find((el) => el.elementUuid === elementId);
(el) => el.elementUuid === elementId
);
if (element && element.type === "graph") { if (element && element.type === "graph") {
element.graphType = graphType; element.graphType = graphType;
element.graphTitle = `${ element.graphTitle = `${graphType.charAt(0).toUpperCase() + graphType.slice(1)} Chart`;
graphType.charAt(0).toUpperCase() + graphType.slice(1)
} Chart`;
element.graphData = defaultGraphData; element.graphData = defaultGraphData;
} }
@@ -495,20 +485,12 @@ export const createSimulationDashboardStore = () => {
if (block) { if (block) {
block.elements = block.elements.map((el) => { block.elements = block.elements.map((el) => {
if (el.elementUuid === elementId1) { if (el.elementUuid === elementId1) {
const targetElement = block.elements.find( const targetElement = block.elements.find((e) => e.elementUuid === elementId2);
(e) => e.elementUuid === elementId2 return targetElement ? { ...targetElement, elementUuid: elementId1 } : el;
);
return targetElement
? { ...targetElement, elementUuid: elementId1 }
: el;
} }
if (el.elementUuid === elementId2) { if (el.elementUuid === elementId2) {
const sourceElement = block.elements.find( const sourceElement = block.elements.find((e) => e.elementUuid === elementId1);
(e) => e.elementUuid === elementId1 return sourceElement ? { ...sourceElement, elementUuid: elementId2 } : el;
);
return sourceElement
? { ...sourceElement, elementUuid: elementId2 }
: el;
} }
return el; return el;
}); });
@@ -528,9 +510,7 @@ export const createSimulationDashboardStore = () => {
getSelectedBlock: () => { getSelectedBlock: () => {
const { selectedBlockId, blocks } = get(); const { selectedBlockId, blocks } = get();
return selectedBlockId return selectedBlockId ? blocks.find((b) => b.blockUuid === selectedBlockId) : undefined;
? blocks.find((b) => b.blockUuid === selectedBlockId)
: undefined;
}, },
getSelectedElement: () => { getSelectedElement: () => {
@@ -538,9 +518,7 @@ export const createSimulationDashboardStore = () => {
if (!selectedElementId || !selectedBlockId) return undefined; if (!selectedElementId || !selectedBlockId) return undefined;
const block = blocks.find((b) => b.blockUuid === selectedBlockId); const block = blocks.find((b) => b.blockUuid === selectedBlockId);
return block?.elements.find( return block?.elements.find((el) => el.elementUuid === selectedElementId);
(el) => el.elementUuid === selectedElementId
);
}, },
hasBlock: (blockId) => { hasBlock: (blockId) => {
@@ -549,14 +527,10 @@ export const createSimulationDashboardStore = () => {
hasElement: (blockId, elementId) => { hasElement: (blockId, elementId) => {
const block = get().blocks.find((b) => b.blockUuid === blockId); const block = get().blocks.find((b) => b.blockUuid === blockId);
return ( return block?.elements.some((el) => el.elementUuid === elementId) || false;
block?.elements.some((el) => el.elementUuid === elementId) || false
);
}, },
})) }))
); );
}; };
export type SimulationDashboardStoreType = ReturnType< export type SimulationDashboardStoreType = ReturnType<typeof createSimulationDashboardStore>;
typeof createSimulationDashboardStore
>;

View File

@@ -27,4 +27,33 @@ export type UIElement = {
zIndex?: number; zIndex?: number;
graphData?: GraphDataPoint[]; graphData?: GraphDataPoint[];
size?: Size; size?: Size;
}; } & (
| {
type: "label-value";
title: string;
dataSource: string;
dataValue: string;
}
| {
type: "graph";
dataType: "single-machine";
title: string;
dataSource: string;
dataValue: string[];
}
| {
type: "graph";
dataType: "multiple-machine";
title: string;
dataSource: string[];
commonValue: string;
}
| {
type: Exclude<UIType, "label-value" | "graph">;
title?: never;
dataSource?: never;
dataValue?: never;
commonValue?: never;
dataType?: never;
}
);

View File

@@ -17,6 +17,8 @@ type DataModel = Record<string, DataModelValue>;
type UIType = "label-value" | "text" | "graph" | "icon"; type UIType = "label-value" | "text" | "graph" | "icon";
type DataType = "single-machine" | "multiple-machine";
type Position = { type Position = {
x: number; x: number;
y: number; y: number;