Skip to content

Commit

Permalink
Implemented: Make changing the "Name" property more easy #626
Browse files Browse the repository at this point in the history
  • Loading branch information
mvladic committed Nov 8, 2024
1 parent 683d0e8 commit 9804d22
Show file tree
Hide file tree
Showing 3 changed files with 239 additions and 98 deletions.
8 changes: 7 additions & 1 deletion packages/project-editor/lvgl/identifiers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -180,7 +186,7 @@ export class LVGLIdentifiers {
}

return identifiers.find(
lvglIdentifier => lvglIdentifier.identifier == displayName
lvglIdentifier => lvglIdentifier.identifier == identifierName
);
}

Expand Down
104 changes: 7 additions & 97 deletions packages/project-editor/ui-components/PropertyGrid/Property.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -52,6 +48,7 @@ import { Checkbox } from "./Checkbox";
import { ImageProperty } from "./ImageProperty";

import { General } from "project-editor/project/project";
import { UniqueValueInput } from "./UniqueValueInput";

////////////////////////////////////////////////////////////////////////////////

Expand Down Expand Up @@ -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());
};
Expand Down Expand Up @@ -572,22 +493,11 @@ export const Property = observer(
(propertyInfo.unique || propertyInfo.uniqueIdentifier)
) {
return (
<div className="input-group">
<input
ref={(ref: any) => (this.input = ref)}
type="text"
className="form-control"
value={this._value || ""}
readOnly
/>
<button
className="btn btn-secondary"
type="button"
onClick={this.onEditUnique}
>
&hellip;
</button>
</div>
<UniqueValueInput
{...this.props}
value={this._value}
changeValue={this.changeValue}
/>
);
} else if (propertyInfo.type === PropertyType.MultilineText) {
if (!readOnly && isOnSelectAvailable) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<typeof ProjectContext>;

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<HTMLInputElement>) => {
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 (
<>
<div className="input-group">
<input
type="text"
className="form-control"
value={
this._value != undefined
? this._value
: this.props.value || ""
}
onChange={this.onChange}
onKeyDown={this.onKeyDown}
onBlur={this.onBlur}
readOnly={this.props.objects.length > 1}
/>
{this._value != undefined && (
<>
<button
className="btn btn-secondary"
type="button"
onClick={this.onOK}
title={"Commit Change (ENTER)"}
>
<Icon icon="material:check" size={16} />
</button>
<button
className="btn btn-secondary"
type="button"
onClick={this.onCancel}
title={"Discard Change (ESC)"}
>
<Icon icon="material:close" size={16} />
</button>
</>
)}
</div>
{this.error && (
<div className="form-text error">{this.error}</div>
)}
</>
);
}
}
);

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;
}

0 comments on commit 9804d22

Please sign in to comment.