diff --git a/packages/project-editor/lvgl/identifiers.ts b/packages/project-editor/lvgl/identifiers.ts index 7af31ed6..86106a3e 100644 --- a/packages/project-editor/lvgl/identifiers.ts +++ b/packages/project-editor/lvgl/identifiers.ts @@ -165,6 +165,12 @@ export class LVGLIdentifiers { flow: Flow, displayName: string ): LVGLIdentifier | undefined { + const identifierName = getName( + "", + displayName, + NamingConvention.UnderscoreLowerCase + ); + let identifiers = this.getIdentifiersVisibleFromFlow(flow); if (!identifiers) { @@ -180,7 +186,7 @@ export class LVGLIdentifiers { } return identifiers.find( - lvglIdentifier => lvglIdentifier.identifier == displayName + lvglIdentifier => lvglIdentifier.identifier == identifierName ); } diff --git a/packages/project-editor/ui-components/PropertyGrid/Property.tsx b/packages/project-editor/ui-components/PropertyGrid/Property.tsx index dce091c1..b84587f0 100644 --- a/packages/project-editor/ui-components/PropertyGrid/Property.tsx +++ b/packages/project-editor/ui-components/PropertyGrid/Property.tsx @@ -6,24 +6,20 @@ import { dialog } from "@electron/remote"; import { guid } from "eez-studio-shared/guid"; import { humanize } from "eez-studio-shared/string"; -import { validators, filterNumber } from "eez-studio-shared/validation"; -import { validators as validatorsRenderer } from "eez-studio-shared/validation-renderer"; +import { filterNumber } from "eez-studio-shared/validation"; import { confirm } from "eez-studio-ui/dialog-electron"; -import { showGenericDialog } from "eez-studio-ui/generic-dialog"; import { Icon } from "eez-studio-ui/icon"; import { PropertyType, PropertyProps, - getParent, getObjectPropertyDisplayName, isPropertyOptional, EnumItem } from "project-editor/core/object"; import { info } from "project-editor/core/util"; -import { replaceObjectReference } from "project-editor/core/search"; import { ConfigurationReferencesPropertyValue } from "project-editor/ui-components/ConfigurationReferencesPropertyValue"; @@ -52,6 +48,7 @@ import { Checkbox } from "./Checkbox"; import { ImageProperty } from "./ImageProperty"; import { General } from "project-editor/project/project"; +import { UniqueValueInput } from "./UniqueValueInput"; //////////////////////////////////////////////////////////////////////////////// @@ -393,82 +390,6 @@ export const Property = observer( ); }; - onEditUnique = () => { - const propertyInfoUnique = (this.props.propertyInfo.unique || - this.props.propertyInfo.uniqueIdentifier)!; - - showGenericDialog({ - dialogDefinition: { - fields: [ - { - name: this.props.propertyInfo.name, - displayName: getObjectPropertyDisplayName( - this.props.objects[0], - this.props.propertyInfo - ), - type: "string", - validators: [ - typeof propertyInfoUnique === "boolean" - ? validators.unique( - this.props.objects[0], - getParent(this.props.objects[0]) - ) - : propertyInfoUnique( - this.props.objects[0], - getParent(this.props.objects[0]), - this.props.propertyInfo - ) - ] - .concat( - isPropertyOptional( - this.props.objects[0], - this.props.propertyInfo - ) - ? [] - : [validators.required] - ) - .concat( - this.props.propertyInfo.uniqueIdentifier - ? [ - validatorsRenderer.identifierValidator - ] - : [] - ) - } - ] - }, - values: this.props.objects[0] - }) - .then(result => { - let oldValue = this._value; - let newValue = - result.values[this.props.propertyInfo.name].trim(); - if (newValue.length === 0) { - newValue = undefined; - } - if (newValue != oldValue) { - this.context.undoManager.setCombineCommands(true); - - console.log("Change unique value", oldValue, newValue); - - runInAction(() => { - replaceObjectReference( - this.props.objects[0], - newValue - ); - this.changeValue(newValue); - }); - - this.context.undoManager.setCombineCommands(false); - } - }) - .catch(error => { - if (error !== undefined) { - console.error(error); - } - }); - }; - onGenerateGuid = () => { this.changeValue(guid()); }; @@ -572,22 +493,11 @@ export const Property = observer( (propertyInfo.unique || propertyInfo.uniqueIdentifier) ) { return ( -
- (this.input = ref)} - type="text" - className="form-control" - value={this._value || ""} - readOnly - /> - -
+ ); } else if (propertyInfo.type === PropertyType.MultilineText) { if (!readOnly && isOnSelectAvailable) { diff --git a/packages/project-editor/ui-components/PropertyGrid/UniqueValueInput.tsx b/packages/project-editor/ui-components/PropertyGrid/UniqueValueInput.tsx new file mode 100644 index 00000000..542d2879 --- /dev/null +++ b/packages/project-editor/ui-components/PropertyGrid/UniqueValueInput.tsx @@ -0,0 +1,225 @@ +import React from "react"; +import { observable, action, runInAction, makeObservable } from "mobx"; +import { observer } from "mobx-react"; + +import { getParent, PropertyProps } from "project-editor/core/object"; + +import { ProjectContext } from "project-editor/project/context"; + +import { validators } from "eez-studio-shared/validation"; +import { validators as validatorsRenderer } from "eez-studio-shared/validation-renderer"; + +import { isPropertyOptional } from "project-editor/core/object"; +import { replaceObjectReference } from "project-editor/core/search"; +import { Icon } from "eez-studio-ui/icon"; + +//////////////////////////////////////////////////////////////////////////////// + +export const UniqueValueInput = observer( + class UniqueValueInput extends React.Component< + PropertyProps & { value: any; changeValue: (newValue: any) => void } + > { + static contextType = ProjectContext; + declare context: React.ContextType; + + oldValue: any; + _value: string | undefined; + error: string | undefined = undefined; + + constructor(props: any) { + super(props); + + makeObservable(this, { + _value: observable, + error: observable + }); + } + + componentDidUpdate(prevProps: PropertyProps) { + if ( + !arrayCompareShallow(prevProps.objects, this.props.objects) || + prevProps.propertyInfo != this.props.propertyInfo || + this.oldValue != this.props.value + ) { + this.resetChange(); + } + } + + onChange = action((event: React.ChangeEvent) => { + this.oldValue = this.props.value; + this._value = event.target.value.toString(); + this.error = undefined; + }); + + onKeyDown = (event: React.KeyboardEvent) => { + if (event.key === "Enter") { + this.commitChange(); + } else if (event.key == "Escape") { + this.discardChange(); + } + }; + + onOK = () => { + this.commitChange(); + }; + + onCancel = () => { + this.discardChange(); + }; + + onBlur = (event: React.FocusEvent) => {}; + + resetChange() { + runInAction(() => { + this._value = undefined; + this.error = undefined; + }); + } + + discardChange() { + this.resetChange(); + } + + commitChange = async () => { + if (this._value == undefined) { + return; + } + + let newValue = this._value.trim(); + + const valueValidators = []; + + const propertyInfoUnique = (this.props.propertyInfo.unique || + this.props.propertyInfo.uniqueIdentifier)!; + if (typeof propertyInfoUnique === "boolean") { + valueValidators.push( + validators.unique( + this.props.objects[0], + getParent(this.props.objects[0]) + ) + ); + } else { + valueValidators.push( + propertyInfoUnique( + this.props.objects[0], + getParent(this.props.objects[0]), + this.props.propertyInfo + ) + ); + } + + if ( + !isPropertyOptional( + this.props.objects[0], + this.props.propertyInfo + ) + ) { + valueValidators.push(validators.required); + } + + if (this.props.propertyInfo.uniqueIdentifier) { + valueValidators.push(validatorsRenderer.identifierValidator); + } + + for (const valueValidator of valueValidators) { + const error = await valueValidator( + { + [this.props.propertyInfo.name]: newValue + }, + this.props.propertyInfo.name + ); + + if (error) { + runInAction(() => { + this.error = error; + }); + return; + } + } + + let oldValue = this.props.value; + + if (newValue != oldValue) { + if (newValue.length == 0) { + runInAction(() => { + this.props.changeValue(undefined); + }); + } else { + this.context.undoManager.setCombineCommands(true); + + runInAction(() => { + replaceObjectReference(this.props.objects[0], newValue); + this.props.changeValue(newValue); + }); + + this.context.undoManager.setCombineCommands(false); + } + } + + this.resetChange(); + }; + + render() { + return ( + <> +
+ 1} + /> + {this._value != undefined && ( + <> + + + + )} +
+ {this.error && ( +
{this.error}
+ )} + + ); + } + } +); + +function arrayCompareShallow(arr1: any, arr2: any) { + if (!arr1 && !arr2) { + return true; + } + + if ((!arr1 && arr2) || (arr1 && !arr2) || arr1.length != arr2.length) { + return false; + } + + for (let i = 0; i < arr1.length; i++) { + if (arr1[i] != arr2[i]) { + return false; + } + } + + return true; +}