From 3746fccd199a1685daa95527a7039d69f1cdcf62 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Thu, 18 Dec 2025 11:35:49 +0530 Subject: [PATCH] feat: Implement the Simulation Dashboard editor with core components, state management, and types for blocks and elements. --- .../SimulationDashboard/AnalyzerManager.tsx | 22 +-- .../SimulationDashboard/DashboardEditor.tsx | 21 ++- .../components/block/BlockEditor.tsx | 75 ++-------- .../components/element/ElementDesign.tsx | 2 +- .../components/element/ElementEditor.tsx | 83 +++++++---- .../functions/helpers/resolveElementValue.ts | 49 +----- .../ui/inputs/InputWithDropDown.tsx | 19 +-- .../dashBoard/deleteDashBoardElements.ts | 28 ++++ .../simulation/useSimulationDashBoardStore.ts | 140 ++++++++---------- app/src/types/exportedTypes.ts | 33 +---- app/src/types/simulationDashboard.d.ts | 21 +-- 11 files changed, 202 insertions(+), 291 deletions(-) create mode 100644 app/src/services/visulization/dashBoard/deleteDashBoardElements.ts diff --git a/app/src/components/SimulationDashboard/AnalyzerManager.tsx b/app/src/components/SimulationDashboard/AnalyzerManager.tsx index 55e8a3b..ffcba26 100644 --- a/app/src/components/SimulationDashboard/AnalyzerManager.tsx +++ b/app/src/components/SimulationDashboard/AnalyzerManager.tsx @@ -29,16 +29,16 @@ const AnalyzerManager: React.FC = () => { block.elements.forEach((element) => { // 1. Handle Label-Value (Direct DOM Manipulation) if (element.type === "label-value") { - if (!element.dataSource || !element.dataValue) return; + if (!element.dataBinding?.dataSource || !element.dataBinding?.dataValue) return; let value: any = "-"; // Ensure dataValue is treated as string if possible, or take first if array - const mixedDataValue = element.dataValue; + const mixedDataValue = element.dataBinding.dataValue; const dataValueStr = Array.isArray(mixedDataValue) ? mixedDataValue[0] : mixedDataValue; if (typeof dataValueStr !== "string") return; - if (element.dataSource === "global") { + if (element.dataBinding.dataSource === "global") { // Handle global metrics // Expected format: "global.systemPerformance.overallOEE" -> we need last part relative to metrics // But dataValue usually comes as "systemPerformance.overallOEE" if dataSource is global? @@ -58,7 +58,7 @@ const AnalyzerManager: React.FC = () => { } else { // Handle Asset Specific - const assetAnalysis = getAssetAnalysis(element.dataSource); + const assetAnalysis = getAssetAnalysis(element.dataBinding.dataSource as string); if (assetAnalysis) { value = resolvePath(assetAnalysis, dataValueStr); } @@ -77,13 +77,13 @@ const AnalyzerManager: React.FC = () => { // Assuming we want to visualize historical data or current state trends. else if (element.type === "graph") { - if (element.dataType === "single-machine") { - if (!element.dataSource || !element.dataValue) return; + if (element.dataBinding?.dataType === "single-machine") { + if (!element.dataBinding.dataSource || !element.dataBinding.dataValue) return; // Single machine, multiple values potentially? // element.dataValue is string[] for single-machine graph - const assetId = element.dataSource as string; - const dataKeys = element.dataValue as string[]; // e.g. ["efficiency.overallEffectiveness"] + const assetId = element.dataBinding.dataSource as string; + const dataKeys = element.dataBinding.dataValue as string[]; // e.g. ["efficiency.overallEffectiveness"] // For now support getting the FIRST value as the main value to plot? // Or if we track history? @@ -138,10 +138,10 @@ const AnalyzerManager: React.FC = () => { } } - } else if (element.dataType === "multiple-machine") { + } else if (element.dataBinding?.dataType === "multiple-machine") { // Multiple machines, single common value - const assetIds = element.dataSource as string[]; - const commonValueKey = element.commonValue as string; + const assetIds = element.dataBinding.dataSource as string[]; + const commonValueKey = element.dataBinding.commonValue as string; if (assetIds && commonValueKey) { // Bar chart comparing machines? diff --git a/app/src/components/SimulationDashboard/DashboardEditor.tsx b/app/src/components/SimulationDashboard/DashboardEditor.tsx index d7ecbf9..3c24a57 100644 --- a/app/src/components/SimulationDashboard/DashboardEditor.tsx +++ b/app/src/components/SimulationDashboard/DashboardEditor.tsx @@ -21,6 +21,7 @@ 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(); @@ -622,10 +623,22 @@ const DashboardEditor: React.FC = () => { } }} handleRemoveElement={async (blockId, elementId) => { - const updatedBlocks = peekRemoveElement(blockId, elementId); - const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId); - if (updatedBlock) { - // await updateBackend(updatedBlock); + 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} diff --git a/app/src/components/SimulationDashboard/components/block/BlockEditor.tsx b/app/src/components/SimulationDashboard/components/block/BlockEditor.tsx index b837d61..5fa9586 100644 --- a/app/src/components/SimulationDashboard/components/block/BlockEditor.tsx +++ b/app/src/components/SimulationDashboard/components/block/BlockEditor.tsx @@ -37,10 +37,8 @@ const BlockEditor: React.FC = ({ updateBlockZIndex, handleRemoveBlock, }) => { - const [color, setColor] = useState("#000000"); - return (
@@ -55,20 +53,18 @@ const BlockEditor: React.FC = ({
- -
Size
{ updateBlockSize(selectedBlock, { ...currentBlock.size!, - width: Number(newValue), // Make sure to convert the string back to a number here - }) + width: Number(newValue), // Make sure to convert the string back to a number here + }); }} /> = ({ updateBlockSize(selectedBlock, { ...currentBlock.size!, height: Number(newValue), - }) + }); }} />
@@ -100,56 +96,22 @@ const BlockEditor: React.FC = ({
- - +
- - +
- - +
- - +
-
- updateBlockZIndex(selectedBlock, Number(newValue))} - /> + updateBlockZIndex(selectedBlock, Number(newValue))} /> = ({ onChange={(newValue) => { updateBlockStyle(selectedBlock, { borderRadius: Number(newValue), - }) + }); }} /> -
@@ -176,7 +137,6 @@ const BlockEditor: React.FC = ({ value={rgbaToHex(getCurrentBlockStyleValue(currentBlock, "backgroundColor"))} // onChange={(e) => setColor(e.target.value)} onChange={(e) => handleBackgroundColorChange(currentBlock, selectedBlock, updateBlockStyle, e.target.value)} - />
{color}
@@ -189,23 +149,10 @@ const BlockEditor: React.FC = ({ value={Math.round(getAlphaFromRgba(getCurrentBlockStyleValue(currentBlock, "backgroundColor")) * 100)} // onChange={(value: number) => handleBackgroundAlphaChange(currentBlock, selectedBlock, updateBlockStyle, Number(value))} onChange={(value: number) => handleBlurAmountChange(selectedBlock, updateBlockStyle, Number(value))} - /> - - + - - - - - ); }; diff --git a/app/src/components/SimulationDashboard/components/element/ElementDesign.tsx b/app/src/components/SimulationDashboard/components/element/ElementDesign.tsx index e29a164..cc267d0 100644 --- a/app/src/components/SimulationDashboard/components/element/ElementDesign.tsx +++ b/app/src/components/SimulationDashboard/components/element/ElementDesign.tsx @@ -19,7 +19,7 @@ interface ElementDesignProps { updateElementPosition: (blockId: string, elementId: string, position: { x: number; y: number }) => void; updateElementPositionType: (blockId: string, elementId: string, positionType: "relative" | "absolute" | "fixed") => void; updateElementZIndex: (blockId: string, elementId: string, zIndex: number) => void; - updateElementData: (blockId: string, elementId: string, updates: Partial) => void; + updateElementData: (blockId: string, elementId: string, updates: Partial) => void; updateGraphData: (blockId: string, elementId: string, newData: GraphDataPoint[]) => void; updateGraphTitle: (blockId: string, elementId: string, title: string) => void; updateGraphType: (blockId: string, elementId: string, type: GraphTypes) => void; diff --git a/app/src/components/SimulationDashboard/components/element/ElementEditor.tsx b/app/src/components/SimulationDashboard/components/element/ElementEditor.tsx index f11c141..b7fe86e 100644 --- a/app/src/components/SimulationDashboard/components/element/ElementEditor.tsx +++ b/app/src/components/SimulationDashboard/components/element/ElementEditor.tsx @@ -20,7 +20,7 @@ interface ElementEditorProps { updateElementPosition: (blockId: string, elementId: string, position: { x: number; y: number }) => void; updateElementPositionType: (blockId: string, elementId: string, positionType: "relative" | "absolute" | "fixed") => void; updateElementZIndex: (blockId: string, elementId: string, zIndex: number) => void; - updateElementData: (blockId: string, elementId: string, updates: Partial) => void; + updateElementData: (blockId: string, elementId: string, updates: Partial) => void; updateGraphData: (blockId: string, elementId: string, newData: GraphDataPoint[]) => void; updateGraphTitle: (blockId: string, elementId: string, title: string) => void; updateGraphType: (blockId: string, elementId: string, type: GraphTypes) => void; @@ -62,7 +62,7 @@ const ElementEditor: React.FC = ({ const { getElementById } = simulationDashBoardStore(); const element = getElementById(selectedBlock, selectedElement); const [selectType, setSelectType] = useState("design"); - const [selectDataMapping, setSelectDataMapping] = useState(element?.type === "graph" && element.dataType === "multiple-machine" ? "multipleMachine" : "singleMachine"); + const [selectDataMapping, setSelectDataMapping] = useState(element?.type === "graph" && element.dataBinding?.dataType === "multiple-machine" ? "multipleMachine" : "singleMachine"); const getAssetDropdownItems = useCallback(() => { if (!product?.eventDatas) return []; @@ -273,10 +273,12 @@ const ElementEditor: React.FC = ({ ); const singleValueFields = useMemo(() => { - if (element?.type === "graph" && element.dataType === "single-machine") { - const dataValues = Array.isArray(element.dataValue) ? element.dataValue : []; + if (element?.type === "graph" && element.dataBinding?.dataType === "single-machine") { + const dataValues = Array.isArray(element.dataBinding.dataValue) ? element.dataBinding.dataValue : []; - const valueOptions = element.dataSource ? getLableValueDropdownItems(element.dataSource).flatMap((section) => section.items.map((item) => ({ id: item.id, label: item.label }))) : []; + const valueOptions = element.dataBinding.dataSource + ? getLableValueDropdownItems(element.dataBinding.dataSource as string).flatMap((section) => section.items.map((item) => ({ id: item.id, label: item.label }))) + : []; return dataValues.map((value, index) => ({ id: `data-value-${index}`, @@ -297,8 +299,8 @@ const ElementEditor: React.FC = ({ }, [element, getLableValueDropdownItems]); const multipleSourceFields = useMemo(() => { - if (element?.type === "graph" && element.dataType === "multiple-machine") { - const dataSources = Array.isArray(element.dataSource) ? element.dataSource : []; + if (element?.type === "graph" && element.dataBinding?.dataType === "multiple-machine") { + const dataSources = Array.isArray(element.dataBinding.dataSource) ? element.dataBinding.dataSource : []; return dataSources.map((_, index) => ({ id: `data-source-${index}`, @@ -324,21 +326,21 @@ const ElementEditor: React.FC = ({ setSelectDataMapping(newDataType); - if (newDataType === "singleMachine" && element.dataType === "multiple-machine") { + if (newDataType === "singleMachine" && element.dataBinding?.dataType === "multiple-machine") { updateDataType(selectedBlock, selectedElement, "single-machine"); - } else if (newDataType === "multipleMachine" && element.dataType === "single-machine") { + } else if (newDataType === "multipleMachine" && element.dataBinding?.dataType === "single-machine") { updateDataType(selectedBlock, selectedElement, "multiple-machine"); } }; const addField = () => { - if (selectDataMapping === "singleMachine" && element?.type === "graph" && element.dataType === "single-machine") { - const currentDataValue = Array.isArray(element.dataValue) ? element.dataValue : []; + if (selectDataMapping === "singleMachine" && element?.type === "graph" && element.dataBinding?.dataType === "single-machine") { + const currentDataValue = Array.isArray(element.dataBinding.dataValue) ? element.dataBinding.dataValue : []; const newDataValue = [...currentDataValue, ""]; updateDataValue(selectedBlock, selectedElement, newDataValue); - } else if (selectDataMapping === "multipleMachine" && element?.type === "graph" && element.dataType === "multiple-machine") { - const currentDataSource = Array.isArray(element.dataSource) ? element.dataSource : []; + } else if (selectDataMapping === "multipleMachine" && element?.type === "graph" && element.dataBinding?.dataType === "multiple-machine") { + const currentDataSource = Array.isArray(element.dataBinding.dataSource) ? element.dataBinding.dataSource : []; const newDataSource = [...currentDataSource, ""]; updateDataSource(selectedBlock, selectedElement, newDataSource); @@ -399,7 +401,15 @@ const ElementEditor: React.FC = ({
{element?.type === "label-value" && (
- {}} /> + { + updateElementData(selectedBlock, selectedElement, { label: value }); + }} + />
= ({ }, ]} value={ - element.dataSource - ? { id: element.dataSource, label: getEventByModelUuid(selectedProduct.productUuid, element.dataSource)?.modelName ?? "", icon: } + element.dataBinding?.dataSource + ? { + id: element.dataBinding.dataSource as string, + label: + getEventByModelUuid(selectedProduct.productUuid, element.dataBinding.dataSource as string)?.modelName ?? + (element.dataBinding.dataSource === "global" ? "Global" : ""), + icon: , + } : null } onChange={(value) => { - updateDataSource(selectedBlock, selectedElement, value.id); + updateElementData(selectedBlock, selectedElement, { dataSource: value.id }); }} dropDownHeader={"RT-Data"} eyedroper={true} @@ -431,10 +447,21 @@ const ElementEditor: React.FC = ({ } : null} + sections={getLableValueDropdownItems(element.dataBinding?.dataSource as string | undefined)} + value={ + element.dataBinding?.dataValue + ? { + id: element.dataBinding.dataValue as string, + label: + getLableValueDropdownItems(element.dataBinding?.dataSource as string | undefined) + .flatMap((section) => section.items) + .find((item) => item.id === element.dataBinding?.dataValue)?.label ?? "", + icon: , + } + : null + } onChange={(value) => { - updateDataValue(selectedBlock, selectedElement, value.id); + updateElementData(selectedBlock, selectedElement, { dataValue: value.id, label: value.label }); }} dropDownHeader={"RT-Data-Value"} /> @@ -456,14 +483,14 @@ const ElementEditor: React.FC = ({
- {selectDataMapping === "singleMachine" && element.dataType === "single-machine" && ( + {selectDataMapping === "singleMachine" && element.dataBinding?.dataType === "single-machine" && (
{singleSourceFields.map((field) => ( { updateDataSource(selectedBlock, selectedElement, value.id); }} @@ -476,9 +503,9 @@ const ElementEditor: React.FC = ({ key={field.id} label={field.label} options={field.options} - selected={field.options.find((option) => option.id === element.dataValue?.[index])?.label ?? ""} + selected={field.options.find((option) => option.id === element.dataBinding?.dataValue?.[index])?.label ?? ""} onSelect={(value) => { - const currentDataValue = Array.isArray(element.dataValue) ? element.dataValue : []; + const currentDataValue = Array.isArray(element.dataBinding?.dataValue) ? element.dataBinding!.dataValue : []; const newDataValue = [...currentDataValue]; newDataValue[index] = value.id; @@ -498,14 +525,14 @@ const ElementEditor: React.FC = ({
)} - {selectDataMapping === "multipleMachine" && element.dataType === "multiple-machine" && ( + {selectDataMapping === "multipleMachine" && element.dataBinding?.dataType === "multiple-machine" && (
{multipleValueFields.map((field) => ( o.id === element.commonValue)?.label ?? ""} + selected={field.options.find((o) => o.id === element.dataBinding?.commonValue)?.label ?? ""} onSelect={(value) => { updateCommonValue(selectedBlock, selectedElement, value.id); }} @@ -518,9 +545,9 @@ const ElementEditor: React.FC = ({ key={field.id} label={field.label} options={field.options} - selected={getEventByModelUuid(selectedProduct.productUuid, element.dataSource?.[index])?.modelName ?? ""} + selected={getEventByModelUuid(selectedProduct.productUuid, (element.dataBinding?.dataSource as string[])?.[index] || "")?.modelName ?? ""} onSelect={(value) => { - const current = Array.isArray(element.dataSource) ? element.dataSource : []; + const current = Array.isArray(element.dataBinding?.dataSource) ? element.dataBinding!.dataSource : []; const next = [...current]; next[index] = value.id; diff --git a/app/src/components/SimulationDashboard/functions/helpers/resolveElementValue.ts b/app/src/components/SimulationDashboard/functions/helpers/resolveElementValue.ts index f82a7da..754b05c 100644 --- a/app/src/components/SimulationDashboard/functions/helpers/resolveElementValue.ts +++ b/app/src/components/SimulationDashboard/functions/helpers/resolveElementValue.ts @@ -1,57 +1,12 @@ -import { dataModelManager } from "../../data/dataModel"; import type { UIElement } from "../../../../types/exportedTypes"; export const resolveElementValue = (element: UIElement) => { - // Implementation from original code - if (!element.data) { + if (!element.dataBinding) { return { value: "No data" }; } - const binding = element.data; - - switch (binding.dataSource) { - case "static": - return { - label: binding.label, - value: binding.staticValue, - graphData: element.graphData, - }; - - case "dynamic": - if (binding.dynamicKey) { - const dynamicValue = dataModelManager.getValue(binding.dynamicKey); - if (dynamicValue !== undefined) { - return { - label: binding.label, - value: dynamicValue as string, - graphData: dataModelManager.parseGraphData(dynamicValue), - }; - } - } - break; - - case "formula": - if (binding.formula) { - const formulaValue = dataModelManager.evaluateFormula(binding.formula); - return { - label: binding.label, - value: formulaValue, - graphData: element.graphData, - }; - } - break; - - case "api": - return { - label: binding.label, - value: binding.staticValue || "API Data", - graphData: element.graphData, - }; - } - return { - label: binding.label, - value: binding.staticValue, + label: element.dataBinding.label, graphData: element.graphData, }; }; diff --git a/app/src/components/ui/inputs/InputWithDropDown.tsx b/app/src/components/ui/inputs/InputWithDropDown.tsx index cc2ccd5..77a7cc3 100644 --- a/app/src/components/ui/inputs/InputWithDropDown.tsx +++ b/app/src/components/ui/inputs/InputWithDropDown.tsx @@ -15,6 +15,7 @@ type InputWithDropDownProps = { onChange: (newValue: string) => void; editableLabel?: boolean; placeholder?: string; + type?: string; }; const InputWithDropDown: React.FC = ({ @@ -31,6 +32,7 @@ const InputWithDropDown: React.FC = ({ onChange, editableLabel = false, placeholder = "Inherit", + type = "number", }) => { const [openDropdown, setOpenDropdown] = useState(false); @@ -54,7 +56,7 @@ const InputWithDropDown: React.FC = ({ min={min} max={max} step={step} - type="number" + type={type} value={value} // Controlled input disabled={disabled} onChange={(e) => onChange(e.target.value)} @@ -62,19 +64,12 @@ const InputWithDropDown: React.FC = ({ /> {activeOption && ( -
setOpenDropdown((prev) => !prev)} - > +
setOpenDropdown((prev) => !prev)}>
{activeOption}
{options && openDropdown && (
{options.map((option, index) => ( -
+
{option}
))} @@ -88,7 +83,3 @@ const InputWithDropDown: React.FC = ({ }; export default InputWithDropDown; - - - - diff --git a/app/src/services/visulization/dashBoard/deleteDashBoardElements.ts b/app/src/services/visulization/dashBoard/deleteDashBoardElements.ts new file mode 100644 index 0000000..350d27b --- /dev/null +++ b/app/src/services/visulization/dashBoard/deleteDashBoardElements.ts @@ -0,0 +1,28 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const deleteDashBoardElementsApi = async ({ projectId, versionId, elementDatas }: { projectId: string; versionId: string; elementDatas: { blockUuid: string; elementUuid: string }[] }) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/V1/simulation/elements`, { + method: "PATCH", + headers: { + Authorization: "Bearer ", + "Content-Type": "application/json", + token: localStorage.getItem("token") || "", + refresh_token: localStorage.getItem("refreshToken") || "", + }, + body: JSON.stringify({ projectId, versionId, elementDatas }), + }); + const newAccessToken = response.headers.get("x-access-token"); + if (newAccessToken) { + localStorage.setItem("token", newAccessToken); + } + + if (!response.ok) { + echo.error("Failed to delete dashBoardElements"); + } + + return await response.json(); + } catch { + echo.error("Failed to delete dashBoardElements"); + } +}; diff --git a/app/src/store/simulation/useSimulationDashBoardStore.ts b/app/src/store/simulation/useSimulationDashBoardStore.ts index ad75a3b..adc8abd 100644 --- a/app/src/store/simulation/useSimulationDashBoardStore.ts +++ b/app/src/store/simulation/useSimulationDashBoardStore.ts @@ -45,7 +45,7 @@ interface SimulationDashboardStore { updateElementZIndex: (blockId: string, elementId: string, zIndex: number) => void; // Element data operations - updateElementData: (blockId: string, elementId: string, updates: Partial) => void; + updateElementData: (blockId: string, elementId: string, updates: Partial) => 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; @@ -70,7 +70,7 @@ interface SimulationDashboardStore { 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) => Block[]; + peekUpdateElementData: (blockId: string, elementId: string, updates: Partial) => 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[]; @@ -244,6 +244,7 @@ export const createSimulationDashboardStore = () => { staticValue: "", label: undefined, }, + dataBinding: {}, }; switch (type) { @@ -251,9 +252,6 @@ export const createSimulationDashboardStore = () => { newElement = { ...commonProps, type: "label-value", - title: "Label Value", - dataSource: "", - dataValue: "", style: { color: "#ffffff", fontSize: 14, @@ -266,10 +264,11 @@ export const createSimulationDashboardStore = () => { labelColor: "#ffffff", valueColor: "#ffffff", }, - data: { - ...commonProps.data, - staticValue: "Value", - label: "Label", + dataBinding: { + label: "Label Value", + dataSource: "", + dataValue: "", + dataType: "single-machine", }, size: { width: 200, height: 60 }, }; @@ -299,18 +298,22 @@ export const createSimulationDashboardStore = () => { if (dataType === "multiple-machine") { newElement = { ...baseGraphProps, - dataType: "multiple-machine" as const, - title: "Multi Machine Chart", - dataSource: [], - commonValue: "", + dataBinding: { + dataType: "multiple-machine" as const, + label: "Multi Machine Chart", + dataSource: [], + commonValue: "", + }, }; } else { newElement = { ...baseGraphProps, - dataType: "single-machine" as const, - title: "Single Machine Chart", - dataSource: "", - dataValue: [], + dataBinding: { + dataType: "single-machine" as const, + label: "Single Machine Chart", + dataSource: "", + dataValue: [], + }, }; } break; @@ -324,10 +327,6 @@ export const createSimulationDashboardStore = () => { fontSize: 14, textAlign: "left" as const, }, - data: { - ...commonProps.data, - staticValue: "Text", - }, size: { width: 200, height: 40 }, }; break; @@ -444,8 +443,8 @@ export const createSimulationDashboardStore = () => { 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 }; + if (element?.dataBinding) { + element.dataBinding = { ...element.dataBinding, ...updates }; } } }); @@ -618,9 +617,6 @@ export const createSimulationDashboardStore = () => { newElement = { ...commonProps, type: "label-value", - title: "Label Value", - dataSource: "", - dataValue: "metric-1", style: { color: "#ffffff", fontSize: 14, @@ -633,10 +629,10 @@ export const createSimulationDashboardStore = () => { labelColor: "#ffffff", valueColor: "#ffffff", }, - data: { - ...commonProps.data, - staticValue: "Value", - label: "Label", + dataBinding: { + label: "Label Value", + dataSource: "", + dataValue: "", }, size: { width: 200, height: 60 }, }; @@ -666,18 +662,22 @@ export const createSimulationDashboardStore = () => { if (dataType === "multiple-machine") { newElement = { ...baseGraphProps, - dataType: "multiple-machine" as const, - title: "Multi Machine Chart", - dataSource: [], - commonValue: "", + dataBinding: { + dataType: "multiple-machine" as const, + label: "Multi Machine Chart", + dataSource: [], + commonValue: "", + }, }; } else { newElement = { ...baseGraphProps, - dataType: "single-machine" as const, - title: "Single Machine Chart", - dataSource: "", - dataValue: [], + dataBinding: { + dataType: "single-machine" as const, + label: "Single Machine Chart", + dataSource: "", + dataValue: [], + }, }; } break; @@ -691,10 +691,6 @@ export const createSimulationDashboardStore = () => { fontSize: 14, textAlign: "left" as const, }, - data: { - ...commonProps.data, - staticValue: "Text", - }, size: { width: 200, height: 40 }, }; break; @@ -806,8 +802,8 @@ export const createSimulationDashboardStore = () => { 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 }; + if (element?.dataBinding) { + element.dataBinding = { ...element.dataBinding, ...updates }; } } return blocks; @@ -851,7 +847,7 @@ export const createSimulationDashboardStore = () => { return blocks; }, - peekUpdateDataType: (blockId, elementId, dataType) => { + peekUpdateDataType: (blockId: string, elementId: string, dataType: DataType) => { const blocks = cloneBlocks(get().blocks); const block = blocks.find((b) => b.blockUuid === blockId); @@ -861,70 +857,58 @@ export const createSimulationDashboardStore = () => { if (index === -1) return blocks; const element = block.elements[index]; - if (element.type !== "graph" || element.dataType === dataType) return blocks; - - let newElement: UIElement; + if (element.type !== "graph" || !element.dataBinding || element.dataBinding.dataType === dataType) return blocks; + // We are updating the dataBinding object deeply if (dataType === "single-machine") { - const { commonValue, ...rest } = element as Extract; - - newElement = { - ...rest, - dataType: "single-machine", - dataSource: "", - dataValue: [], - }; + element.dataBinding.dataType = "single-machine"; + element.dataBinding.dataSource = ""; + element.dataBinding.dataValue = []; + delete element.dataBinding.commonValue; } else { - const { dataValue, ...rest } = element as Extract; - - newElement = { - ...rest, - dataType: "multiple-machine", - dataSource: [], - commonValue: "", - }; + element.dataBinding.dataType = "multiple-machine"; + element.dataBinding.dataSource = []; + element.dataBinding.commonValue = ""; + delete element.dataBinding.dataValue; } - block.elements[index] = newElement; return blocks; }, - peekUpdateCommonValue: (blockId, elementId, commonValue) => { + peekUpdateCommonValue: (blockId: string, elementId: string, commonValue: string) => { 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.dataType === "multiple-machine") { - element.commonValue = commonValue; + if (element && element.dataBinding) { + element.dataBinding.commonValue = commonValue; } } return blocks; }, - peekUpdateDataValue: (blockId, elementId, dataValue) => { + peekUpdateDataValue: (blockId: string, elementId: string, dataValue: string | string[]) => { 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.dataType === "single-machine") { - element.dataValue = dataValue as string[]; - } else if (element && element.type === "label-value") { - element.dataValue = dataValue as string; + if (element && element.dataBinding) { + element.dataBinding.dataValue = dataValue; } } return blocks; }, - peekUpdateDataSource: (blockId, elementId, dataSource) => { + peekUpdateDataSource: (blockId: string, elementId: string, dataSource: string | string[]) => { 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?.type === "label-value") { - element.dataValue = ""; + if (element?.type === "label-value" && element.dataBinding) { + element.dataBinding.dataValue = ""; } - if (element) { - element.dataSource = dataSource; + if (element && element.dataBinding) { + element.dataBinding.dataSource = dataSource; } } return blocks; diff --git a/app/src/types/exportedTypes.ts b/app/src/types/exportedTypes.ts index 0e39175..f108d79 100644 --- a/app/src/types/exportedTypes.ts +++ b/app/src/types/exportedTypes.ts @@ -21,39 +21,10 @@ export type UIElement = { graphType?: GraphTypes; graphTitle?: string; style: ExtendedCSSProperties; - data?: DataBinding; + dataBinding?: ElementDataBinding; position?: Position; positionType?: "relative" | "absolute" | "fixed"; zIndex?: number; graphData?: GraphDataPoint[]; 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; - title?: never; - dataSource?: never; - dataValue?: never; - commonValue?: never; - dataType?: never; - } -); +}; diff --git a/app/src/types/simulationDashboard.d.ts b/app/src/types/simulationDashboard.d.ts index 09b14ef..4cf1b4a 100644 --- a/app/src/types/simulationDashboard.d.ts +++ b/app/src/types/simulationDashboard.d.ts @@ -1,16 +1,3 @@ -type DataSourceType = "static" | "dynamic" | "api" | "formula"; - -type DataBinding = { - key: string; - label?: string; - value?: string | number; - dataSource: DataSourceType; - staticValue?: string | number; - dynamicKey?: string; - formula?: string; - apiEndpoint?: string; -}; - type DataModelValue = string | number | GraphDataPoint[]; type DataModel = Record; @@ -19,6 +6,14 @@ type UIType = "label-value" | "text" | "graph" | "icon"; type DataType = "single-machine" | "multiple-machine"; +type ElementDataBinding = { + label?: string; + dataSource?: string | string[]; + dataValue?: string | string[]; + commonValue?: string; + dataType?: "single-machine" | "multiple-machine"; +} + type Position = { x: number; y: number;