+
-
-
+
{{ getErrorMessageText(key.settings,'required') }}
@@ -193,7 +193,7 @@
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts
index d4c0ad2630..eb3b0c9abf 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts
@@ -604,7 +604,8 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni
}
public inputChanged(source: MultipleInputWidgetSource, key: MultipleInputWidgetDataKey) {
- if (!this.settings.showActionButtons && !this.isSavingInProgress && this.multipleInputFormGroup.get(key.formId).valid) {
+ const control = this.multipleInputFormGroup.get(key.formId);
+ if (!this.settings.showActionButtons && !this.isSavingInProgress && (Array.isArray(control.value) || control.valid)) {
this.isSavingInProgress = true;
const dataToSave: MultipleInputWidgetSource = {
datasource: source.datasource,
@@ -775,6 +776,7 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
data: {
jsonValue: formControl.value,
+ required: key.settings.required,
title: key.settings.dialogTitle,
saveLabel: key.settings.saveButtonLabel,
cancelLabel: key.settings.cancelButtonLabel
@@ -791,4 +793,16 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni
}
);
}
+
+ invalid(): boolean {
+ for (const source of this.sources) {
+ for (const key of this.visibleKeys(source)) {
+ const control = this.multipleInputFormGroup.get(key.formId);
+ if (!Array.isArray(control.value) && control.invalid) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
}
diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html
index 732d6e3119..cdd1d8e2da 100644
--- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html
+++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html
@@ -89,7 +89,6 @@
diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.html
index 97f2214f2e..6d059fddec 100644
--- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.html
+++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.html
@@ -22,7 +22,7 @@
class="tb-rule-node-configuration-json"
formControlName="configuration"
[label]="'rulenode.configuration' | translate"
- [required]="required"
+ [jsonRequired]="required"
[fillHeight]="true">
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 141979d8ff..3b216bda71 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
@@ -33,8 +33,7 @@
,
protected router: Router,
@Inject(MAT_DIALOG_DATA) public data: JsonObjectEditDialogData,
diff --git a/ui-ngx/src/app/shared/components/directives/tb-json-to-string.directive.ts b/ui-ngx/src/app/shared/components/directives/tb-json-to-string.directive.ts
index 8da5fb1396..c70de1ab48 100644
--- a/ui-ngx/src/app/shared/components/directives/tb-json-to-string.directive.ts
+++ b/ui-ngx/src/app/shared/components/directives/tb-json-to-string.directive.ts
@@ -17,19 +17,23 @@
import { Directive, ElementRef, forwardRef, HostListener, Renderer2, SkipSelf } from '@angular/core';
import {
ControlValueAccessor,
- UntypedFormControl,
FormGroupDirective,
NG_VALIDATORS,
NG_VALUE_ACCESSOR,
NgForm,
+ UntypedFormControl,
ValidationErrors,
Validator
} from '@angular/forms';
import { ErrorStateMatcher } from '@angular/material/core';
-import { isObject } from "@core/utils";
+import { isObject } from '@core/utils';
@Directive({
selector: '[tb-json-to-string]',
+ // eslint-disable-next-line @angular-eslint/no-host-metadata-property
+ host: {
+ '(blur)': 'onTouched()'
+ },
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TbJsonToStringDirective),
@@ -48,18 +52,26 @@ import { isObject } from "@core/utils";
export class TbJsonToStringDirective implements ControlValueAccessor, Validator, ErrorStateMatcher {
private propagateChange = null;
+ public onTouched = () => {};
private parseError: boolean;
private data: any;
@HostListener('input', ['$event.target.value']) input(newValue: any): void {
try {
- this.data = JSON.parse(newValue);
- if (isObject(this.data)) {
- this.parseError = false;
+ if (newValue) {
+ this.data = JSON.parse(newValue);
+ if (isObject(this.data)) {
+ this.parseError = false;
+ } else {
+ this.data = null;
+ this.parseError = true;
+ }
} else {
- this.parseError = true;
+ this.data = null;
+ this.parseError = false;
}
} catch (e) {
+ this.data = null;
this.parseError = true;
}
@@ -73,9 +85,7 @@ export class TbJsonToStringDirective implements ControlValueAccessor, Validator,
}
isErrorState(control: UntypedFormControl | null, form: FormGroupDirective | NgForm | null): boolean {
- const originalErrorState = this.errorStateMatcher.isErrorState(control, form);
- const customErrorState = !!(control && control.invalid && this.parseError);
- return originalErrorState || customErrorState;
+ return !!(control && control.invalid && !Array.isArray(control.value) && control.touched);
}
validate(c: UntypedFormControl): ValidationErrors {
@@ -87,11 +97,9 @@ export class TbJsonToStringDirective implements ControlValueAccessor, Validator,
}
writeValue(obj: any): void {
- if (obj) {
- this.data = obj;
- this.parseError = false;
- this.render.setProperty(this.element.nativeElement, 'value', JSON.stringify(obj));
- }
+ this.data = obj;
+ this.parseError = false;
+ this.render.setProperty(this.element.nativeElement, 'value', obj ? JSON.stringify(obj) : '');
}
registerOnChange(fn: any): void {
@@ -99,5 +107,6 @@ export class TbJsonToStringDirective implements ControlValueAccessor, Validator,
}
registerOnTouched(fn: any): void {
+ this.onTouched = fn;
}
}
diff --git a/ui-ngx/src/app/shared/components/json-object-edit.component.html b/ui-ngx/src/app/shared/components/json-object-edit.component.html
index c0024da9dd..3ed828e6cf 100644
--- a/ui-ngx/src/app/shared/components/json-object-edit.component.html
+++ b/ui-ngx/src/app/shared/components/json-object-edit.component.html
@@ -20,7 +20,7 @@
[fullscreen]="fullscreen" (fullscreenChanged)="onFullscreen()" fxLayout="column">
diff --git a/ui-ngx/src/app/shared/components/json-object-edit.component.ts b/ui-ngx/src/app/shared/components/json-object-edit.component.ts
index f7e3116b0f..f89430f98b 100644
--- a/ui-ngx/src/app/shared/components/json-object-edit.component.ts
+++ b/ui-ngx/src/app/shared/components/json-object-edit.component.ts
@@ -24,7 +24,14 @@ import {
OnInit,
ViewChild
} from '@angular/core';
-import { ControlValueAccessor, UntypedFormControl, NG_VALIDATORS, NG_VALUE_ACCESSOR, Validator } from '@angular/forms';
+import {
+ ControlValueAccessor,
+ UntypedFormControl,
+ NG_VALIDATORS,
+ NG_VALUE_ACCESSOR,
+ Validator,
+ AbstractControl, ValidationErrors
+} from '@angular/forms';
import { Ace } from 'ace-builds';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { ActionNotificationHide, ActionNotificationShow } from '@core/notification/notification.actions';
@@ -34,6 +41,9 @@ import { CancelAnimationFrame, RafService } from '@core/services/raf.service';
import { guid, isDefinedAndNotNull, isObject, isUndefined } from '@core/utils';
import { ResizeObserver } from '@juggle/resize-observer';
import { getAce } from '@shared/models/ace/ace.models';
+import { coerceBoolean } from '@shared/decorators/coercion';
+
+export const jsonRequired = (control: AbstractControl): ValidationErrors | null => !control.value ? {required: true} : null;
@Component({
selector: 'tb-json-object-edit',
@@ -73,27 +83,13 @@ export class JsonObjectEditComponent implements OnInit, ControlValueAccessor, Va
@Input() sort: (key: string, value: any) => any;
- private requiredValue: boolean;
-
- get required(): boolean {
- return this.requiredValue;
- }
-
+ @coerceBoolean()
@Input()
- set required(value: boolean) {
- this.requiredValue = coerceBooleanProperty(value);
- }
-
- private readonlyValue: boolean;
-
- get readonly(): boolean {
- return this.readonlyValue;
- }
+ jsonRequired: boolean;
+ @coerceBoolean()
@Input()
- set readonly(value: boolean) {
- this.readonlyValue = coerceBooleanProperty(value);
- }
+ readonly: boolean;
fullscreen = false;
@@ -245,12 +241,10 @@ export class JsonObjectEditComponent implements OnInit, ControlValueAccessor, Va
try {
if (isDefinedAndNotNull(this.modelValue)) {
this.contentValue = JSON.stringify(this.modelValue, isUndefined(this.sort) ? undefined :
- (key, objectValue) => {
- return this.sort(key, objectValue);
- }, 2);
+ (key, objectValue) => this.sort(key, objectValue), 2);
this.objectValid = true;
} else {
- this.objectValid = !this.required;
+ this.objectValid = !this.jsonRequired;
this.validationError = 'Json object is required.';
}
} catch (e) {
@@ -288,8 +282,8 @@ export class JsonObjectEditComponent implements OnInit, ControlValueAccessor, Va
this.validationError = errorInfo;
}
} else {
- this.objectValid = !this.required;
- this.validationError = this.required ? 'Json object is required.' : '';
+ this.objectValid = !this.jsonRequired;
+ this.validationError = this.jsonRequired ? 'Json object is required.' : '';
}
this.modelValue = data;
this.propagateChange(data);
diff --git a/ui-ngx/src/app/shared/components/value-input.component.html b/ui-ngx/src/app/shared/components/value-input.component.html
index 57d6954699..9f7f9d0ffc 100644
--- a/ui-ngx/src/app/shared/components/value-input.component.html
+++ b/ui-ngx/src/app/shared/components/value-input.component.html
@@ -67,7 +67,7 @@
-
+
{{ (requiredText ? requiredText : 'value.json-value-required') | translate }}
diff --git a/ui-ngx/src/app/shared/components/value-input.component.ts b/ui-ngx/src/app/shared/components/value-input.component.ts
index 4ba7abf157..52828cec35 100644
--- a/ui-ngx/src/app/shared/components/value-input.component.ts
+++ b/ui-ngx/src/app/shared/components/value-input.component.ts
@@ -15,7 +15,7 @@
///
import { Component, forwardRef, Input, OnInit, ViewChild } from '@angular/core';
-import { ControlValueAccessor, NG_VALUE_ACCESSOR, NgForm } from '@angular/forms';
+import { ControlValueAccessor, NG_VALUE_ACCESSOR, NgForm, NgModel } from '@angular/forms';
import { ValueType, valueTypesMap } from '@shared/models/constants';
import { isObject } from '@core/utils';
import { MatDialog } from '@angular/material/dialog';
@@ -23,6 +23,7 @@ import {
JsonObjectEditDialogComponent,
JsonObjectEditDialogData
} from '@shared/components/dialog/json-object-edit-dialog.component';
+import { coerceBoolean } from '@shared/decorators/coercion';
@Component({
selector: 'tb-value-input',
@@ -73,7 +74,8 @@ export class ValueInputComponent implements OnInit, ControlValueAccessor {
disableClose: true,
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
data: {
- jsonValue: this.modelValue
+ jsonValue: this.modelValue,
+ required: true
}
}).afterClosed().subscribe(
(res) => {
@@ -115,7 +117,8 @@ export class ValueInputComponent implements OnInit, ControlValueAccessor {
}
updateView() {
- if (this.inputForm.valid || this.valueType === ValueType.BOOLEAN) {
+ if (this.inputForm.valid || this.valueType === ValueType.BOOLEAN ||
+ (this.valueType === ValueType.JSON && Array.isArray(this.modelValue))) {
this.propagateChange(this.modelValue);
} else {
this.propagateChange(null);