feat: Implement the Simulation Dashboard editor with core components, state management, and types for blocks and elements.
This commit is contained in:
@@ -29,16 +29,16 @@ const AnalyzerManager: React.FC = () => {
|
|||||||
block.elements.forEach((element) => {
|
block.elements.forEach((element) => {
|
||||||
// 1. Handle Label-Value (Direct DOM Manipulation)
|
// 1. Handle Label-Value (Direct DOM Manipulation)
|
||||||
if (element.type === "label-value") {
|
if (element.type === "label-value") {
|
||||||
if (!element.dataSource || !element.dataValue) return;
|
if (!element.dataBinding?.dataSource || !element.dataBinding?.dataValue) return;
|
||||||
|
|
||||||
let value: any = "-";
|
let value: any = "-";
|
||||||
// Ensure dataValue is treated as string if possible, or take first if array
|
// 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;
|
const dataValueStr = Array.isArray(mixedDataValue) ? mixedDataValue[0] : mixedDataValue;
|
||||||
|
|
||||||
if (typeof dataValueStr !== "string") return;
|
if (typeof dataValueStr !== "string") return;
|
||||||
|
|
||||||
if (element.dataSource === "global") {
|
if (element.dataBinding.dataSource === "global") {
|
||||||
// Handle global metrics
|
// Handle global metrics
|
||||||
// Expected format: "global.systemPerformance.overallOEE" -> we need last part relative to metrics
|
// Expected format: "global.systemPerformance.overallOEE" -> we need last part relative to metrics
|
||||||
// But dataValue usually comes as "systemPerformance.overallOEE" if dataSource is global?
|
// But dataValue usually comes as "systemPerformance.overallOEE" if dataSource is global?
|
||||||
@@ -58,7 +58,7 @@ const AnalyzerManager: React.FC = () => {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Handle Asset Specific
|
// Handle Asset Specific
|
||||||
const assetAnalysis = getAssetAnalysis(element.dataSource);
|
const assetAnalysis = getAssetAnalysis(element.dataBinding.dataSource as string);
|
||||||
if (assetAnalysis) {
|
if (assetAnalysis) {
|
||||||
value = resolvePath(assetAnalysis, dataValueStr);
|
value = resolvePath(assetAnalysis, dataValueStr);
|
||||||
}
|
}
|
||||||
@@ -77,13 +77,13 @@ const AnalyzerManager: React.FC = () => {
|
|||||||
// Assuming we want to visualize historical data or current state trends.
|
// Assuming we want to visualize historical data or current state trends.
|
||||||
else if (element.type === "graph") {
|
else if (element.type === "graph") {
|
||||||
|
|
||||||
if (element.dataType === "single-machine") {
|
if (element.dataBinding?.dataType === "single-machine") {
|
||||||
if (!element.dataSource || !element.dataValue) return;
|
if (!element.dataBinding.dataSource || !element.dataBinding.dataValue) return;
|
||||||
// Single machine, multiple values potentially?
|
// Single machine, multiple values potentially?
|
||||||
// element.dataValue is string[] for single-machine graph
|
// element.dataValue is string[] for single-machine graph
|
||||||
|
|
||||||
const assetId = element.dataSource as string;
|
const assetId = element.dataBinding.dataSource as string;
|
||||||
const dataKeys = element.dataValue as string[]; // e.g. ["efficiency.overallEffectiveness"]
|
const dataKeys = element.dataBinding.dataValue as string[]; // e.g. ["efficiency.overallEffectiveness"]
|
||||||
|
|
||||||
// For now support getting the FIRST value as the main value to plot?
|
// For now support getting the FIRST value as the main value to plot?
|
||||||
// Or if we track history?
|
// 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
|
// Multiple machines, single common value
|
||||||
const assetIds = element.dataSource as string[];
|
const assetIds = element.dataBinding.dataSource as string[];
|
||||||
const commonValueKey = element.commonValue as string;
|
const commonValueKey = element.dataBinding.commonValue as string;
|
||||||
|
|
||||||
if (assetIds && commonValueKey) {
|
if (assetIds && commonValueKey) {
|
||||||
// Bar chart comparing machines?
|
// Bar chart comparing machines?
|
||||||
|
|||||||
@@ -21,6 +21,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";
|
import { deleteDashBoardBlocksApi } from "../../services/visulization/dashBoard/deleteDashBoardBlocks";
|
||||||
|
import { deleteDashBoardElementsApi } from "../../services/visulization/dashBoard/deleteDashBoardElements";
|
||||||
|
|
||||||
const DashboardEditor: React.FC = () => {
|
const DashboardEditor: React.FC = () => {
|
||||||
const { simulationDashBoardStore, versionStore } = useSceneContext();
|
const { simulationDashBoardStore, versionStore } = useSceneContext();
|
||||||
@@ -622,10 +623,22 @@ const DashboardEditor: React.FC = () => {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
handleRemoveElement={async (blockId, elementId) => {
|
handleRemoveElement={async (blockId, elementId) => {
|
||||||
const updatedBlocks = peekRemoveElement(blockId, elementId);
|
try {
|
||||||
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
const data = await deleteDashBoardElementsApi({
|
||||||
if (updatedBlock) {
|
projectId: projectId!,
|
||||||
// await updateBackend(updatedBlock);
|
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}
|
setSwapSource={setSwapSource}
|
||||||
|
|||||||
@@ -37,10 +37,8 @@ const BlockEditor: React.FC<BlockEditorProps> = ({
|
|||||||
updateBlockZIndex,
|
updateBlockZIndex,
|
||||||
handleRemoveBlock,
|
handleRemoveBlock,
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
const [color, setColor] = useState("#000000");
|
const [color, setColor] = useState("#000000");
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={blockEditorRef} className="panel block-editor-panel">
|
<div ref={blockEditorRef} className="panel block-editor-panel">
|
||||||
<div className="header">
|
<div className="header">
|
||||||
@@ -55,8 +53,6 @@ const BlockEditor: React.FC<BlockEditorProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div className="design-section-wrapper">
|
<div className="design-section-wrapper">
|
||||||
<div className="design-section">
|
<div className="design-section">
|
||||||
<div className="section-header">Size</div>
|
<div className="section-header">Size</div>
|
||||||
@@ -68,7 +64,7 @@ const BlockEditor: React.FC<BlockEditorProps> = ({
|
|||||||
updateBlockSize(selectedBlock, {
|
updateBlockSize(selectedBlock, {
|
||||||
...currentBlock.size!,
|
...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
|
||||||
})
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<InputWithDropDown
|
<InputWithDropDown
|
||||||
@@ -79,7 +75,7 @@ const BlockEditor: React.FC<BlockEditorProps> = ({
|
|||||||
updateBlockSize(selectedBlock, {
|
updateBlockSize(selectedBlock, {
|
||||||
...currentBlock.size!,
|
...currentBlock.size!,
|
||||||
height: Number(newValue),
|
height: Number(newValue),
|
||||||
})
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -100,56 +96,22 @@ const BlockEditor: React.FC<BlockEditorProps> = ({
|
|||||||
<div className="position-canvas">
|
<div className="position-canvas">
|
||||||
<div className="canvas">
|
<div className="canvas">
|
||||||
<div className="value padding-top">
|
<div className="value padding-top">
|
||||||
<RenameInput
|
<RenameInput value={getCurrentBlockStyleValue(currentBlock, "padding") ? String(getCurrentBlockStyleValue(currentBlock, "padding")) : "120"} />
|
||||||
value={
|
|
||||||
getCurrentBlockStyleValue(currentBlock, "padding")
|
|
||||||
? String(getCurrentBlockStyleValue(currentBlock, "padding"))
|
|
||||||
: "120"
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div className="value padding-right">
|
<div className="value padding-right">
|
||||||
<RenameInput
|
<RenameInput value={getCurrentBlockStyleValue(currentBlock, "padding") ? String(getCurrentBlockStyleValue(currentBlock, "padding")) : "120"} />
|
||||||
value={
|
|
||||||
getCurrentBlockStyleValue(currentBlock, "padding")
|
|
||||||
? String(getCurrentBlockStyleValue(currentBlock, "padding"))
|
|
||||||
: "120"
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div className="value padding-bottom">
|
<div className="value padding-bottom">
|
||||||
<RenameInput
|
<RenameInput value={getCurrentBlockStyleValue(currentBlock, "padding") ? String(getCurrentBlockStyleValue(currentBlock, "padding")) : "120"} />
|
||||||
value={
|
|
||||||
getCurrentBlockStyleValue(currentBlock, "padding")
|
|
||||||
? String(getCurrentBlockStyleValue(currentBlock, "padding"))
|
|
||||||
: "120"
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div className="value padding-left">
|
<div className="value padding-left">
|
||||||
<RenameInput
|
<RenameInput value={getCurrentBlockStyleValue(currentBlock, "padding") ? String(getCurrentBlockStyleValue(currentBlock, "padding")) : "120"} />
|
||||||
value={
|
|
||||||
getCurrentBlockStyleValue(currentBlock, "padding")
|
|
||||||
? String(getCurrentBlockStyleValue(currentBlock, "padding"))
|
|
||||||
: "120"
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div className="design-section-footer">
|
<div className="design-section-footer">
|
||||||
<InputWithDropDown
|
<InputWithDropDown label="Layer" value={String(currentBlock.zIndex || 1)} placeholder={"Layer"} onChange={(newValue) => updateBlockZIndex(selectedBlock, Number(newValue))} />
|
||||||
label="Layer"
|
|
||||||
value={String(currentBlock.zIndex || 1)}
|
|
||||||
placeholder={"Layer"}
|
|
||||||
onChange={(newValue) => updateBlockZIndex(selectedBlock, Number(newValue))}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<InputRange
|
<InputRange
|
||||||
label={"Radius"}
|
label={"Radius"}
|
||||||
@@ -159,10 +121,9 @@ const BlockEditor: React.FC<BlockEditorProps> = ({
|
|||||||
onChange={(newValue) => {
|
onChange={(newValue) => {
|
||||||
updateBlockStyle(selectedBlock, {
|
updateBlockStyle(selectedBlock, {
|
||||||
borderRadius: Number(newValue),
|
borderRadius: Number(newValue),
|
||||||
})
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -176,7 +137,6 @@ const BlockEditor: React.FC<BlockEditorProps> = ({
|
|||||||
value={rgbaToHex(getCurrentBlockStyleValue(currentBlock, "backgroundColor"))}
|
value={rgbaToHex(getCurrentBlockStyleValue(currentBlock, "backgroundColor"))}
|
||||||
// onChange={(e) => setColor(e.target.value)}
|
// onChange={(e) => setColor(e.target.value)}
|
||||||
onChange={(e) => handleBackgroundColorChange(currentBlock, selectedBlock, updateBlockStyle, e.target.value)}
|
onChange={(e) => handleBackgroundColorChange(currentBlock, selectedBlock, updateBlockStyle, e.target.value)}
|
||||||
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="colorValue">{color}</div>
|
<div className="colorValue">{color}</div>
|
||||||
@@ -189,23 +149,10 @@ const BlockEditor: React.FC<BlockEditorProps> = ({
|
|||||||
value={Math.round(getAlphaFromRgba(getCurrentBlockStyleValue(currentBlock, "backgroundColor")) * 100)}
|
value={Math.round(getAlphaFromRgba(getCurrentBlockStyleValue(currentBlock, "backgroundColor")) * 100)}
|
||||||
// onChange={(value: number) => handleBackgroundAlphaChange(currentBlock, selectedBlock, updateBlockStyle, Number(value))}
|
// onChange={(value: number) => handleBackgroundAlphaChange(currentBlock, selectedBlock, updateBlockStyle, Number(value))}
|
||||||
onChange={(value: number) => handleBlurAmountChange(selectedBlock, updateBlockStyle, Number(value))}
|
onChange={(value: number) => handleBlurAmountChange(selectedBlock, updateBlockStyle, Number(value))}
|
||||||
|
|
||||||
/>
|
/>
|
||||||
<InputRange
|
<InputRange label={"Blur"} min={0} max={8} value={parseInt(getCurrentBlockStyleValue(currentBlock, "backdropFilter")?.match(/\d+/)?.[0] || "10")} />
|
||||||
label={"Blur"}
|
|
||||||
min={0}
|
|
||||||
max={8}
|
|
||||||
value={parseInt(getCurrentBlockStyleValue(currentBlock, "backdropFilter")?.match(/\d+/)?.[0] || "10")}
|
|
||||||
|
|
||||||
/>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ interface ElementDesignProps {
|
|||||||
updateElementPosition: (blockId: string, elementId: string, position: { x: number; y: number }) => void;
|
updateElementPosition: (blockId: string, elementId: string, position: { x: number; y: number }) => void;
|
||||||
updateElementPositionType: (blockId: string, elementId: string, positionType: "relative" | "absolute" | "fixed") => void;
|
updateElementPositionType: (blockId: string, elementId: string, positionType: "relative" | "absolute" | "fixed") => void;
|
||||||
updateElementZIndex: (blockId: string, elementId: string, zIndex: number) => void;
|
updateElementZIndex: (blockId: string, elementId: string, zIndex: number) => void;
|
||||||
updateElementData: (blockId: string, elementId: string, updates: Partial<DataBinding>) => void;
|
updateElementData: (blockId: string, elementId: string, updates: Partial<ElementDataBinding>) => void;
|
||||||
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;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ interface ElementEditorProps {
|
|||||||
updateElementPosition: (blockId: string, elementId: string, position: { x: number; y: number }) => void;
|
updateElementPosition: (blockId: string, elementId: string, position: { x: number; y: number }) => void;
|
||||||
updateElementPositionType: (blockId: string, elementId: string, positionType: "relative" | "absolute" | "fixed") => void;
|
updateElementPositionType: (blockId: string, elementId: string, positionType: "relative" | "absolute" | "fixed") => void;
|
||||||
updateElementZIndex: (blockId: string, elementId: string, zIndex: number) => void;
|
updateElementZIndex: (blockId: string, elementId: string, zIndex: number) => void;
|
||||||
updateElementData: (blockId: string, elementId: string, updates: Partial<DataBinding>) => void;
|
updateElementData: (blockId: string, elementId: string, updates: Partial<ElementDataBinding>) => void;
|
||||||
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;
|
||||||
@@ -62,7 +62,7 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
|
|||||||
const { getElementById } = simulationDashBoardStore();
|
const { getElementById } = simulationDashBoardStore();
|
||||||
const element = getElementById(selectedBlock, selectedElement);
|
const element = getElementById(selectedBlock, selectedElement);
|
||||||
const [selectType, setSelectType] = useState("design");
|
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(() => {
|
const getAssetDropdownItems = useCallback(() => {
|
||||||
if (!product?.eventDatas) return [];
|
if (!product?.eventDatas) return [];
|
||||||
@@ -273,10 +273,12 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const singleValueFields = useMemo(() => {
|
const singleValueFields = useMemo(() => {
|
||||||
if (element?.type === "graph" && element.dataType === "single-machine") {
|
if (element?.type === "graph" && element.dataBinding?.dataType === "single-machine") {
|
||||||
const dataValues = Array.isArray(element.dataValue) ? element.dataValue : [];
|
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) => ({
|
return dataValues.map((value, index) => ({
|
||||||
id: `data-value-${index}`,
|
id: `data-value-${index}`,
|
||||||
@@ -297,8 +299,8 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
|
|||||||
}, [element, getLableValueDropdownItems]);
|
}, [element, getLableValueDropdownItems]);
|
||||||
|
|
||||||
const multipleSourceFields = useMemo(() => {
|
const multipleSourceFields = useMemo(() => {
|
||||||
if (element?.type === "graph" && element.dataType === "multiple-machine") {
|
if (element?.type === "graph" && element.dataBinding?.dataType === "multiple-machine") {
|
||||||
const dataSources = Array.isArray(element.dataSource) ? element.dataSource : [];
|
const dataSources = Array.isArray(element.dataBinding.dataSource) ? element.dataBinding.dataSource : [];
|
||||||
|
|
||||||
return dataSources.map((_, index) => ({
|
return dataSources.map((_, index) => ({
|
||||||
id: `data-source-${index}`,
|
id: `data-source-${index}`,
|
||||||
@@ -324,21 +326,21 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
|
|||||||
|
|
||||||
setSelectDataMapping(newDataType);
|
setSelectDataMapping(newDataType);
|
||||||
|
|
||||||
if (newDataType === "singleMachine" && element.dataType === "multiple-machine") {
|
if (newDataType === "singleMachine" && element.dataBinding?.dataType === "multiple-machine") {
|
||||||
updateDataType(selectedBlock, selectedElement, "single-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");
|
updateDataType(selectedBlock, selectedElement, "multiple-machine");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const addField = () => {
|
const addField = () => {
|
||||||
if (selectDataMapping === "singleMachine" && element?.type === "graph" && element.dataType === "single-machine") {
|
if (selectDataMapping === "singleMachine" && element?.type === "graph" && element.dataBinding?.dataType === "single-machine") {
|
||||||
const currentDataValue = Array.isArray(element.dataValue) ? element.dataValue : [];
|
const currentDataValue = Array.isArray(element.dataBinding.dataValue) ? element.dataBinding.dataValue : [];
|
||||||
const newDataValue = [...currentDataValue, ""];
|
const newDataValue = [...currentDataValue, ""];
|
||||||
|
|
||||||
updateDataValue(selectedBlock, selectedElement, newDataValue);
|
updateDataValue(selectedBlock, selectedElement, newDataValue);
|
||||||
} else if (selectDataMapping === "multipleMachine" && element?.type === "graph" && element.dataType === "multiple-machine") {
|
} else if (selectDataMapping === "multipleMachine" && element?.type === "graph" && element.dataBinding?.dataType === "multiple-machine") {
|
||||||
const currentDataSource = Array.isArray(element.dataSource) ? element.dataSource : [];
|
const currentDataSource = Array.isArray(element.dataBinding.dataSource) ? element.dataBinding.dataSource : [];
|
||||||
const newDataSource = [...currentDataSource, ""];
|
const newDataSource = [...currentDataSource, ""];
|
||||||
|
|
||||||
updateDataSource(selectedBlock, selectedElement, newDataSource);
|
updateDataSource(selectedBlock, selectedElement, newDataSource);
|
||||||
@@ -399,7 +401,15 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
|
|||||||
<div className="data-details">
|
<div className="data-details">
|
||||||
{element?.type === "label-value" && (
|
{element?.type === "label-value" && (
|
||||||
<div className="data-wrapper">
|
<div className="data-wrapper">
|
||||||
<InputWithDropDown label="Title" value={`title`} placeholder={"Label 1"} min={0.1} step={0.1} max={2} onChange={() => {}} />
|
<InputWithDropDown
|
||||||
|
label="Label"
|
||||||
|
type="string"
|
||||||
|
value={element.dataBinding?.label || ""}
|
||||||
|
placeholder={"Label 1"}
|
||||||
|
onChange={(value) => {
|
||||||
|
updateElementData(selectedBlock, selectedElement, { label: value });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
<div className="data">
|
<div className="data">
|
||||||
<DataDetailedDropdown
|
<DataDetailedDropdown
|
||||||
title="Data Source"
|
title="Data Source"
|
||||||
@@ -415,12 +425,18 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
value={
|
value={
|
||||||
element.dataSource
|
element.dataBinding?.dataSource
|
||||||
? { id: element.dataSource, label: getEventByModelUuid(selectedProduct.productUuid, element.dataSource)?.modelName ?? "", icon: <DeviceIcon /> }
|
? {
|
||||||
|
id: element.dataBinding.dataSource as string,
|
||||||
|
label:
|
||||||
|
getEventByModelUuid(selectedProduct.productUuid, element.dataBinding.dataSource as string)?.modelName ??
|
||||||
|
(element.dataBinding.dataSource === "global" ? "Global" : ""),
|
||||||
|
icon: <DeviceIcon />,
|
||||||
|
}
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
updateDataSource(selectedBlock, selectedElement, value.id);
|
updateElementData(selectedBlock, selectedElement, { dataSource: value.id });
|
||||||
}}
|
}}
|
||||||
dropDownHeader={"RT-Data"}
|
dropDownHeader={"RT-Data"}
|
||||||
eyedroper={true}
|
eyedroper={true}
|
||||||
@@ -431,10 +447,21 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
|
|||||||
<DataDetailedDropdown
|
<DataDetailedDropdown
|
||||||
title="Data Value"
|
title="Data Value"
|
||||||
placeholder="Select Value"
|
placeholder="Select Value"
|
||||||
sections={getLableValueDropdownItems(element.dataSource as string | undefined)}
|
sections={getLableValueDropdownItems(element.dataBinding?.dataSource as string | undefined)}
|
||||||
value={element.dataValue ? { id: element.dataValue, label: element.dataValue, icon: <ParametersIcon /> } : null}
|
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: <ParametersIcon />,
|
||||||
|
}
|
||||||
|
: null
|
||||||
|
}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
updateDataValue(selectedBlock, selectedElement, value.id);
|
updateElementData(selectedBlock, selectedElement, { dataValue: value.id, label: value.label });
|
||||||
}}
|
}}
|
||||||
dropDownHeader={"RT-Data-Value"}
|
dropDownHeader={"RT-Data-Value"}
|
||||||
/>
|
/>
|
||||||
@@ -456,14 +483,14 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{selectDataMapping === "singleMachine" && element.dataType === "single-machine" && (
|
{selectDataMapping === "singleMachine" && element.dataBinding?.dataType === "single-machine" && (
|
||||||
<div className="fields-wrapper">
|
<div className="fields-wrapper">
|
||||||
{singleSourceFields.map((field) => (
|
{singleSourceFields.map((field) => (
|
||||||
<DataSourceSelector
|
<DataSourceSelector
|
||||||
key={field.id}
|
key={field.id}
|
||||||
label={field.label}
|
label={field.label}
|
||||||
options={field.options}
|
options={field.options}
|
||||||
selected={getEventByModelUuid(selectedProduct.productUuid, element.dataSource)?.modelName ?? ""}
|
selected={getEventByModelUuid(selectedProduct.productUuid, element.dataBinding?.dataSource as string)?.modelName ?? ""}
|
||||||
onSelect={(value) => {
|
onSelect={(value) => {
|
||||||
updateDataSource(selectedBlock, selectedElement, value.id);
|
updateDataSource(selectedBlock, selectedElement, value.id);
|
||||||
}}
|
}}
|
||||||
@@ -476,9 +503,9 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
|
|||||||
key={field.id}
|
key={field.id}
|
||||||
label={field.label}
|
label={field.label}
|
||||||
options={field.options}
|
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) => {
|
onSelect={(value) => {
|
||||||
const currentDataValue = Array.isArray(element.dataValue) ? element.dataValue : [];
|
const currentDataValue = Array.isArray(element.dataBinding?.dataValue) ? element.dataBinding!.dataValue : [];
|
||||||
|
|
||||||
const newDataValue = [...currentDataValue];
|
const newDataValue = [...currentDataValue];
|
||||||
newDataValue[index] = value.id;
|
newDataValue[index] = value.id;
|
||||||
@@ -498,14 +525,14 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{selectDataMapping === "multipleMachine" && element.dataType === "multiple-machine" && (
|
{selectDataMapping === "multipleMachine" && element.dataBinding?.dataType === "multiple-machine" && (
|
||||||
<div className="fields-wrapper">
|
<div className="fields-wrapper">
|
||||||
{multipleValueFields.map((field) => (
|
{multipleValueFields.map((field) => (
|
||||||
<DataSourceSelector
|
<DataSourceSelector
|
||||||
key={field.id}
|
key={field.id}
|
||||||
label={field.label}
|
label={field.label}
|
||||||
options={field.options}
|
options={field.options}
|
||||||
selected={field.options.find((o) => o.id === element.commonValue)?.label ?? ""}
|
selected={field.options.find((o) => o.id === element.dataBinding?.commonValue)?.label ?? ""}
|
||||||
onSelect={(value) => {
|
onSelect={(value) => {
|
||||||
updateCommonValue(selectedBlock, selectedElement, value.id);
|
updateCommonValue(selectedBlock, selectedElement, value.id);
|
||||||
}}
|
}}
|
||||||
@@ -518,9 +545,9 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
|
|||||||
key={field.id}
|
key={field.id}
|
||||||
label={field.label}
|
label={field.label}
|
||||||
options={field.options}
|
options={field.options}
|
||||||
selected={getEventByModelUuid(selectedProduct.productUuid, element.dataSource?.[index])?.modelName ?? ""}
|
selected={getEventByModelUuid(selectedProduct.productUuid, (element.dataBinding?.dataSource as string[])?.[index] || "")?.modelName ?? ""}
|
||||||
onSelect={(value) => {
|
onSelect={(value) => {
|
||||||
const current = Array.isArray(element.dataSource) ? element.dataSource : [];
|
const current = Array.isArray(element.dataBinding?.dataSource) ? element.dataBinding!.dataSource : [];
|
||||||
|
|
||||||
const next = [...current];
|
const next = [...current];
|
||||||
next[index] = value.id;
|
next[index] = value.id;
|
||||||
|
|||||||
@@ -1,57 +1,12 @@
|
|||||||
import { dataModelManager } from "../../data/dataModel";
|
|
||||||
import type { UIElement } from "../../../../types/exportedTypes";
|
import type { UIElement } from "../../../../types/exportedTypes";
|
||||||
|
|
||||||
export const resolveElementValue = (element: UIElement) => {
|
export const resolveElementValue = (element: UIElement) => {
|
||||||
// Implementation from original code
|
if (!element.dataBinding) {
|
||||||
if (!element.data) {
|
|
||||||
return { value: "No data" };
|
return { value: "No data" };
|
||||||
}
|
}
|
||||||
|
|
||||||
const binding = element.data;
|
|
||||||
|
|
||||||
switch (binding.dataSource) {
|
|
||||||
case "static":
|
|
||||||
return {
|
return {
|
||||||
label: binding.label,
|
label: element.dataBinding.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,
|
|
||||||
graphData: element.graphData,
|
graphData: element.graphData,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ type InputWithDropDownProps = {
|
|||||||
onChange: (newValue: string) => void;
|
onChange: (newValue: string) => void;
|
||||||
editableLabel?: boolean;
|
editableLabel?: boolean;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
|
type?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const InputWithDropDown: React.FC<InputWithDropDownProps> = ({
|
const InputWithDropDown: React.FC<InputWithDropDownProps> = ({
|
||||||
@@ -31,6 +32,7 @@ const InputWithDropDown: React.FC<InputWithDropDownProps> = ({
|
|||||||
onChange,
|
onChange,
|
||||||
editableLabel = false,
|
editableLabel = false,
|
||||||
placeholder = "Inherit",
|
placeholder = "Inherit",
|
||||||
|
type = "number",
|
||||||
}) => {
|
}) => {
|
||||||
const [openDropdown, setOpenDropdown] = useState(false);
|
const [openDropdown, setOpenDropdown] = useState(false);
|
||||||
|
|
||||||
@@ -54,7 +56,7 @@ const InputWithDropDown: React.FC<InputWithDropDownProps> = ({
|
|||||||
min={min}
|
min={min}
|
||||||
max={max}
|
max={max}
|
||||||
step={step}
|
step={step}
|
||||||
type="number"
|
type={type}
|
||||||
value={value} // Controlled input
|
value={value} // Controlled input
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onChange={(e) => onChange(e.target.value)}
|
onChange={(e) => onChange(e.target.value)}
|
||||||
@@ -62,19 +64,12 @@ const InputWithDropDown: React.FC<InputWithDropDownProps> = ({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{activeOption && (
|
{activeOption && (
|
||||||
<div
|
<div className="dropdown" onClick={() => setOpenDropdown((prev) => !prev)}>
|
||||||
className="dropdown"
|
|
||||||
onClick={() => setOpenDropdown((prev) => !prev)}
|
|
||||||
>
|
|
||||||
<div className="active-option">{activeOption}</div>
|
<div className="active-option">{activeOption}</div>
|
||||||
{options && openDropdown && (
|
{options && openDropdown && (
|
||||||
<div className="dropdown-options-list">
|
<div className="dropdown-options-list">
|
||||||
{options.map((option, index) => (
|
{options.map((option, index) => (
|
||||||
<div
|
<div key={index} className="dropdown-option" onClick={onClick}>
|
||||||
key={index}
|
|
||||||
className="dropdown-option"
|
|
||||||
onClick={onClick}
|
|
||||||
>
|
|
||||||
{option}
|
{option}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
@@ -88,7 +83,3 @@ const InputWithDropDown: React.FC<InputWithDropDownProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default InputWithDropDown;
|
export default InputWithDropDown;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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 <access_token>",
|
||||||
|
"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");
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -45,7 +45,7 @@ interface SimulationDashboardStore {
|
|||||||
updateElementZIndex: (blockId: string, elementId: string, zIndex: number) => void;
|
updateElementZIndex: (blockId: string, elementId: string, zIndex: number) => void;
|
||||||
|
|
||||||
// Element data operations
|
// Element data operations
|
||||||
updateElementData: (blockId: string, elementId: string, updates: Partial<DataBinding>) => void;
|
updateElementData: (blockId: string, elementId: string, updates: Partial<ElementDataBinding>) => void;
|
||||||
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, graphType: GraphTypes) => void;
|
updateGraphType: (blockId: string, elementId: string, graphType: GraphTypes) => void;
|
||||||
@@ -70,7 +70,7 @@ interface SimulationDashboardStore {
|
|||||||
peekUpdateElementPosition: (blockId: string, elementId: string, position: Position) => Block[];
|
peekUpdateElementPosition: (blockId: string, elementId: string, position: Position) => Block[];
|
||||||
peekUpdateElementPositionType: (blockId: string, elementId: string, positionType: "relative" | "absolute" | "fixed") => Block[];
|
peekUpdateElementPositionType: (blockId: string, elementId: string, positionType: "relative" | "absolute" | "fixed") => Block[];
|
||||||
peekUpdateElementZIndex: (blockId: string, elementId: string, zIndex: number) => Block[];
|
peekUpdateElementZIndex: (blockId: string, elementId: string, zIndex: number) => Block[];
|
||||||
peekUpdateElementData: (blockId: string, elementId: string, updates: Partial<DataBinding>) => Block[];
|
peekUpdateElementData: (blockId: string, elementId: string, updates: Partial<ElementDataBinding>) => Block[];
|
||||||
peekUpdateGraphData: (blockId: string, elementId: string, newData: GraphDataPoint[]) => Block[];
|
peekUpdateGraphData: (blockId: string, elementId: string, newData: GraphDataPoint[]) => Block[];
|
||||||
peekUpdateGraphTitle: (blockId: string, elementId: string, title: string) => Block[];
|
peekUpdateGraphTitle: (blockId: string, elementId: string, title: string) => Block[];
|
||||||
peekUpdateGraphType: (blockId: string, elementId: string, graphType: GraphTypes) => Block[];
|
peekUpdateGraphType: (blockId: string, elementId: string, graphType: GraphTypes) => Block[];
|
||||||
@@ -244,6 +244,7 @@ export const createSimulationDashboardStore = () => {
|
|||||||
staticValue: "",
|
staticValue: "",
|
||||||
label: undefined,
|
label: undefined,
|
||||||
},
|
},
|
||||||
|
dataBinding: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@@ -251,9 +252,6 @@ export const createSimulationDashboardStore = () => {
|
|||||||
newElement = {
|
newElement = {
|
||||||
...commonProps,
|
...commonProps,
|
||||||
type: "label-value",
|
type: "label-value",
|
||||||
title: "Label Value",
|
|
||||||
dataSource: "",
|
|
||||||
dataValue: "",
|
|
||||||
style: {
|
style: {
|
||||||
color: "#ffffff",
|
color: "#ffffff",
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
@@ -266,10 +264,11 @@ export const createSimulationDashboardStore = () => {
|
|||||||
labelColor: "#ffffff",
|
labelColor: "#ffffff",
|
||||||
valueColor: "#ffffff",
|
valueColor: "#ffffff",
|
||||||
},
|
},
|
||||||
data: {
|
dataBinding: {
|
||||||
...commonProps.data,
|
label: "Label Value",
|
||||||
staticValue: "Value",
|
dataSource: "",
|
||||||
label: "Label",
|
dataValue: "",
|
||||||
|
dataType: "single-machine",
|
||||||
},
|
},
|
||||||
size: { width: 200, height: 60 },
|
size: { width: 200, height: 60 },
|
||||||
};
|
};
|
||||||
@@ -299,18 +298,22 @@ export const createSimulationDashboardStore = () => {
|
|||||||
if (dataType === "multiple-machine") {
|
if (dataType === "multiple-machine") {
|
||||||
newElement = {
|
newElement = {
|
||||||
...baseGraphProps,
|
...baseGraphProps,
|
||||||
|
dataBinding: {
|
||||||
dataType: "multiple-machine" as const,
|
dataType: "multiple-machine" as const,
|
||||||
title: "Multi Machine Chart",
|
label: "Multi Machine Chart",
|
||||||
dataSource: [],
|
dataSource: [],
|
||||||
commonValue: "",
|
commonValue: "",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
newElement = {
|
newElement = {
|
||||||
...baseGraphProps,
|
...baseGraphProps,
|
||||||
|
dataBinding: {
|
||||||
dataType: "single-machine" as const,
|
dataType: "single-machine" as const,
|
||||||
title: "Single Machine Chart",
|
label: "Single Machine Chart",
|
||||||
dataSource: "",
|
dataSource: "",
|
||||||
dataValue: [],
|
dataValue: [],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -324,10 +327,6 @@ export const createSimulationDashboardStore = () => {
|
|||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
textAlign: "left" as const,
|
textAlign: "left" as const,
|
||||||
},
|
},
|
||||||
data: {
|
|
||||||
...commonProps.data,
|
|
||||||
staticValue: "Text",
|
|
||||||
},
|
|
||||||
size: { width: 200, height: 40 },
|
size: { width: 200, height: 40 },
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
@@ -444,8 +443,8 @@ export const createSimulationDashboardStore = () => {
|
|||||||
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((el) => el.elementUuid === elementId);
|
const element = block.elements.find((el) => el.elementUuid === elementId);
|
||||||
if (element?.data) {
|
if (element?.dataBinding) {
|
||||||
element.data = { ...element.data, ...updates };
|
element.dataBinding = { ...element.dataBinding, ...updates };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -618,9 +617,6 @@ export const createSimulationDashboardStore = () => {
|
|||||||
newElement = {
|
newElement = {
|
||||||
...commonProps,
|
...commonProps,
|
||||||
type: "label-value",
|
type: "label-value",
|
||||||
title: "Label Value",
|
|
||||||
dataSource: "",
|
|
||||||
dataValue: "metric-1",
|
|
||||||
style: {
|
style: {
|
||||||
color: "#ffffff",
|
color: "#ffffff",
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
@@ -633,10 +629,10 @@ export const createSimulationDashboardStore = () => {
|
|||||||
labelColor: "#ffffff",
|
labelColor: "#ffffff",
|
||||||
valueColor: "#ffffff",
|
valueColor: "#ffffff",
|
||||||
},
|
},
|
||||||
data: {
|
dataBinding: {
|
||||||
...commonProps.data,
|
label: "Label Value",
|
||||||
staticValue: "Value",
|
dataSource: "",
|
||||||
label: "Label",
|
dataValue: "",
|
||||||
},
|
},
|
||||||
size: { width: 200, height: 60 },
|
size: { width: 200, height: 60 },
|
||||||
};
|
};
|
||||||
@@ -666,18 +662,22 @@ export const createSimulationDashboardStore = () => {
|
|||||||
if (dataType === "multiple-machine") {
|
if (dataType === "multiple-machine") {
|
||||||
newElement = {
|
newElement = {
|
||||||
...baseGraphProps,
|
...baseGraphProps,
|
||||||
|
dataBinding: {
|
||||||
dataType: "multiple-machine" as const,
|
dataType: "multiple-machine" as const,
|
||||||
title: "Multi Machine Chart",
|
label: "Multi Machine Chart",
|
||||||
dataSource: [],
|
dataSource: [],
|
||||||
commonValue: "",
|
commonValue: "",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
newElement = {
|
newElement = {
|
||||||
...baseGraphProps,
|
...baseGraphProps,
|
||||||
|
dataBinding: {
|
||||||
dataType: "single-machine" as const,
|
dataType: "single-machine" as const,
|
||||||
title: "Single Machine Chart",
|
label: "Single Machine Chart",
|
||||||
dataSource: "",
|
dataSource: "",
|
||||||
dataValue: [],
|
dataValue: [],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -691,10 +691,6 @@ export const createSimulationDashboardStore = () => {
|
|||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
textAlign: "left" as const,
|
textAlign: "left" as const,
|
||||||
},
|
},
|
||||||
data: {
|
|
||||||
...commonProps.data,
|
|
||||||
staticValue: "Text",
|
|
||||||
},
|
|
||||||
size: { width: 200, height: 40 },
|
size: { width: 200, height: 40 },
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
@@ -806,8 +802,8 @@ export const createSimulationDashboardStore = () => {
|
|||||||
const block = blocks.find((b) => b.blockUuid === blockId);
|
const block = blocks.find((b) => b.blockUuid === blockId);
|
||||||
if (block) {
|
if (block) {
|
||||||
const element = block.elements.find((el) => el.elementUuid === elementId);
|
const element = block.elements.find((el) => el.elementUuid === elementId);
|
||||||
if (element?.data) {
|
if (element?.dataBinding) {
|
||||||
element.data = { ...element.data, ...updates };
|
element.dataBinding = { ...element.dataBinding, ...updates };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return blocks;
|
return blocks;
|
||||||
@@ -851,7 +847,7 @@ export const createSimulationDashboardStore = () => {
|
|||||||
return blocks;
|
return blocks;
|
||||||
},
|
},
|
||||||
|
|
||||||
peekUpdateDataType: (blockId, elementId, dataType) => {
|
peekUpdateDataType: (blockId: string, elementId: string, dataType: DataType) => {
|
||||||
const blocks = cloneBlocks(get().blocks);
|
const blocks = cloneBlocks(get().blocks);
|
||||||
|
|
||||||
const block = blocks.find((b) => b.blockUuid === blockId);
|
const block = blocks.find((b) => b.blockUuid === blockId);
|
||||||
@@ -861,70 +857,58 @@ export const createSimulationDashboardStore = () => {
|
|||||||
if (index === -1) return blocks;
|
if (index === -1) return blocks;
|
||||||
|
|
||||||
const element = block.elements[index];
|
const element = block.elements[index];
|
||||||
if (element.type !== "graph" || element.dataType === dataType) return blocks;
|
if (element.type !== "graph" || !element.dataBinding || element.dataBinding.dataType === dataType) return blocks;
|
||||||
|
|
||||||
let newElement: UIElement;
|
|
||||||
|
|
||||||
|
// We are updating the dataBinding object deeply
|
||||||
if (dataType === "single-machine") {
|
if (dataType === "single-machine") {
|
||||||
const { commonValue, ...rest } = element as Extract<UIElement, { type: "graph"; dataType: "multiple-machine" }>;
|
element.dataBinding.dataType = "single-machine";
|
||||||
|
element.dataBinding.dataSource = "";
|
||||||
newElement = {
|
element.dataBinding.dataValue = [];
|
||||||
...rest,
|
delete element.dataBinding.commonValue;
|
||||||
dataType: "single-machine",
|
|
||||||
dataSource: "",
|
|
||||||
dataValue: [],
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
const { dataValue, ...rest } = element as Extract<UIElement, { type: "graph"; dataType: "single-machine" }>;
|
element.dataBinding.dataType = "multiple-machine";
|
||||||
|
element.dataBinding.dataSource = [];
|
||||||
newElement = {
|
element.dataBinding.commonValue = "";
|
||||||
...rest,
|
delete element.dataBinding.dataValue;
|
||||||
dataType: "multiple-machine",
|
|
||||||
dataSource: [],
|
|
||||||
commonValue: "",
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
block.elements[index] = newElement;
|
|
||||||
return blocks;
|
return blocks;
|
||||||
},
|
},
|
||||||
|
|
||||||
peekUpdateCommonValue: (blockId, elementId, commonValue) => {
|
peekUpdateCommonValue: (blockId: string, elementId: string, commonValue: string) => {
|
||||||
const blocks = cloneBlocks(get().blocks);
|
const blocks = cloneBlocks(get().blocks);
|
||||||
const block = blocks.find((b) => b.blockUuid === blockId);
|
const block = blocks.find((b) => b.blockUuid === blockId);
|
||||||
if (block) {
|
if (block) {
|
||||||
const element = block.elements.find((el) => el.elementUuid === elementId);
|
const element = block.elements.find((el) => el.elementUuid === elementId);
|
||||||
if (element && element.type === "graph" && element.dataType === "multiple-machine") {
|
if (element && element.dataBinding) {
|
||||||
element.commonValue = commonValue;
|
element.dataBinding.commonValue = commonValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return blocks;
|
return blocks;
|
||||||
},
|
},
|
||||||
|
|
||||||
peekUpdateDataValue: (blockId, elementId, dataValue) => {
|
peekUpdateDataValue: (blockId: string, elementId: string, dataValue: string | string[]) => {
|
||||||
const blocks = cloneBlocks(get().blocks);
|
const blocks = cloneBlocks(get().blocks);
|
||||||
const block = blocks.find((b) => b.blockUuid === blockId);
|
const block = blocks.find((b) => b.blockUuid === blockId);
|
||||||
if (block) {
|
if (block) {
|
||||||
const element = block.elements.find((el) => el.elementUuid === elementId);
|
const element = block.elements.find((el) => el.elementUuid === elementId);
|
||||||
if (element && element.type === "graph" && element.dataType === "single-machine") {
|
if (element && element.dataBinding) {
|
||||||
element.dataValue = dataValue as string[];
|
element.dataBinding.dataValue = dataValue;
|
||||||
} else if (element && element.type === "label-value") {
|
|
||||||
element.dataValue = dataValue as string;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return blocks;
|
return blocks;
|
||||||
},
|
},
|
||||||
|
|
||||||
peekUpdateDataSource: (blockId, elementId, dataSource) => {
|
peekUpdateDataSource: (blockId: string, elementId: string, dataSource: string | string[]) => {
|
||||||
const blocks = cloneBlocks(get().blocks);
|
const blocks = cloneBlocks(get().blocks);
|
||||||
const block = blocks.find((b) => b.blockUuid === blockId);
|
const block = blocks.find((b) => b.blockUuid === blockId);
|
||||||
if (block) {
|
if (block) {
|
||||||
const element = block.elements.find((el) => el.elementUuid === elementId);
|
const element = block.elements.find((el) => el.elementUuid === elementId);
|
||||||
if (element?.type === "label-value") {
|
if (element?.type === "label-value" && element.dataBinding) {
|
||||||
element.dataValue = "";
|
element.dataBinding.dataValue = "";
|
||||||
}
|
}
|
||||||
if (element) {
|
if (element && element.dataBinding) {
|
||||||
element.dataSource = dataSource;
|
element.dataBinding.dataSource = dataSource;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return blocks;
|
return blocks;
|
||||||
|
|||||||
@@ -21,39 +21,10 @@ export type UIElement = {
|
|||||||
graphType?: GraphTypes;
|
graphType?: GraphTypes;
|
||||||
graphTitle?: string;
|
graphTitle?: string;
|
||||||
style: ExtendedCSSProperties;
|
style: ExtendedCSSProperties;
|
||||||
data?: DataBinding;
|
dataBinding?: ElementDataBinding;
|
||||||
position?: Position;
|
position?: Position;
|
||||||
positionType?: "relative" | "absolute" | "fixed";
|
positionType?: "relative" | "absolute" | "fixed";
|
||||||
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;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|||||||
21
app/src/types/simulationDashboard.d.ts
vendored
21
app/src/types/simulationDashboard.d.ts
vendored
@@ -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 DataModelValue = string | number | GraphDataPoint[];
|
||||||
|
|
||||||
type DataModel = Record<string, DataModelValue>;
|
type DataModel = Record<string, DataModelValue>;
|
||||||
@@ -19,6 +6,14 @@ type UIType = "label-value" | "text" | "graph" | "icon";
|
|||||||
|
|
||||||
type DataType = "single-machine" | "multiple-machine";
|
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 = {
|
type Position = {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
|
|||||||
Reference in New Issue
Block a user