feat: Add ElementEditor component for managing UI element properties and editor panel positioning.
This commit is contained in:
@@ -0,0 +1,256 @@
|
|||||||
|
import { AddIcon, DeviceIcon, ParametersIcon } from "../../../icons/ExportCommonIcons";
|
||||||
|
import DataDetailedDropdown from "../../../ui/inputs/DataDetailedDropdown";
|
||||||
|
import DataSourceSelector from "../../../ui/inputs/DataSourceSelector";
|
||||||
|
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
|
||||||
|
import { UIElement } from "../../../../types/exportedTypes";
|
||||||
|
|
||||||
|
interface ElementDataProps {
|
||||||
|
element: UIElement | null;
|
||||||
|
selectedBlock: string;
|
||||||
|
selectedElement: string;
|
||||||
|
updateElementData: (blockId: string, elementId: string, updates: Partial<ElementDataBinding>) => void;
|
||||||
|
selectedProduct: any;
|
||||||
|
getEventByModelUuid: (productUuid: string, modelUuid: string) => any;
|
||||||
|
getAssetDropdownItems: () => Array<{ id: string; label: string; icon: JSX.Element }>;
|
||||||
|
getLableValueDropdownItems: (assetId: string | undefined) => Array<{ title: string; items: Array<{ id: string; label: string; icon: JSX.Element }> }>;
|
||||||
|
singleSourceFields: Array<{ id: string; label: string; showEyeDropper: boolean; options: Array<{ id: string; label: string }> }>;
|
||||||
|
singleValueFields: Array<{ id: string; label: string; showEyeDropper: boolean; options: Array<{ id: string; label: string }> }>;
|
||||||
|
multipleSourceFields: Array<{ id: string; label: string; showEyeDropper: boolean; options: Array<{ id: string; label: string }> }>;
|
||||||
|
multipleValueFields: Array<{ id: string; label: string; showEyeDropper: boolean; options: Array<{ id: string; label: string }> }>;
|
||||||
|
selectDataMapping: "singleMachine" | "multipleMachine";
|
||||||
|
handleDataTypeSwitch: (newDataType: "singleMachine" | "multipleMachine") => void;
|
||||||
|
updateDataSource: (blockId: string, elementId: string, dataSource: string | string[]) => void;
|
||||||
|
updateDataValue: (blockId: string, elementId: string, dataValue: string | string[]) => void;
|
||||||
|
updateCommonValue: (blockId: string, elementId: string, commonValue: string) => void;
|
||||||
|
addField?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ElementData: React.FC<ElementDataProps> = ({
|
||||||
|
element,
|
||||||
|
selectedBlock,
|
||||||
|
selectedElement,
|
||||||
|
updateElementData,
|
||||||
|
selectedProduct,
|
||||||
|
getEventByModelUuid,
|
||||||
|
getAssetDropdownItems,
|
||||||
|
getLableValueDropdownItems,
|
||||||
|
singleSourceFields = [],
|
||||||
|
singleValueFields = [],
|
||||||
|
multipleSourceFields = [],
|
||||||
|
multipleValueFields = [],
|
||||||
|
selectDataMapping = "singleMachine",
|
||||||
|
handleDataTypeSwitch,
|
||||||
|
updateDataSource,
|
||||||
|
updateDataValue,
|
||||||
|
updateCommonValue,
|
||||||
|
addField,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div className="data-details">
|
||||||
|
{element?.type === "label-value" && (
|
||||||
|
<>
|
||||||
|
<div className="design-section">
|
||||||
|
<div className="sub-header">Data Handling</div>
|
||||||
|
<InputWithDropDown
|
||||||
|
label="Label"
|
||||||
|
type="string"
|
||||||
|
value={element.dataBinding?.label || ""}
|
||||||
|
placeholder={"Label 1"}
|
||||||
|
onChange={(value) => {
|
||||||
|
updateElementData(selectedBlock, selectedElement, { label: value });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div className="data">
|
||||||
|
<DataDetailedDropdown
|
||||||
|
title="Data Source"
|
||||||
|
placeholder="Select assets"
|
||||||
|
sections={[
|
||||||
|
{
|
||||||
|
title: "Global",
|
||||||
|
items: [{ id: "global", label: "Global", icon: <DeviceIcon /> }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Assets",
|
||||||
|
items: getAssetDropdownItems(),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
value={
|
||||||
|
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: <DeviceIcon />,
|
||||||
|
}
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
onChange={(value) => {
|
||||||
|
updateElementData(selectedBlock, selectedElement, { dataSource: value.id });
|
||||||
|
}}
|
||||||
|
dropDownHeader={"RT-Data"}
|
||||||
|
eyedroper={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="data">
|
||||||
|
<DataDetailedDropdown
|
||||||
|
title="Data Value"
|
||||||
|
placeholder="Select Value"
|
||||||
|
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: <ParametersIcon />,
|
||||||
|
}
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
onChange={(value) => {
|
||||||
|
updateElementData(selectedBlock, selectedElement, { dataValue: value.id, label: value.label });
|
||||||
|
}}
|
||||||
|
dropDownHeader={"RT-Data-Value"}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Data Mapping */}
|
||||||
|
{element?.type === "graph" && (
|
||||||
|
<div className="data-mapping">
|
||||||
|
<div className="heading">Data Mapping</div>
|
||||||
|
|
||||||
|
<div className="type-switch">
|
||||||
|
<div className={`type ${selectDataMapping === "singleMachine" ? "active" : ""}`} onClick={() => handleDataTypeSwitch("singleMachine")}>
|
||||||
|
Single Machine
|
||||||
|
</div>
|
||||||
|
<div className={`type ${selectDataMapping === "multipleMachine" ? "active" : ""}`} onClick={() => handleDataTypeSwitch("multipleMachine")}>
|
||||||
|
Multiple Machine
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{selectDataMapping === "singleMachine" && element.dataBinding?.dataType === "single-machine" && (
|
||||||
|
<div className="fields-wrapper design-section">
|
||||||
|
{singleSourceFields.map((field) => (
|
||||||
|
<DataSourceSelector
|
||||||
|
key={field.id}
|
||||||
|
label={field.label}
|
||||||
|
options={field.options}
|
||||||
|
selected={getEventByModelUuid(selectedProduct.productUuid, element.dataBinding?.dataSource as string)?.modelName ?? ""}
|
||||||
|
onSelect={(value) => {
|
||||||
|
updateDataSource(selectedBlock, selectedElement, value.id);
|
||||||
|
}}
|
||||||
|
showEyeDropper={field.showEyeDropper}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{/* add delete */}
|
||||||
|
{singleValueFields.map((field, index) => (
|
||||||
|
<DataSourceSelector
|
||||||
|
key={field.id}
|
||||||
|
label={field.label}
|
||||||
|
options={field.options}
|
||||||
|
selected={field.options.find((option) => option.id === element.dataBinding?.dataValue?.[index])?.label ?? ""}
|
||||||
|
onSelect={(value) => {
|
||||||
|
const currentDataValue = Array.isArray(element.dataBinding?.dataValue)
|
||||||
|
? element.dataBinding!.dataValue
|
||||||
|
: element.dataBinding?.dataValue
|
||||||
|
? [element.dataBinding.dataValue]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const newDataValue = [...currentDataValue];
|
||||||
|
newDataValue[index] = value.id;
|
||||||
|
|
||||||
|
updateDataValue(selectedBlock, selectedElement, newDataValue);
|
||||||
|
}}
|
||||||
|
showEyeDropper={field.showEyeDropper}
|
||||||
|
showDeleteBtn={true}
|
||||||
|
onDelete={() => {
|
||||||
|
const current = Array.isArray(element.dataBinding?.dataValue)
|
||||||
|
? element.dataBinding!.dataValue
|
||||||
|
: element.dataBinding?.dataValue
|
||||||
|
? [element.dataBinding.dataValue]
|
||||||
|
: [];
|
||||||
|
const next = [...current];
|
||||||
|
next.splice(index, 1);
|
||||||
|
updateDataValue(selectedBlock, selectedElement, next);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<div className="add-field" onClick={addField}>
|
||||||
|
<div className="icon">
|
||||||
|
<AddIcon />
|
||||||
|
</div>
|
||||||
|
<div className="label">Add Field</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{selectDataMapping === "multipleMachine" && element.dataBinding?.dataType === "multiple-machine" && (
|
||||||
|
<div className="fields-wrapper design-section">
|
||||||
|
{multipleValueFields.map((field) => (
|
||||||
|
<DataSourceSelector
|
||||||
|
key={field.id}
|
||||||
|
label={field.label}
|
||||||
|
options={field.options}
|
||||||
|
selected={field.options.find((o) => o.id === element.dataBinding?.commonValue)?.label ?? ""}
|
||||||
|
onSelect={(value) => {
|
||||||
|
updateCommonValue(selectedBlock, selectedElement, value.id);
|
||||||
|
}}
|
||||||
|
showEyeDropper={field.showEyeDropper}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{/* add delete */}
|
||||||
|
{multipleSourceFields.map((field, index) => (
|
||||||
|
<DataSourceSelector
|
||||||
|
key={field.id}
|
||||||
|
label={field.label}
|
||||||
|
options={field.options}
|
||||||
|
selected={getEventByModelUuid(selectedProduct.productUuid, (element.dataBinding?.dataSource as string[])?.[index] || "")?.modelName ?? ""}
|
||||||
|
onSelect={(value) => {
|
||||||
|
const current = Array.isArray(element.dataBinding?.dataSource)
|
||||||
|
? element.dataBinding!.dataSource
|
||||||
|
: element.dataBinding?.dataSource
|
||||||
|
? [element.dataBinding.dataSource]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const next = [...current];
|
||||||
|
next[index] = value.id;
|
||||||
|
|
||||||
|
updateDataSource(selectedBlock, selectedElement, next);
|
||||||
|
}}
|
||||||
|
showEyeDropper={field.showEyeDropper}
|
||||||
|
showDeleteBtn={true}
|
||||||
|
onDelete={() => {
|
||||||
|
const current = Array.isArray(element.dataBinding?.dataSource)
|
||||||
|
? element.dataBinding!.dataSource
|
||||||
|
: element.dataBinding?.dataSource
|
||||||
|
? [element.dataBinding.dataSource]
|
||||||
|
: [];
|
||||||
|
const next = [...current];
|
||||||
|
next.splice(index, 1);
|
||||||
|
updateDataSource(selectedBlock, selectedElement, next);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<div className="add-field" onClick={addField}>
|
||||||
|
<div className="icon">
|
||||||
|
<AddIcon />
|
||||||
|
</div>
|
||||||
|
<div className="label">Add Field</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ElementData;
|
||||||
@@ -1,14 +1,10 @@
|
|||||||
import { useCallback, useMemo, useState, useRef, useEffect, type RefObject } from "react";
|
import { useCallback, useMemo, useState, useRef, useEffect, type RefObject } from "react";
|
||||||
import { ExtendedCSSProperties, UIElement } from "../../../../types/exportedTypes";
|
import { ExtendedCSSProperties, UIElement } from "../../../../types/exportedTypes";
|
||||||
import { DeleteIcon } from "../../../icons/ContextMenuIcons";
|
import { DeleteIcon } from "../../../icons/ContextMenuIcons";
|
||||||
import DataSourceSelector from "../../../ui/inputs/DataSourceSelector";
|
import { DeviceIcon, ParametersIcon, ResizeHeightIcon } from "../../../icons/ExportCommonIcons";
|
||||||
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
|
|
||||||
import InputRange from "../../../ui/inputs/InputRange";
|
|
||||||
import RenameInput from "../../../ui/inputs/RenameInput";
|
|
||||||
import { AddIcon, DeviceIcon, ParametersIcon, ResizeHeightIcon } from "../../../icons/ExportCommonIcons";
|
|
||||||
import DataDetailedDropdown from "../../../ui/inputs/DataDetailedDropdown";
|
|
||||||
import { useSceneContext } from "../../../../modules/scene/sceneContext";
|
import { useSceneContext } from "../../../../modules/scene/sceneContext";
|
||||||
import ElementDesign from "./ElementDesign";
|
import ElementDesign from "./ElementDesign";
|
||||||
|
import ElementData from "./ElementData";
|
||||||
import { useVisualizationStore } from "../../../../store/visualization/useVisualizationStore";
|
import { useVisualizationStore } from "../../../../store/visualization/useVisualizationStore";
|
||||||
|
|
||||||
interface ElementEditorProps {
|
interface ElementEditorProps {
|
||||||
@@ -60,7 +56,9 @@ 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.dataBinding?.dataType === "multiple-machine" ? "multipleMachine" : "singleMachine");
|
const [selectDataMapping, setSelectDataMapping] = useState<"singleMachine" | "multipleMachine">(
|
||||||
|
element?.type === "graph" && element.dataBinding?.dataType === "multiple-machine" ? "multipleMachine" : "singleMachine"
|
||||||
|
);
|
||||||
|
|
||||||
// Use shared position from VisualizationStore
|
// Use shared position from VisualizationStore
|
||||||
const { editorPosition, setEditorPosition } = useVisualizationStore();
|
const { editorPosition, setEditorPosition } = useVisualizationStore();
|
||||||
@@ -573,210 +571,26 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{selectType === "data" && (
|
{selectType === "data" && (
|
||||||
<div className="data-details">
|
<ElementData
|
||||||
{element?.type === "label-value" && (
|
element={element || null}
|
||||||
<>
|
selectedBlock={selectedBlock}
|
||||||
<div className="design-section">
|
selectedElement={selectedElement}
|
||||||
<div className="sub-header">Data Handling</div>
|
updateElementData={updateElementData}
|
||||||
<InputWithDropDown
|
selectedProduct={selectedProduct}
|
||||||
label="Label"
|
getEventByModelUuid={getEventByModelUuid}
|
||||||
type="string"
|
getAssetDropdownItems={getAssetDropdownItems}
|
||||||
value={element.dataBinding?.label || ""}
|
getLableValueDropdownItems={getLableValueDropdownItems}
|
||||||
placeholder={"Label 1"}
|
singleSourceFields={singleSourceFields}
|
||||||
onChange={(value) => {
|
singleValueFields={singleValueFields}
|
||||||
updateElementData(selectedBlock, selectedElement, { label: value });
|
multipleSourceFields={multipleSourceFields}
|
||||||
}}
|
multipleValueFields={multipleValueFields}
|
||||||
/>
|
selectDataMapping={selectDataMapping}
|
||||||
<div className="data">
|
handleDataTypeSwitch={handleDataTypeSwitch}
|
||||||
<DataDetailedDropdown
|
updateDataSource={updateDataSource}
|
||||||
title="Data Source"
|
updateDataValue={updateDataValue}
|
||||||
placeholder="Select assets"
|
updateCommonValue={updateCommonValue}
|
||||||
sections={[
|
addField={addField}
|
||||||
{
|
/>
|
||||||
title: "Global",
|
|
||||||
items: [{ id: "global", label: "Global", icon: <DeviceIcon /> }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Assets",
|
|
||||||
items: getAssetDropdownItems(),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
value={
|
|
||||||
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: <DeviceIcon />,
|
|
||||||
}
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
onChange={(value) => {
|
|
||||||
updateElementData(selectedBlock, selectedElement, { dataSource: value.id });
|
|
||||||
}}
|
|
||||||
dropDownHeader={"RT-Data"}
|
|
||||||
eyedroper={true}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="data">
|
|
||||||
<DataDetailedDropdown
|
|
||||||
title="Data Value"
|
|
||||||
placeholder="Select Value"
|
|
||||||
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: <ParametersIcon />,
|
|
||||||
}
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
onChange={(value) => {
|
|
||||||
updateElementData(selectedBlock, selectedElement, { dataValue: value.id, label: value.label });
|
|
||||||
}}
|
|
||||||
dropDownHeader={"RT-Data-Value"}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Data Mapping */}
|
|
||||||
{element?.type === "graph" && (
|
|
||||||
<div className="data-mapping">
|
|
||||||
<div className="heading">Data Mapping</div>
|
|
||||||
|
|
||||||
<div className="type-switch">
|
|
||||||
<div className={`type ${selectDataMapping === "singleMachine" ? "active" : ""}`} onClick={() => handleDataTypeSwitch("singleMachine")}>
|
|
||||||
Single Machine
|
|
||||||
</div>
|
|
||||||
<div className={`type ${selectDataMapping === "multipleMachine" ? "active" : ""}`} onClick={() => handleDataTypeSwitch("multipleMachine")}>
|
|
||||||
Multiple Machine
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{selectDataMapping === "singleMachine" && element.dataBinding?.dataType === "single-machine" && (
|
|
||||||
<div className="fields-wrapper design-section">
|
|
||||||
{singleSourceFields.map((field) => (
|
|
||||||
<DataSourceSelector
|
|
||||||
key={field.id}
|
|
||||||
label={field.label}
|
|
||||||
options={field.options}
|
|
||||||
selected={getEventByModelUuid(selectedProduct.productUuid, element.dataBinding?.dataSource as string)?.modelName ?? ""}
|
|
||||||
onSelect={(value) => {
|
|
||||||
updateDataSource(selectedBlock, selectedElement, value.id);
|
|
||||||
}}
|
|
||||||
showEyeDropper={field.showEyeDropper}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
{/* add delete */}
|
|
||||||
{singleValueFields.map((field, index) => (
|
|
||||||
<DataSourceSelector
|
|
||||||
key={field.id}
|
|
||||||
label={field.label}
|
|
||||||
options={field.options}
|
|
||||||
selected={field.options.find((option) => option.id === element.dataBinding?.dataValue?.[index])?.label ?? ""}
|
|
||||||
onSelect={(value) => {
|
|
||||||
const currentDataValue = Array.isArray(element.dataBinding?.dataValue)
|
|
||||||
? element.dataBinding!.dataValue
|
|
||||||
: element.dataBinding?.dataValue
|
|
||||||
? [element.dataBinding.dataValue]
|
|
||||||
: [];
|
|
||||||
|
|
||||||
const newDataValue = [...currentDataValue];
|
|
||||||
newDataValue[index] = value.id;
|
|
||||||
|
|
||||||
updateDataValue(selectedBlock, selectedElement, newDataValue);
|
|
||||||
}}
|
|
||||||
showEyeDropper={field.showEyeDropper}
|
|
||||||
showDeleteBtn={true}
|
|
||||||
onDelete={() => {
|
|
||||||
const current = Array.isArray(element.dataBinding?.dataValue)
|
|
||||||
? element.dataBinding!.dataValue
|
|
||||||
: element.dataBinding?.dataValue
|
|
||||||
? [element.dataBinding.dataValue]
|
|
||||||
: [];
|
|
||||||
const next = [...current];
|
|
||||||
next.splice(index, 1);
|
|
||||||
updateDataValue(selectedBlock, selectedElement, next);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
|
|
||||||
<div className="add-field" onClick={addField}>
|
|
||||||
<div className="icon">
|
|
||||||
<AddIcon />
|
|
||||||
</div>
|
|
||||||
<div className="label">Add Field</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{selectDataMapping === "multipleMachine" && element.dataBinding?.dataType === "multiple-machine" && (
|
|
||||||
<div className="fields-wrapper design-section">
|
|
||||||
{multipleValueFields.map((field) => (
|
|
||||||
<DataSourceSelector
|
|
||||||
key={field.id}
|
|
||||||
label={field.label}
|
|
||||||
options={field.options}
|
|
||||||
selected={field.options.find((o) => o.id === element.dataBinding?.commonValue)?.label ?? ""}
|
|
||||||
onSelect={(value) => {
|
|
||||||
updateCommonValue(selectedBlock, selectedElement, value.id);
|
|
||||||
}}
|
|
||||||
showEyeDropper={field.showEyeDropper}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
{/* add delete */}
|
|
||||||
{multipleSourceFields.map((field, index) => (
|
|
||||||
<DataSourceSelector
|
|
||||||
key={field.id}
|
|
||||||
label={field.label}
|
|
||||||
options={field.options}
|
|
||||||
selected={getEventByModelUuid(selectedProduct.productUuid, (element.dataBinding?.dataSource as string[])?.[index] || "")?.modelName ?? ""}
|
|
||||||
onSelect={(value) => {
|
|
||||||
const current = Array.isArray(element.dataBinding?.dataSource)
|
|
||||||
? element.dataBinding!.dataSource
|
|
||||||
: element.dataBinding?.dataSource
|
|
||||||
? [element.dataBinding.dataSource]
|
|
||||||
: [];
|
|
||||||
|
|
||||||
const next = [...current];
|
|
||||||
next[index] = value.id;
|
|
||||||
|
|
||||||
updateDataSource(selectedBlock, selectedElement, next);
|
|
||||||
}}
|
|
||||||
showEyeDropper={field.showEyeDropper}
|
|
||||||
showDeleteBtn={true}
|
|
||||||
onDelete={() => {
|
|
||||||
const current = Array.isArray(element.dataBinding?.dataSource)
|
|
||||||
? element.dataBinding!.dataSource
|
|
||||||
: element.dataBinding?.dataSource
|
|
||||||
? [element.dataBinding.dataSource]
|
|
||||||
: [];
|
|
||||||
const next = [...current];
|
|
||||||
next.splice(index, 1);
|
|
||||||
updateDataSource(selectedBlock, selectedElement, next);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
|
|
||||||
<div className="add-field" onClick={addField}>
|
|
||||||
<div className="icon">
|
|
||||||
<AddIcon />
|
|
||||||
</div>
|
|
||||||
<div className="label">Add Field</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ function Models({ loader }: { readonly loader: GLTFLoader }) {
|
|||||||
const { controls, camera } = useThree();
|
const { controls, camera } = useThree();
|
||||||
const assetGroupRef = useRef<Group>(null);
|
const assetGroupRef = useRef<Group>(null);
|
||||||
const { assetStore, layout } = useSceneContext();
|
const { assetStore, layout } = useSceneContext();
|
||||||
const { assets, selectedAssets, getSelectedAssetUuids } = assetStore();
|
const { assets, selectedAssets, getSelectedAssetUuids, clearSelectedAssets } = assetStore();
|
||||||
const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
|
const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
|
||||||
const { contextAction, setContextAction } = useContextActionStore();
|
const { contextAction, setContextAction } = useContextActionStore();
|
||||||
const { limitDistance } = useLimitDistance();
|
const { limitDistance } = useLimitDistance();
|
||||||
@@ -126,6 +126,7 @@ function Models({ loader }: { readonly loader: GLTFLoader }) {
|
|||||||
if (selectedAssets.length > 0) {
|
if (selectedAssets.length > 0) {
|
||||||
const target = (controls as CameraControls).getTarget(new Vector3());
|
const target = (controls as CameraControls).getTarget(new Vector3());
|
||||||
(controls as CameraControls).setTarget(target.x, 0, target.z, true);
|
(controls as CameraControls).setTarget(target.x, 0, target.z, true);
|
||||||
|
clearSelectedAssets();
|
||||||
}
|
}
|
||||||
if (selectedAsset) {
|
if (selectedAsset) {
|
||||||
clearSelectedAsset();
|
clearSelectedAsset();
|
||||||
|
|||||||
Reference in New Issue
Block a user