diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html index 256f6e7f9f..0a757fd34f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html @@ -85,6 +85,39 @@ {{key.label}} +
+ + {{key.label}} + + + {{key.settings.icon}} + + icon + + + + + {{ getErrorMessageText(key.settings,'required') }} + + + {{ getErrorMessageText(key.settings,'invalidJSON') | translate }} + + +
any; @@ -90,6 +95,7 @@ interface MultipleInputWidgetDataKeySettings { invalidDateErrorMessage?: string; minValueErrorMessage?: string; maxValueErrorMessage?: string; + invalidJsonErrorMessage?: string; useCustomIcon: boolean; icon: string; customIcon: string ; @@ -103,6 +109,9 @@ interface MultipleInputWidgetDataKeySettings { useSetValueFunction?: boolean; setValueFunctionBody?: string; setValueFunction?: ConvertSetValueFunction; + dialogTitle?: string; + saveButtonLabel?: string; + cancelButtonLabel?: string; } interface MultipleInputWidgetDataKey extends DataKey { @@ -161,7 +170,8 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni private fb: UntypedFormBuilder, private attributeService: AttributeService, private translate: TranslateService, - private sanitizer: DomSanitizer) { + private sanitizer: DomSanitizer, + private dialog: MatDialog) { super(store); } @@ -425,6 +435,13 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni case 'select': value = keyValue !== null ? keyValue.toString() : null; break; + case 'JSON': + try { + value = JSON.parse(keyValue); + } catch (e) { + value = keyValue ? keyValue : null; + } + break; default: value = keyValue; } @@ -520,6 +537,10 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni errorMessage = keySettings.invalidDateErrorMessage; defaultMessage = 'widgets.input-widgets.invalid-date'; break; + case 'invalidJSON': + errorMessage = keySettings.invalidJsonErrorMessage; + defaultMessage = 'widgets.input-widgets.json-invalid'; + break; default: return ''; } @@ -670,8 +691,8 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni } }); if (tasks.length) { - forkJoin(tasks).subscribe( - () => { + forkJoin(tasks).subscribe({ + next: () => { this.multipleInputFormGroup.markAsPristine(); this.ctx.detectChanges(); this.isSavingInProgress = false; @@ -680,13 +701,13 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni 1000, 'bottom', 'left', this.toastTargetId); } }, - () => { + error: () => { this.isSavingInProgress = false; if (this.settings.showResultMessage) { this.ctx.showErrorToast(this.translate.instant('widgets.input-widgets.update-failed'), 'bottom', 'left', this.toastTargetId); } - }); + }}); } else { this.multipleInputFormGroup.markAsPristine(); this.ctx.detectChanges(); @@ -718,4 +739,31 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni }); this.multipleInputFormGroup.markAsPristine(); } + + openEditJSONDialog($event: Event, key: MultipleInputWidgetDataKey, source: MultipleInputWidgetSource) { + if ($event) { + $event.stopPropagation(); + } + const formControl = this.multipleInputFormGroup.controls[key.formId]; + this.dialog.open(JsonObjectEditDialogComponent, { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: { + jsonValue: formControl.value, + title: key.settings.dialogTitle, + saveLabel: key.settings.saveButtonLabel, + cancelLabel: key.settings.cancelButtonLabel + } + }).afterClosed().subscribe( + (res) => { + if (!isEqual(res, formControl.value)) { + formControl.patchValue(res); + formControl.markAsDirty(); + if(!this.settings.showActionButtons) { + this.inputChanged(source, key); + } + } + } + ); + } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.html index 186583d5c1..3c62810000 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.html @@ -66,6 +66,9 @@ {{ 'widgets.input-widgets.datakey-value-type-select' | translate }} + + {{ 'widgets.input-widgets.datakey-value-type-json' | translate }} + @@ -179,6 +182,28 @@ widgets.input-widgets.invalid-date-error-message + + widgets.input-widgets.invalid-JSON-error-message + + + +
+ widgets.input-widgets.dialog-editor-settings + + widgets.input-widgets.title + + +
+ + widgets.input-widgets.save-button-label + + + + widgets.input-widgets.cancel-button-label + + +
widgets.input-widgets.icon-settings diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.ts index 56ab12605d..7eff1bdc80 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.ts @@ -24,6 +24,7 @@ import { dataKeySelectOptionValidator } from '@home/components/widget/lib/settings/input/datakey-select-option.component'; import { CdkDragDrop } from '@angular/cdk/drag-drop'; +import { MultipleInputWidgetDataKeyValueType } from '@home/components/widget/lib/multiple-input-widget.component'; @Component({ selector: 'tb-update-multiple-attributes-key-settings', @@ -62,6 +63,11 @@ export class UpdateMultipleAttributesKeySettingsComponent extends WidgetSettings minValueErrorMessage: '', maxValueErrorMessage: '', invalidDateErrorMessage: '', + invalidJsonErrorMessage: '', + + dialogTitle: '', + saveButtonLabel: '', + cancelButtonLabel: '', useCustomIcon: false, icon: '', @@ -107,6 +113,13 @@ export class UpdateMultipleAttributesKeySettingsComponent extends WidgetSettings minValueErrorMessage: [settings.minValueErrorMessage, []], maxValueErrorMessage: [settings.maxValueErrorMessage, []], invalidDateErrorMessage: [settings.invalidDateErrorMessage, []], + invalidJsonErrorMessage: [settings.invalidJsonErrorMessage, []], + + // Dialog settings + + dialogTitle: [settings.dialogTitle, []], + saveButtonLabel: [settings.saveButtonLabel, []], + cancelButtonLabel: [settings.cancelButtonLabel, []], // Icon settings @@ -130,7 +143,8 @@ export class UpdateMultipleAttributesKeySettingsComponent extends WidgetSettings protected updateValidators(emitEvent: boolean) { const dataKeyHidden: boolean = this.updateMultipleAttributesKeySettingsForm.get('dataKeyHidden').value; - const dataKeyValueType: string = this.updateMultipleAttributesKeySettingsForm.get('dataKeyValueType').value; + const dataKeyValueType: MultipleInputWidgetDataKeyValueType = + this.updateMultipleAttributesKeySettingsForm.get('dataKeyValueType').value; const required: boolean = this.updateMultipleAttributesKeySettingsForm.get('required').value; const isEditable: string = this.updateMultipleAttributesKeySettingsForm.get('isEditable').value; const useCustomIcon: boolean = this.updateMultipleAttributesKeySettingsForm.get('useCustomIcon').value; @@ -165,6 +179,11 @@ export class UpdateMultipleAttributesKeySettingsComponent extends WidgetSettings this.updateMultipleAttributesKeySettingsForm.get('maxValueErrorMessage').enable({emitEvent: false}); } else if (dataKeyValueType === 'dateTime' || dataKeyValueType === 'date' || dataKeyValueType === 'time') { this.updateMultipleAttributesKeySettingsForm.get('invalidDateErrorMessage').enable({emitEvent: false}); + } else if (dataKeyValueType === 'JSON') { + this.updateMultipleAttributesKeySettingsForm.get('invalidJsonErrorMessage').enable({emitEvent: false}); + this.updateMultipleAttributesKeySettingsForm.get('dialogTitle').enable({emitEvent: false}); + this.updateMultipleAttributesKeySettingsForm.get('saveButtonLabel').enable({emitEvent: false}); + this.updateMultipleAttributesKeySettingsForm.get('cancelButtonLabel').enable({emitEvent: false}); } if (required) { this.updateMultipleAttributesKeySettingsForm.get('requiredErrorMessage').enable({emitEvent: false}); @@ -243,8 +262,9 @@ export class UpdateMultipleAttributesKeySettingsComponent extends WidgetSettings displayErrorMessagesSection(): boolean { const dataKeyHidden: boolean = this.updateMultipleAttributesKeySettingsForm.get('dataKeyHidden').value; const required: boolean = this.updateMultipleAttributesKeySettingsForm.get('required').value; - const dataKeyValueType: string = this.updateMultipleAttributesKeySettingsForm.get('dataKeyValueType').value; - return !dataKeyHidden && (required || (['integer', 'double', 'dateTime', 'date', 'time'].includes(dataKeyValueType))); + const dataKeyValueType: MultipleInputWidgetDataKeyValueType = + this.updateMultipleAttributesKeySettingsForm.get('dataKeyValueType').value; + return !dataKeyHidden && (required || (['integer', 'double', 'dateTime', 'date', 'time', 'JSON'].includes(dataKeyValueType))); } } diff --git a/ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.html b/ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.html index a4096da67c..141979d8ff 100644 --- a/ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.html +++ b/ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.html @@ -45,12 +45,12 @@ type="button" [disabled]="(isLoading$ | async)" (click)="cancel()" cdkFocusInitial> - {{ 'action.cancel' | translate }} + {{ cancelButtonLabel }}
diff --git a/ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.ts b/ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.ts index b1ca78b78a..e55431a327 100644 --- a/ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.ts +++ b/ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.ts @@ -14,18 +14,21 @@ /// limitations under the License. /// -import { Component, Inject, OnInit } from '@angular/core'; +import { Component, Inject } from '@angular/core'; import { DialogComponent } from '@shared/components/dialog.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { Router } from '@angular/router'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { FormBuilder, FormGroup } from '@angular/forms'; import { TranslateService } from '@ngx-translate/core'; +import { isNotEmptyStr } from '@core/utils'; export interface JsonObjectEditDialogData { jsonValue: object; title?: string; + saveLabel?: string; + cancelLabel?: string; } @Component({ @@ -33,24 +36,29 @@ export interface JsonObjectEditDialogData { templateUrl: './json-object-edit-dialog.component.html', styleUrls: [] }) -export class JsonObjectEditDialogComponent extends DialogComponent implements OnInit { +export class JsonObjectEditDialogComponent extends DialogComponent { - jsonFormGroup: UntypedFormGroup; - title: string; - - submitted = false; + jsonFormGroup: FormGroup; + title = this.translate.instant('details.edit-json'); + saveButtonLabel = this.translate.instant('action.save'); + cancelButtonLabel = this.translate.instant('action.cancel'); constructor(protected store: Store, protected router: Router, @Inject(MAT_DIALOG_DATA) public data: JsonObjectEditDialogData, public dialogRef: MatDialogRef, - public fb: UntypedFormBuilder, + public fb: FormBuilder, private translate: TranslateService) { super(store, router, dialogRef); - } - - ngOnInit(): void { - this.title = this.data.title ? this.data.title : this.translate.instant('details.edit-json'); + if (isNotEmptyStr(this.data.title)) { + this.title = this.data.title; + } + if (isNotEmptyStr(this.data.saveLabel)) { + this.saveButtonLabel = this.data.saveLabel; + } + if (isNotEmptyStr(this.data.cancelLabel)) { + this.cancelButtonLabel = this.data.cancelLabel; + } this.jsonFormGroup = this.fb.group({ json: [this.data.jsonValue, []] }); diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index 59003e7cf5..740b413afa 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -464,6 +464,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) HtmlComponent, FabTriggerDirective, FabActionsDirective, + TbJsonToStringDirective, FabToolbarComponent, WidgetsBundleSelectComponent, ValueInputComponent, diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 93fb935d8f..420f7ae1ef 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -4597,6 +4597,7 @@ "datakey-value-type-string": "String", "datakey-value-type-double": "Double", "datakey-value-type-integer": "Integer", + "datakey-value-type-json": "JSON", "datakey-value-type-boolean-checkbox": "Boolean (Checkbox)", "datakey-value-type-boolean-switch": "Boolean (Switch)", "datakey-value-type-date-time": "Date & Time", @@ -4622,7 +4623,9 @@ "min-value-error-message": "'Min value' error message", "max-value-error-message": "'Max value' error message", "invalid-date-error-message": "'Invalid date' error message", + "invalid-JSON-error-message": "'Invalid JSON' error message", "icon-settings": "Icon settings", + "dialog-editor-settings": "Dialog editor settings", "use-custom-icon": "Use custom icon", "input-cell-icon": "Icon to show before input cell", "value-conversion-settings": "Value conversion settings", @@ -4631,7 +4634,10 @@ "get-value-function": "getValue function", "set-value-settings": "Set value settings", "use-set-value-function": "Use setValue function", - "set-value-function": "setValue function" + "set-value-function": "setValue function", + "json-invalid": "JSON value has an invalid format", + "title": "Title", + "cancel-button-label": "'Cancel' button label" }, "invalid-qr-code-text": "Invalid input text for QR code. Input should have a string type", "qr-code": {