2025-10-16 11:38:51 +05:30
|
|
|
import { MathUtils } from "three";
|
|
|
|
|
import { create } from "zustand";
|
|
|
|
|
import { immer } from "zustand/middleware/immer";
|
2025-10-16 14:40:09 +05:30
|
|
|
import { defaultGraphData } from "../../components/SimulationDashboard/data/defaultGraphData";
|
2025-10-17 15:31:46 +05:30
|
|
|
import {
|
|
|
|
|
Block,
|
|
|
|
|
UIElement,
|
|
|
|
|
ExtendedCSSProperties,
|
|
|
|
|
} from "../../types/exportedTypes";
|
2025-10-16 11:38:51 +05:30
|
|
|
|
|
|
|
|
interface SimulationDashboardStore {
|
2025-10-17 15:31:46 +05:30
|
|
|
blocks: Block[];
|
|
|
|
|
selectedBlockId: string | null;
|
|
|
|
|
selectedElementId: string | null;
|
|
|
|
|
|
|
|
|
|
// Subscription management
|
|
|
|
|
subscribe: (callback: () => void) => () => void;
|
|
|
|
|
_notifySubscribers: () => void;
|
|
|
|
|
saveBlocks: () => void;
|
|
|
|
|
|
|
|
|
|
// Block operations
|
|
|
|
|
addBlock: () => void;
|
|
|
|
|
removeBlock: (blockId: string) => void;
|
|
|
|
|
updateBlock: (blockId: string, updates: Partial<Block>) => void;
|
|
|
|
|
clearBlocks: () => void;
|
|
|
|
|
setBlocks: (blocks: Block[]) => void;
|
|
|
|
|
|
|
|
|
|
// Block styling and positioning
|
|
|
|
|
updateBlockStyle: (blockId: string, newStyle: React.CSSProperties) => void;
|
|
|
|
|
updateBlockSize: (blockId: string, size: Size) => void;
|
|
|
|
|
updateBlockPosition: (blockId: string, position: Position) => void;
|
|
|
|
|
updateBlockPositionType: (
|
|
|
|
|
blockId: string,
|
|
|
|
|
positionType: "relative" | "absolute" | "fixed"
|
|
|
|
|
) => void;
|
|
|
|
|
updateBlockZIndex: (blockId: string, zIndex: number) => void;
|
|
|
|
|
|
|
|
|
|
// Element operations
|
|
|
|
|
addElement: (blockId: string, type: UIType, graphType?: GraphTypes) => void;
|
|
|
|
|
removeElement: (blockId: string, elementId: string) => void;
|
|
|
|
|
updateElement: (
|
|
|
|
|
blockId: string,
|
|
|
|
|
elementId: string,
|
|
|
|
|
updates: Partial<UIElement>
|
|
|
|
|
) => void;
|
|
|
|
|
|
|
|
|
|
// Element styling and positioning
|
|
|
|
|
updateElementStyle: (
|
|
|
|
|
blockId: string,
|
|
|
|
|
elementId: string,
|
|
|
|
|
newStyle: ExtendedCSSProperties
|
|
|
|
|
) => void;
|
|
|
|
|
updateElementSize: (blockId: string, elementId: string, size: Size) => void;
|
|
|
|
|
updateElementPosition: (
|
|
|
|
|
blockId: string,
|
|
|
|
|
elementId: string,
|
|
|
|
|
position: Position
|
|
|
|
|
) => void;
|
|
|
|
|
updateElementPositionType: (
|
|
|
|
|
blockId: string,
|
|
|
|
|
elementId: string,
|
|
|
|
|
positionType: "relative" | "absolute" | "fixed"
|
|
|
|
|
) => void;
|
|
|
|
|
updateElementZIndex: (
|
|
|
|
|
blockId: string,
|
|
|
|
|
elementId: string,
|
|
|
|
|
zIndex: number
|
|
|
|
|
) => void;
|
|
|
|
|
|
|
|
|
|
// Element data operations
|
|
|
|
|
updateElementData: (
|
|
|
|
|
blockId: string,
|
|
|
|
|
elementId: string,
|
|
|
|
|
updates: Partial<DataBinding>
|
|
|
|
|
) => void;
|
|
|
|
|
updateGraphData: (
|
|
|
|
|
blockId: string,
|
|
|
|
|
elementId: string,
|
|
|
|
|
newData: GraphDataPoint[]
|
|
|
|
|
) => void;
|
|
|
|
|
updateGraphTitle: (blockId: string, elementId: string, title: string) => void;
|
|
|
|
|
updateGraphType: (
|
|
|
|
|
blockId: string,
|
|
|
|
|
elementId: string,
|
|
|
|
|
graphType: GraphTypes
|
|
|
|
|
) => void;
|
|
|
|
|
|
|
|
|
|
// Selection and hover management
|
|
|
|
|
setSelectedBlock: (blockId: string | null) => void;
|
|
|
|
|
setSelectedElement: (elementId: string | null) => void;
|
|
|
|
|
|
|
|
|
|
// Element swapping
|
|
|
|
|
swapElements: (
|
|
|
|
|
blockId: string,
|
|
|
|
|
elementId1: string,
|
|
|
|
|
elementId2: string
|
|
|
|
|
) => void;
|
|
|
|
|
|
|
|
|
|
// Helper functions
|
|
|
|
|
getBlockById: (blockId: string) => Block | undefined;
|
|
|
|
|
getElementById: (blockId: string, elementId: string) => UIElement | undefined;
|
|
|
|
|
getSelectedBlock: () => Block | undefined;
|
|
|
|
|
getSelectedElement: () => UIElement | undefined;
|
|
|
|
|
hasBlock: (blockId: string) => boolean;
|
|
|
|
|
hasElement: (blockId: string, elementId: string) => boolean;
|
2025-10-16 11:38:51 +05:30
|
|
|
}
|
|
|
|
|
|
2025-10-17 10:27:43 +05:30
|
|
|
const subscribers = new Set<() => void>();
|
|
|
|
|
|
2025-10-16 11:38:51 +05:30
|
|
|
export const createSimulationDashboardStore = () => {
|
2025-10-17 15:31:46 +05:30
|
|
|
return create<SimulationDashboardStore>()(
|
|
|
|
|
immer((set, get) => ({
|
|
|
|
|
blocks: [],
|
|
|
|
|
selectedBlockId: null,
|
|
|
|
|
selectedElementId: null,
|
|
|
|
|
|
|
|
|
|
subscribe: (callback: () => void) => {
|
|
|
|
|
subscribers.add(callback);
|
|
|
|
|
return () => {
|
|
|
|
|
subscribers.delete(callback);
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_notifySubscribers: () => {
|
|
|
|
|
subscribers.forEach((callback) => {
|
|
|
|
|
try {
|
|
|
|
|
callback();
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Error in store subscriber:", error);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
saveBlocks: () => {
|
|
|
|
|
get()._notifySubscribers();
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Block operations
|
|
|
|
|
addBlock: () => {
|
|
|
|
|
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);
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
removeBlock: (blockId) => {
|
|
|
|
|
set((state) => {
|
|
|
|
|
state.blocks = state.blocks.filter(
|
|
|
|
|
(block) => block.blockUuid !== blockId
|
|
|
|
|
);
|
|
|
|
|
if (state.selectedBlockId === blockId) {
|
|
|
|
|
state.selectedBlockId = null;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
updateBlock: (blockId, updates) => {
|
|
|
|
|
set((state) => {
|
|
|
|
|
const block = state.blocks.find((b) => b.blockUuid === blockId);
|
|
|
|
|
if (block) {
|
|
|
|
|
Object.assign(block, updates);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
clearBlocks: () => {
|
|
|
|
|
set((state) => {
|
|
|
|
|
state.blocks = [];
|
|
|
|
|
state.selectedBlockId = null;
|
|
|
|
|
state.selectedElementId = null;
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
setBlocks: (blocks) => {
|
|
|
|
|
set((state) => {
|
|
|
|
|
state.blocks = blocks;
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Block styling and positioning
|
|
|
|
|
updateBlockStyle: (blockId, newStyle) => {
|
|
|
|
|
set((state) => {
|
|
|
|
|
const block = state.blocks.find((b) => b.blockUuid === blockId);
|
|
|
|
|
if (block) {
|
|
|
|
|
block.style = { ...block.style, ...newStyle };
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
updateBlockSize: (blockId, size) => {
|
|
|
|
|
set((state) => {
|
|
|
|
|
const block = state.blocks.find((b) => b.blockUuid === blockId);
|
|
|
|
|
if (block) {
|
|
|
|
|
block.size = size;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
updateBlockPosition: (blockId, position) => {
|
|
|
|
|
set((state) => {
|
|
|
|
|
const block = state.blocks.find((b) => b.blockUuid === blockId);
|
|
|
|
|
if (block) {
|
|
|
|
|
block.position = position;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
updateBlockPositionType: (blockId, positionType) => {
|
|
|
|
|
set((state) => {
|
|
|
|
|
const block = state.blocks.find((b) => b.blockUuid === blockId);
|
|
|
|
|
if (block) {
|
|
|
|
|
block.positionType = positionType;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
updateBlockZIndex: (blockId, zIndex) => {
|
|
|
|
|
set((state) => {
|
|
|
|
|
const block = state.blocks.find((b) => b.blockUuid === blockId);
|
|
|
|
|
if (block) {
|
|
|
|
|
block.zIndex = zIndex;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Element operations
|
|
|
|
|
addElement: (blockId, type, graphType) => {
|
|
|
|
|
set((state) => {
|
|
|
|
|
const block = state.blocks.find((b) => b.blockUuid === blockId);
|
|
|
|
|
if (block) {
|
|
|
|
|
const newElement: UIElement = {
|
|
|
|
|
elementUuid: MathUtils.generateUUID(),
|
|
|
|
|
type: type,
|
|
|
|
|
graphType,
|
|
|
|
|
graphTitle: graphType
|
|
|
|
|
? `${
|
|
|
|
|
graphType.charAt(0).toUpperCase() + graphType.slice(1)
|
|
|
|
|
} Chart`
|
|
|
|
|
: undefined,
|
|
|
|
|
style:
|
|
|
|
|
type === "graph"
|
|
|
|
|
? {
|
|
|
|
|
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",
|
2025-10-17 10:27:43 +05:30
|
|
|
}
|
2025-10-17 15:31:46 +05:30
|
|
|
: type === "label-value"
|
|
|
|
|
? {
|
|
|
|
|
color: "#ffffff",
|
|
|
|
|
fontSize: 14,
|
|
|
|
|
textAlign: "left" as const,
|
|
|
|
|
display: "flex",
|
|
|
|
|
flexDirection: "column",
|
|
|
|
|
gap: "4px",
|
|
|
|
|
alignItems: "flex-start",
|
|
|
|
|
justifyContent: "center",
|
|
|
|
|
labelColor: "#ffffff",
|
|
|
|
|
valueColor: "#ffffff",
|
2025-10-16 11:38:51 +05:30
|
|
|
}
|
2025-10-17 15:31:46 +05:30
|
|
|
: {
|
|
|
|
|
color: "#ffffff",
|
|
|
|
|
fontSize: 14,
|
|
|
|
|
textAlign: "left" as const,
|
|
|
|
|
},
|
|
|
|
|
positionType: "relative",
|
|
|
|
|
position: { x: 0, y: 0 },
|
|
|
|
|
zIndex: 1,
|
|
|
|
|
data: {
|
|
|
|
|
key: MathUtils.generateUUID(),
|
|
|
|
|
dataSource: "static",
|
|
|
|
|
staticValue:
|
|
|
|
|
type === "label-value"
|
|
|
|
|
? "Value"
|
|
|
|
|
: type === "text"
|
|
|
|
|
? "Text"
|
|
|
|
|
: "",
|
|
|
|
|
label: type === "label-value" ? "Label" : undefined,
|
|
|
|
|
},
|
|
|
|
|
graphData: type === "graph" ? defaultGraphData : undefined,
|
|
|
|
|
size:
|
|
|
|
|
type === "graph"
|
|
|
|
|
? { width: 400, height: 200 }
|
|
|
|
|
: { width: 200, height: 60 },
|
|
|
|
|
};
|
|
|
|
|
block.elements.push(newElement);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
removeElement: (blockId, elementId) => {
|
|
|
|
|
set((state) => {
|
|
|
|
|
const block = state.blocks.find((b) => b.blockUuid === blockId);
|
|
|
|
|
if (block) {
|
|
|
|
|
block.elements = block.elements.filter(
|
|
|
|
|
(el) => el.elementUuid !== elementId
|
|
|
|
|
);
|
|
|
|
|
if (state.selectedElementId === elementId) {
|
|
|
|
|
state.selectedElementId = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
updateElement: (blockId, elementId, updates) => {
|
|
|
|
|
set((state) => {
|
|
|
|
|
const block = state.blocks.find((b) => b.blockUuid === blockId);
|
|
|
|
|
if (block) {
|
|
|
|
|
const element = block.elements.find(
|
|
|
|
|
(el) => el.elementUuid === elementId
|
|
|
|
|
);
|
|
|
|
|
if (element) {
|
|
|
|
|
Object.assign(element, updates);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Element styling and positioning
|
|
|
|
|
updateElementStyle: (blockId, elementId, newStyle) => {
|
|
|
|
|
set((state) => {
|
|
|
|
|
const block = state.blocks.find((b) => b.blockUuid === blockId);
|
|
|
|
|
if (block) {
|
|
|
|
|
const element = block.elements.find(
|
|
|
|
|
(el) => el.elementUuid === elementId
|
|
|
|
|
);
|
|
|
|
|
if (element) {
|
|
|
|
|
element.style = { ...element.style, ...newStyle };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
updateElementSize: (blockId, elementId, size) => {
|
|
|
|
|
set((state) => {
|
|
|
|
|
const block = state.blocks.find((b) => b.blockUuid === blockId);
|
|
|
|
|
if (block) {
|
|
|
|
|
const element = block.elements.find(
|
|
|
|
|
(el) => el.elementUuid === elementId
|
|
|
|
|
);
|
|
|
|
|
if (element) {
|
|
|
|
|
element.size = size;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
updateElementPosition: (blockId, elementId, position) => {
|
|
|
|
|
set((state) => {
|
|
|
|
|
const block = state.blocks.find((b) => b.blockUuid === blockId);
|
|
|
|
|
if (block) {
|
|
|
|
|
const element = block.elements.find(
|
|
|
|
|
(el) => el.elementUuid === elementId
|
|
|
|
|
);
|
|
|
|
|
if (element) {
|
|
|
|
|
element.position = position;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
updateElementPositionType: (blockId, elementId, positionType) => {
|
|
|
|
|
set((state) => {
|
|
|
|
|
const block = state.blocks.find((b) => b.blockUuid === blockId);
|
|
|
|
|
if (block) {
|
|
|
|
|
const element = block.elements.find(
|
|
|
|
|
(el) => el.elementUuid === elementId
|
|
|
|
|
);
|
|
|
|
|
if (element) {
|
|
|
|
|
element.positionType = positionType;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
updateElementZIndex: (blockId, elementId, zIndex) => {
|
|
|
|
|
set((state) => {
|
|
|
|
|
const block = state.blocks.find((b) => b.blockUuid === blockId);
|
|
|
|
|
if (block) {
|
|
|
|
|
const element = block.elements.find(
|
|
|
|
|
(el) => el.elementUuid === elementId
|
|
|
|
|
);
|
|
|
|
|
if (element) {
|
|
|
|
|
element.zIndex = zIndex;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Element data operations
|
|
|
|
|
updateElementData: (blockId, elementId, updates) => {
|
|
|
|
|
set((state) => {
|
|
|
|
|
const block = state.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 };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
updateGraphData: (blockId, elementId, newData) => {
|
|
|
|
|
set((state) => {
|
|
|
|
|
const block = state.blocks.find((b) => b.blockUuid === blockId);
|
|
|
|
|
if (block) {
|
|
|
|
|
const element = block.elements.find(
|
|
|
|
|
(el) => el.elementUuid === elementId
|
|
|
|
|
);
|
|
|
|
|
if (element) {
|
|
|
|
|
element.graphData = newData;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
updateGraphTitle: (blockId, elementId, title) => {
|
|
|
|
|
set((state) => {
|
|
|
|
|
const block = state.blocks.find((b) => b.blockUuid === blockId);
|
|
|
|
|
if (block) {
|
|
|
|
|
const element = block.elements.find(
|
|
|
|
|
(el) => el.elementUuid === elementId
|
|
|
|
|
);
|
|
|
|
|
if (element) {
|
|
|
|
|
element.graphTitle = title;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
updateGraphType: (blockId, elementId, graphType) => {
|
|
|
|
|
set((state) => {
|
|
|
|
|
const block = state.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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Selection and hover management
|
|
|
|
|
setSelectedBlock: (blockId) => {
|
|
|
|
|
set((state) => {
|
|
|
|
|
state.selectedBlockId = blockId;
|
|
|
|
|
// Clear element selection when selecting a block
|
|
|
|
|
if (blockId) {
|
|
|
|
|
state.selectedElementId = null;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
setSelectedElement: (elementId) => {
|
|
|
|
|
set((state) => {
|
|
|
|
|
state.selectedElementId = elementId;
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Element swapping
|
|
|
|
|
swapElements: (blockId, elementId1, elementId2) => {
|
|
|
|
|
set((state) => {
|
|
|
|
|
const block = state.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;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Helper functions
|
|
|
|
|
getBlockById: (blockId) => {
|
|
|
|
|
return get().blocks.find((b) => b.blockUuid === blockId);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
getElementById: (blockId, elementId) => {
|
|
|
|
|
const block = get().blocks.find((b) => b.blockUuid === blockId);
|
|
|
|
|
return block?.elements.find((el) => el.elementUuid === elementId);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
getSelectedBlock: () => {
|
|
|
|
|
const { selectedBlockId, blocks } = get();
|
|
|
|
|
return selectedBlockId
|
|
|
|
|
? blocks.find((b) => b.blockUuid === selectedBlockId)
|
|
|
|
|
: undefined;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
getSelectedElement: () => {
|
|
|
|
|
const { selectedElementId, selectedBlockId, blocks } = get();
|
|
|
|
|
if (!selectedElementId || !selectedBlockId) return undefined;
|
|
|
|
|
|
|
|
|
|
const block = blocks.find((b) => b.blockUuid === selectedBlockId);
|
|
|
|
|
return block?.elements.find(
|
|
|
|
|
(el) => el.elementUuid === selectedElementId
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
hasBlock: (blockId) => {
|
|
|
|
|
return get().blocks.some((b) => b.blockUuid === blockId);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
hasElement: (blockId, elementId) => {
|
|
|
|
|
const block = get().blocks.find((b) => b.blockUuid === blockId);
|
|
|
|
|
return (
|
|
|
|
|
block?.elements.some((el) => el.elementUuid === elementId) || false
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
}))
|
|
|
|
|
);
|
2025-10-16 11:38:51 +05:30
|
|
|
};
|
|
|
|
|
|
2025-10-17 15:31:46 +05:30
|
|
|
export type SimulationDashboardStoreType = ReturnType<
|
|
|
|
|
typeof createSimulationDashboardStore
|
|
|
|
|
>;
|