feat: Update ElementEditor and DashboardEditor to enhance data handling and UI responsiveness
This commit is contained in:
@@ -620,7 +620,7 @@ const DashboardEditor: React.FC = () => {
|
|||||||
const updatedBlocks = peekRemoveElement(blockId, elementId);
|
const updatedBlocks = peekRemoveElement(blockId, elementId);
|
||||||
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
|
||||||
if (updatedBlock) {
|
if (updatedBlock) {
|
||||||
await updateBackend(updatedBlock);
|
// await updateBackend(updatedBlock);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
setSwapSource={setSwapSource}
|
setSwapSource={setSwapSource}
|
||||||
|
|||||||
@@ -66,16 +66,9 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
|
|||||||
const product = getProductById(selectedProduct.productUuid);
|
const product = getProductById(selectedProduct.productUuid);
|
||||||
const { getElementById } = simulationDashBoardStore();
|
const { getElementById } = simulationDashBoardStore();
|
||||||
const element = getElementById(selectedBlock, selectedElement);
|
const element = getElementById(selectedBlock, selectedElement);
|
||||||
console.log("element: ", element);
|
|
||||||
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.dataType === "multiple-machine" ? "multipleMachine" : "singleMachine");
|
||||||
|
|
||||||
const [multipleFields, setMultipleFields] = useState<Array<{ id: string; label: string }>>([
|
|
||||||
{ id: "common-value", label: "Common Value" },
|
|
||||||
{ id: "data-source-1", label: "Data Source" },
|
|
||||||
{ id: "data-source-2", label: "Data Source" },
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Get asset dropdown items from product
|
// Get asset dropdown items from product
|
||||||
const getAssetDropdownItems = useCallback(() => {
|
const getAssetDropdownItems = useCallback(() => {
|
||||||
if (!product?.eventDatas) return [];
|
if (!product?.eventDatas) return [];
|
||||||
@@ -268,26 +261,6 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
|
|||||||
[product]
|
[product]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Get value dropdown items for a specific asset
|
|
||||||
const getValueDropdownItems = useCallback(
|
|
||||||
(assetId: string | undefined) => {
|
|
||||||
if (!product || !assetId || assetId === "global") return [];
|
|
||||||
|
|
||||||
const assetAnalysis = product?.eventDatas.find((e) => e.modelUuid === assetId);
|
|
||||||
if (!assetAnalysis) return [];
|
|
||||||
|
|
||||||
// Return all available metrics for the asset
|
|
||||||
return getLableValueDropdownItems(assetId).flatMap((section) =>
|
|
||||||
section.items.map((item) => ({
|
|
||||||
id: item.id,
|
|
||||||
label: item.label,
|
|
||||||
icon: item.icon,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
},
|
|
||||||
[product, getLableValueDropdownItems]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Get common value dropdown items (available across all assets)
|
// Get common value dropdown items (available across all assets)
|
||||||
const getCommonValueDropdownItems = useCallback(() => {
|
const getCommonValueDropdownItems = useCallback(() => {
|
||||||
const commonItems = [
|
const commonItems = [
|
||||||
@@ -319,7 +292,7 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
|
|||||||
return dataValues.map((value, index) => ({
|
return dataValues.map((value, index) => ({
|
||||||
id: `data-value-${index}`,
|
id: `data-value-${index}`,
|
||||||
label: `Data Value ${index + 1}`,
|
label: `Data Value ${index + 1}`,
|
||||||
showEyeDropper: true,
|
showEyeDropper: false,
|
||||||
options: valueOptions,
|
options: valueOptions,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -335,6 +308,44 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
|
|||||||
];
|
];
|
||||||
}, [element, getLableValueDropdownItems]);
|
}, [element, getLableValueDropdownItems]);
|
||||||
|
|
||||||
|
const multipleSourceFields = useMemo(() => {
|
||||||
|
if (element?.type === "graph" && element.dataType === "multiple-machine") {
|
||||||
|
const dataSources = Array.isArray(element.dataSource) ? element.dataSource : [];
|
||||||
|
|
||||||
|
return dataSources.map((_, index) => ({
|
||||||
|
id: `data-source-${index}`,
|
||||||
|
label: `Data Source ${index + 1}`,
|
||||||
|
showEyeDropper: true,
|
||||||
|
options: getAssetDropdownItems().map((item) => ({
|
||||||
|
id: item.id,
|
||||||
|
label: item.label,
|
||||||
|
})),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}, [element, getAssetDropdownItems]);
|
||||||
|
|
||||||
|
const multipleValueFields = useMemo(
|
||||||
|
() => [{ id: "data-value", label: "Data Value", showEyeDropper: false, options: getCommonValueDropdownItems().map((item) => ({ id: item.id, label: item.label })) }],
|
||||||
|
[getCommonValueDropdownItems]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleDataTypeSwitch = (newDataType: "singleMachine" | "multipleMachine") => {
|
||||||
|
if (!element || element.type !== "graph") return;
|
||||||
|
|
||||||
|
setSelectDataMapping(newDataType);
|
||||||
|
|
||||||
|
// Convert the element data type when switching
|
||||||
|
if (newDataType === "singleMachine" && element.dataType === "multiple-machine") {
|
||||||
|
// Convert from multiple-machine to single-machine
|
||||||
|
updateDataType(selectedBlock, selectedElement, "single-machine");
|
||||||
|
} else if (newDataType === "multipleMachine" && element.dataType === "single-machine") {
|
||||||
|
// Convert from single-machine to 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.dataType === "single-machine") {
|
||||||
// For single machine, add new data value field
|
// For single machine, add new data value field
|
||||||
@@ -343,7 +354,7 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
|
|||||||
|
|
||||||
// Update the element's dataValue
|
// Update the element's dataValue
|
||||||
updateDataValue(selectedBlock, selectedElement, newDataValue);
|
updateDataValue(selectedBlock, selectedElement, newDataValue);
|
||||||
} else if (selectDataMapping === "multipleMachine" && element?.type === "graph") {
|
} else if (selectDataMapping === "multipleMachine" && element?.type === "graph" && element.dataType === "multiple-machine") {
|
||||||
// For multiple machine, add new data source field
|
// For multiple machine, add new data source field
|
||||||
const currentDataSource = Array.isArray(element.dataSource) ? element.dataSource : [];
|
const currentDataSource = Array.isArray(element.dataSource) ? element.dataSource : [];
|
||||||
const newDataSource = [...currentDataSource, ""]; // Add empty string for new field
|
const newDataSource = [...currentDataSource, ""]; // Add empty string for new field
|
||||||
@@ -456,17 +467,16 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
|
|||||||
<div className="heading">Data Mapping</div>
|
<div className="heading">Data Mapping</div>
|
||||||
|
|
||||||
<div className="type-switch">
|
<div className="type-switch">
|
||||||
<div className={`type ${selectDataMapping === "singleMachine" ? "active" : ""}`} onClick={() => setSelectDataMapping("singleMachine")}>
|
<div className={`type ${selectDataMapping === "singleMachine" ? "active" : ""}`} onClick={() => handleDataTypeSwitch("singleMachine")}>
|
||||||
Single Machine
|
Single Machine
|
||||||
</div>
|
</div>
|
||||||
<div className={`type ${selectDataMapping === "multipleMachine" ? "active" : ""}`} onClick={() => setSelectDataMapping("multipleMachine")}>
|
<div className={`type ${selectDataMapping === "multipleMachine" ? "active" : ""}`} onClick={() => handleDataTypeSwitch("multipleMachine")}>
|
||||||
Multiple Machine
|
Multiple Machine
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{selectDataMapping === "singleMachine" && element.dataType === "single-machine" && (
|
{selectDataMapping === "singleMachine" && element.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}
|
||||||
@@ -476,9 +486,10 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
|
|||||||
onSelect={(value) => {
|
onSelect={(value) => {
|
||||||
updateDataSource(selectedBlock, selectedElement, value.id);
|
updateDataSource(selectedBlock, selectedElement, value.id);
|
||||||
}}
|
}}
|
||||||
showEyeDropper={!!field.showEyeDropper}
|
showEyeDropper={field.showEyeDropper}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{singleValueFields.map((field, index) => (
|
{singleValueFields.map((field, index) => (
|
||||||
<DataSourceSelector
|
<DataSourceSelector
|
||||||
key={field.id}
|
key={field.id}
|
||||||
@@ -486,20 +497,16 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
|
|||||||
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.dataValue?.[index])?.label ?? ""}
|
||||||
onSelect={(value) => {
|
onSelect={(value) => {
|
||||||
// Get current dataValue array
|
|
||||||
const currentDataValue = Array.isArray(element.dataValue) ? element.dataValue : [];
|
const currentDataValue = Array.isArray(element.dataValue) ? element.dataValue : [];
|
||||||
|
|
||||||
// Create a new array with the updated value at the correct index
|
|
||||||
const newDataValue = [...currentDataValue];
|
const newDataValue = [...currentDataValue];
|
||||||
newDataValue[index] = value.id;
|
newDataValue[index] = value.id;
|
||||||
|
|
||||||
// Update the entire array
|
|
||||||
updateDataValue(selectedBlock, selectedElement, newDataValue);
|
updateDataValue(selectedBlock, selectedElement, newDataValue);
|
||||||
}}
|
}}
|
||||||
showEyeDropper={!!field.showEyeDropper}
|
showEyeDropper={field.showEyeDropper}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</>
|
|
||||||
|
|
||||||
<div className="add-field" onClick={addField}>
|
<div className="add-field" onClick={addField}>
|
||||||
<div className="icon">
|
<div className="icon">
|
||||||
@@ -510,19 +517,37 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{selectDataMapping === "multipleMachine" && (
|
{selectDataMapping === "multipleMachine" && element.dataType === "multiple-machine" && (
|
||||||
<div className="fields-wrapper">
|
<div className="fields-wrapper">
|
||||||
{multipleFields.map((field) => (
|
{multipleValueFields.map((field) => (
|
||||||
<div className="datas" key={field.id}>
|
|
||||||
<div className="datas__class">
|
|
||||||
<DataSourceSelector
|
<DataSourceSelector
|
||||||
|
key={field.id}
|
||||||
label={field.label}
|
label={field.label}
|
||||||
options={[{ id: "global", label: "Global" }]}
|
options={field.options}
|
||||||
onSelect={() => {}}
|
selected={field.options.find((o) => o.id === element.commonValue)?.label ?? ""}
|
||||||
showEyeDropper={field.label !== "Common Value"}
|
onSelect={(value) => {
|
||||||
|
updateCommonValue(selectedBlock, selectedElement, value.id);
|
||||||
|
}}
|
||||||
|
showEyeDropper={field.showEyeDropper}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{multipleSourceFields.map((field, index) => (
|
||||||
|
<DataSourceSelector
|
||||||
|
key={field.id}
|
||||||
|
label={field.label}
|
||||||
|
options={field.options}
|
||||||
|
selected={getEventByModelUuid(selectedProduct.productUuid, element.dataSource?.[index])?.modelName ?? ""}
|
||||||
|
onSelect={(value) => {
|
||||||
|
const current = Array.isArray(element.dataSource) ? element.dataSource : [];
|
||||||
|
|
||||||
|
const next = [...current];
|
||||||
|
next[index] = value.id;
|
||||||
|
|
||||||
|
updateDataSource(selectedBlock, selectedElement, next);
|
||||||
|
}}
|
||||||
|
showEyeDropper={field.showEyeDropper}
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
))}
|
||||||
|
|
||||||
<div className="add-field" onClick={addField}>
|
<div className="add-field" onClick={addField}>
|
||||||
|
|||||||
@@ -301,7 +301,7 @@ export const createSimulationDashboardStore = () => {
|
|||||||
...baseGraphProps,
|
...baseGraphProps,
|
||||||
dataType: "multiple-machine" as const,
|
dataType: "multiple-machine" as const,
|
||||||
title: "Multi Machine Chart",
|
title: "Multi Machine Chart",
|
||||||
dataSource: ["", "", ""],
|
dataSource: [],
|
||||||
commonValue: "",
|
commonValue: "",
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
@@ -310,7 +310,7 @@ export const createSimulationDashboardStore = () => {
|
|||||||
dataType: "single-machine" as const,
|
dataType: "single-machine" as const,
|
||||||
title: "Single Machine Chart",
|
title: "Single Machine Chart",
|
||||||
dataSource: "",
|
dataSource: "",
|
||||||
dataValue: ["", "", ""],
|
dataValue: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -668,7 +668,7 @@ export const createSimulationDashboardStore = () => {
|
|||||||
...baseGraphProps,
|
...baseGraphProps,
|
||||||
dataType: "multiple-machine" as const,
|
dataType: "multiple-machine" as const,
|
||||||
title: "Multi Machine Chart",
|
title: "Multi Machine Chart",
|
||||||
dataSource: ["", "", ""],
|
dataSource: [],
|
||||||
commonValue: "",
|
commonValue: "",
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
@@ -677,7 +677,7 @@ export const createSimulationDashboardStore = () => {
|
|||||||
dataType: "single-machine" as const,
|
dataType: "single-machine" as const,
|
||||||
title: "Single Machine Chart",
|
title: "Single Machine Chart",
|
||||||
dataSource: "",
|
dataSource: "",
|
||||||
dataValue: ["", "", ""],
|
dataValue: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -853,13 +853,39 @@ export const createSimulationDashboardStore = () => {
|
|||||||
|
|
||||||
peekUpdateDataType: (blockId, elementId, dataType) => {
|
peekUpdateDataType: (blockId, elementId, 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);
|
||||||
if (block) {
|
if (!block) return blocks;
|
||||||
const element = block.elements.find((el) => el.elementUuid === elementId);
|
|
||||||
if (element && element.type === "graph") {
|
const index = block.elements.findIndex((el) => el.elementUuid === elementId);
|
||||||
element.dataType = dataType;
|
if (index === -1) return blocks;
|
||||||
}
|
|
||||||
|
const element = block.elements[index];
|
||||||
|
if (element.type !== "graph" || element.dataType === dataType) return blocks;
|
||||||
|
|
||||||
|
let newElement: UIElement;
|
||||||
|
|
||||||
|
if (dataType === "single-machine") {
|
||||||
|
const { commonValue, ...rest } = element as Extract<UIElement, { type: "graph"; dataType: "multiple-machine" }>;
|
||||||
|
|
||||||
|
newElement = {
|
||||||
|
...rest,
|
||||||
|
dataType: "single-machine",
|
||||||
|
dataSource: "",
|
||||||
|
dataValue: [],
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
const { dataValue, ...rest } = element as Extract<UIElement, { type: "graph"; dataType: "single-machine" }>;
|
||||||
|
|
||||||
|
newElement = {
|
||||||
|
...rest,
|
||||||
|
dataType: "multiple-machine",
|
||||||
|
dataSource: [],
|
||||||
|
commonValue: "",
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
block.elements[index] = newElement;
|
||||||
return blocks;
|
return blocks;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user