diff --git a/ui-ngx/src/app/core/api/widget-subscription.ts b/ui-ngx/src/app/core/api/widget-subscription.ts index 9d07c751a5..440e61148e 100644 --- a/ui-ngx/src/app/core/api/widget-subscription.ts +++ b/ui-ngx/src/app/core/api/widget-subscription.ts @@ -582,12 +582,9 @@ export class WidgetSubscription implements IWidgetSubscription { const data = this.alarms.data[0]; entityId = data.originator; entityName = data.originatorName; + entityLabel = data.originatorLabel; if (data.latest && data.latest[EntityKeyType.ENTITY_FIELD]) { const entityFields = data.latest[EntityKeyType.ENTITY_FIELD]; - const labelValue = entityFields.label; - if (labelValue) { - entityLabel = labelValue.value; - } const additionalInfoValue = entityFields.additionalInfo; if (additionalInfoValue) { const additionalInfo = additionalInfoValue.value; diff --git a/ui-ngx/src/app/core/services/utils.service.ts b/ui-ngx/src/app/core/services/utils.service.ts index ea4c85eb64..813127cbc5 100644 --- a/ui-ngx/src/app/core/services/utils.service.ts +++ b/ui-ngx/src/app/core/services/utils.service.ts @@ -29,7 +29,11 @@ import { isDefined, isDefinedAndNotNull, isString, - isUndefined + isUndefined, + objToBase64, + objToBase64URI, + base64toString, + base64toObj } from '@core/utils'; import { WindowMessage } from '@shared/models/window-message.model'; import { TranslateService } from '@ngx-translate/core'; @@ -87,7 +91,7 @@ const commonMaterialIcons: Array = ['more_horiz', 'more_vert', 'open_in_ 'arrow_forward', 'arrow_upwards', 'close', 'refresh', 'menu', 'show_chart', 'multiline_chart', 'pie_chart', 'insert_chart', 'people', 'person', 'domain', 'devices_other', 'now_widgets', 'dashboards', 'map', 'pin_drop', 'my_location', 'extension', 'search', 'settings', 'notifications', 'notifications_active', 'info', 'info_outline', 'warning', 'list', 'file_download', 'import_export', - 'share', 'add', 'edit', 'done']; + 'share', 'add', 'edit', 'done', 'delete']; // @dynamic @Injectable({ @@ -518,4 +522,21 @@ export class UtilsService { refCount() ); } + + public objToBase64(obj: any): string { + return objToBase64(obj); + } + + public base64toString(b64Encoded: string): string { + return base64toString(b64Encoded); + } + + public objToBase64URI(obj: any): string { + return objToBase64URI(obj); + } + + public base64toObj(b64Encoded: string): any { + return base64toObj(b64Encoded); + } + } diff --git a/ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.html b/ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.html index 12a3c542e1..e70b2d3cc8 100644 --- a/ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.html +++ b/ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.html @@ -42,7 +42,7 @@
+ *ngFor="let predicateControl of predicatesFormArray.controls; let $index = index">
{{ complexOperationTranslations.get(operation) | translate }}
@@ -68,7 +68,7 @@
- filter.no-filters diff --git a/ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.ts b/ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.ts index 809cd553c4..78e7252a72 100644 --- a/ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Inject, Input, OnInit } from '@angular/core'; +import { Component, forwardRef, Inject, Input, OnDestroy, OnInit } from '@angular/core'; import { AbstractControl, ControlValueAccessor, @@ -27,7 +27,7 @@ import { Validator, Validators } from '@angular/forms'; -import { Observable, of, Subscription } from 'rxjs'; +import { Observable, of, Subject } from 'rxjs'; import { ComplexFilterPredicateInfo, ComplexOperation, @@ -37,7 +37,7 @@ import { KeyFilterPredicateInfo } from '@shared/models/query/query.models'; import { MatDialog } from '@angular/material/dialog'; -import { map } from 'rxjs/operators'; +import { map, takeUntil } from 'rxjs/operators'; import { ComponentType } from '@angular/cdk/portal'; import { COMPLEX_FILTER_PREDICATE_DIALOG_COMPONENT_TOKEN } from '@home/components/tokens'; import { ComplexFilterPredicateDialogData } from '@home/components/filter/filter-component.models'; @@ -59,7 +59,7 @@ import { ComplexFilterPredicateDialogData } from '@home/components/filter/filter } ] }) -export class FilterPredicateListComponent implements ControlValueAccessor, Validator, OnInit { +export class FilterPredicateListComponent implements ControlValueAccessor, Validator, OnInit, OnDestroy { @Input() disabled: boolean; @@ -81,22 +81,29 @@ export class FilterPredicateListComponent implements ControlValueAccessor, Valid complexOperationTranslations = complexOperationTranslationMap; + private destroy$ = new Subject(); private propagateChange = null; - private valueChangeSubscription: Subscription = null; - constructor(private fb: UntypedFormBuilder, @Inject(COMPLEX_FILTER_PREDICATE_DIALOG_COMPONENT_TOKEN) private complexFilterPredicateDialogComponent: ComponentType, private dialog: MatDialog) { } ngOnInit(): void { - this.filterListFormGroup = this.fb.group({}); - this.filterListFormGroup.addControl('predicates', - this.fb.array([])); + this.filterListFormGroup = this.fb.group({ + predicates: this.fb.array([]) + }); + this.filterListFormGroup.valueChanges.pipe( + takeUntil(this.destroy$) + ).subscribe(() => this.updateModel()); + } + + ngOnDestroy() { + this.destroy$.next(); + this.destroy$.complete(); } - predicatesFormArray(): UntypedFormArray { + get predicatesFormArray(): UntypedFormArray { return this.filterListFormGroup.get('predicates') as UntypedFormArray; } @@ -123,28 +130,26 @@ export class FilterPredicateListComponent implements ControlValueAccessor, Valid } writeValue(predicates: Array): void { - if (this.valueChangeSubscription) { - this.valueChangeSubscription.unsubscribe(); - } - const predicateControls: Array = []; - if (predicates) { - for (const predicate of predicates) { - predicateControls.push(this.fb.control(predicate, [Validators.required])); - } - } - this.filterListFormGroup.setControl('predicates', this.fb.array(predicateControls)); - this.valueChangeSubscription = this.filterListFormGroup.valueChanges.subscribe(() => { - this.updateModel(); - }); - if (this.disabled) { - this.filterListFormGroup.disable({emitEvent: false}); + if (predicates.length === this.predicatesFormArray.length) { + this.predicatesFormArray.patchValue(predicates, {emitEvent: false}); } else { - this.filterListFormGroup.enable({emitEvent: false}); + const predicateControls: Array = []; + if (predicates) { + for (const predicate of predicates) { + predicateControls.push(this.fb.control(predicate, [Validators.required])); + } + } + this.filterListFormGroup.setControl('predicates', this.fb.array(predicateControls), {emitEvent: false}); + if (this.disabled) { + this.filterListFormGroup.disable({emitEvent: false}); + } else { + this.filterListFormGroup.enable({emitEvent: false}); + } } } public removePredicate(index: number) { - (this.filterListFormGroup.get('predicates') as UntypedFormArray).removeAt(index); + this.predicatesFormArray.removeAt(index); } public addPredicate(complex: boolean) { diff --git a/ui-ngx/src/app/modules/home/components/filter/filters-dialog.component.html b/ui-ngx/src/app/modules/home/components/filter/filters-dialog.component.html index 23135cd862..2d24bc479f 100644 --- a/ui-ngx/src/app/modules/home/components/filter/filters-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/filter/filters-dialog.component.html @@ -64,6 +64,15 @@ matTooltipPosition="above"> edit + - - - -
-
- - -
- {{ 'device-profile.device-profile-details' | translate }} -
- - device-profile.name - - - {{ 'device-profile.name-required' | translate }} - - - {{ 'device-profile.name-max-length' | translate }} - - - - - - {{'device-profile.mobile-dashboard-hint' | translate}} - - - - - {{'device-profile.default-edge-rule-chain-hint' | translate}} - - - device-profile.type - - - {{deviceProfileTypeTranslations.get(type) | translate}} - - - - {{ 'device-profile.type-required' | translate }} - - - - - - device-profile.description - - -
-
-
- -
- {{ 'device-profile.transport-configuration' | translate }} + +

device-profile.add

+ +
+ +
+ + +
+
+ + + + {{ 'device-profile.device-profile-details' | translate }} +
- device-profile.transport-type - - - {{deviceTransportTypeTranslations.get(type) | translate}} + device-profile.name + + + {{ 'device-profile.name-required' | translate }} + + + {{ 'device-profile.name-max-length' | translate }} + + + + + + {{'device-profile.mobile-dashboard-hint' | translate}} + + + + + {{'device-profile.default-edge-rule-chain-hint' | translate}} + + + device-profile.type + + + {{deviceProfileTypeTranslations.get(type) | translate}} - - {{deviceTransportTypeHints.get(transportConfigFormGroup.get('transportType').value) | translate}} - - - {{ 'device-profile.transport-type-required' | translate }} + + {{ 'device-profile.type-required' | translate }} - - - - - -
- {{'device-profile.alarm-rules-with-count' | translate: - {count: alarmRulesFormGroup.get('alarms').value ? - alarmRulesFormGroup.get('alarms').value.length : 0} }} - - -
-
- -
- {{ 'device-profile.device-provisioning' | translate }} - - -
-
- -
-
+ + + + device-profile.description + + + + + + +
+ {{ 'device-profile.transport-configuration' | translate }} + + device-profile.transport-type + + + {{deviceTransportTypeTranslations.get(type) | translate}} + + + + {{deviceTransportTypeHints.get(transportConfigFormGroup.get('transportType').value) | translate}} + + + {{ 'device-profile.transport-type-required' | translate }} + + + + +
+
+ +
+ {{'device-profile.alarm-rules-with-count' | translate: + {count: alarmRulesFormGroup.get('alarms').value ? + alarmRulesFormGroup.get('alarms').value.length : 0} }} + + +
+
+ +
+ {{ 'device-profile.device-provisioning' | translate }} + + +
+
+ +
+
+
@@ -143,8 +147,8 @@ [disabled]="(isLoading$ | async)" (click)="nextStep()">{{ 'action.next-with-label' | translate:{label: (getFormLabel(this.selectedIndex+1) | translate)} }}
- -
+ +
diff --git a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.scss b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.scss index eaef363192..ca54ae2053 100644 --- a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.scss @@ -15,6 +15,15 @@ */ @import "../../../../../scss/constants"; +:host { + height: 100%; + display: grid; + + .dialog-actions-row { + padding: 8px; + } +} + :host-context(.tb-fullscreen-dialog .mat-mdc-dialog-container) { @media #{$mat-lt-sm} { .mat-mdc-dialog-content { @@ -32,31 +41,21 @@ .mat-stepper-horizontal { display: flex; - flex-direction: column; height: 100%; overflow: hidden; - @media #{$mat-lt-sm} { - .mat-step-label { - white-space: normal; - overflow: visible; - .mat-step-text-label { - overflow: visible; - } - } + + .mat-horizontal-stepper-wrapper { + flex: 1 1 100%; } + .mat-horizontal-content-container { - height: 530px; + height: 680px; max-height: 100%; width: 100%;; overflow-y: auto; + scrollbar-gutter: stable; @media #{$mat-gt-sm} { - min-width: 800px; - } - } - .mat-horizontal-stepper-content[aria-expanded=true] { - height: 100%; - form { - height: 100%; + min-width: 500px; } } } diff --git a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts index c9b50727ea..3426593aed 100644 --- a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts @@ -44,13 +44,17 @@ import { } from '@shared/models/device.models'; import { DeviceProfileService } from '@core/http/device-profile.service'; import { EntityType } from '@shared/models/entity-type.models'; -import { MatStepper } from '@angular/material/stepper'; +import { MatStepper, StepperOrientation } from '@angular/material/stepper'; import { RuleChainId } from '@shared/models/id/rule-chain-id'; import { StepperSelectionEvent } from '@angular/cdk/stepper'; import { deepTrim } from '@core/utils'; import { ServiceType } from '@shared/models/queue.models'; import { DashboardId } from '@shared/models/id/dashboard-id'; import { RuleChainType } from '@shared/models/rule-chain.models'; +import { Observable } from 'rxjs'; +import { BreakpointObserver } from '@angular/cdk/layout'; +import { MediaBreakpoints } from '@shared/models/constants'; +import { map } from 'rxjs/operators'; export interface AddDeviceProfileDialogData { deviceProfileName: string; @@ -67,7 +71,8 @@ export class AddDeviceProfileDialogComponent extends DialogComponent implements AfterViewInit { @ViewChild('addDeviceProfileStepper', {static: true}) addDeviceProfileStepper: MatStepper; - + stepperOrientation: Observable; + stepperLabelPosition: Observable<'bottom' | 'end'>; selectedIndex = 0; showNext = true; @@ -102,10 +107,17 @@ export class AddDeviceProfileDialogComponent extends public dialogRef: MatDialogRef, private componentFactoryResolver: ComponentFactoryResolver, private injector: Injector, + private breakpointObserver: BreakpointObserver, @SkipSelf() private errorStateMatcher: ErrorStateMatcher, private deviceProfileService: DeviceProfileService, private fb: UntypedFormBuilder) { super(store, router, dialogRef); + this.stepperOrientation = this.breakpointObserver.observe(MediaBreakpoints['gt-sm']) + .pipe(map(({matches}) => matches ? 'horizontal' : 'vertical')); + + this.stepperLabelPosition = this.breakpointObserver.observe(MediaBreakpoints['gt-md']) + .pipe(map(({matches}) => matches ? 'end' : 'bottom')); + this.deviceProfileDetailsFormGroup = this.fb.group( { name: [data.deviceProfileName, [Validators.required, Validators.maxLength(255)]], diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/create-alarm-rules.component.ts b/ui-ngx/src/app/modules/home/components/profile/alarm/create-alarm-rules.component.ts index 40cc7e2ec6..04169214fd 100644 --- a/ui-ngx/src/app/modules/home/components/profile/alarm/create-alarm-rules.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/alarm/create-alarm-rules.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'; import { AbstractControl, ControlValueAccessor, @@ -23,15 +23,16 @@ import { UntypedFormControl, UntypedFormGroup, NG_VALIDATORS, - NG_VALUE_ACCESSOR, ValidationErrors, + NG_VALUE_ACCESSOR, Validator, Validators } from '@angular/forms'; import { DeviceProfileAlarmRule, alarmRuleValidator } from '@shared/models/device.models'; import { MatDialog } from '@angular/material/dialog'; -import { Subscription } from 'rxjs'; +import { Subject } from 'rxjs'; import { AlarmSeverity, alarmSeverityTranslations } from '@shared/models/alarm.models'; import { EntityId } from '@shared/models/id/entity-id'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'tb-create-alarm-rules', @@ -50,7 +51,7 @@ import { EntityId } from '@shared/models/id/entity-id'; } ] }) -export class CreateAlarmRulesComponent implements ControlValueAccessor, OnInit, Validator { +export class CreateAlarmRulesComponent implements ControlValueAccessor, OnInit, Validator, OnDestroy { alarmSeverities = Object.keys(AlarmSeverity); alarmSeverityEnum = AlarmSeverity; @@ -67,8 +68,7 @@ export class CreateAlarmRulesComponent implements ControlValueAccessor, OnInit, private usedSeverities: AlarmSeverity[] = []; - private valueChangeSubscription: Subscription = null; - + private destroy$ = new Subject(); private propagateChange = (v: any) => { }; constructor(private dialog: MatDialog, @@ -86,6 +86,14 @@ export class CreateAlarmRulesComponent implements ControlValueAccessor, OnInit, this.createAlarmRulesFormGroup = this.fb.group({ createAlarmRules: this.fb.array([]) }); + this.createAlarmRulesFormGroup.valueChanges.pipe( + takeUntil(this.destroy$) + ).subscribe(() => this.updateModel()); + } + + ngOnDestroy() { + this.destroy$.next(); + this.destroy$.complete(); } createAlarmRulesFormArray(): UntypedFormArray { @@ -102,9 +110,6 @@ export class CreateAlarmRulesComponent implements ControlValueAccessor, OnInit, } writeValue(createAlarmRules: {[severity: string]: DeviceProfileAlarmRule}): void { - if (this.valueChangeSubscription) { - this.valueChangeSubscription.unsubscribe(); - } const createAlarmRulesControls: Array = []; if (createAlarmRules) { Object.keys(createAlarmRules).forEach((severity) => { @@ -118,15 +123,12 @@ export class CreateAlarmRulesComponent implements ControlValueAccessor, OnInit, })); }); } - this.createAlarmRulesFormGroup.setControl('createAlarmRules', this.fb.array(createAlarmRulesControls)); + this.createAlarmRulesFormGroup.setControl('createAlarmRules', this.fb.array(createAlarmRulesControls), {emitEvent: false}); if (this.disabled) { this.createAlarmRulesFormGroup.disable({emitEvent: false}); } else { this.createAlarmRulesFormGroup.enable({emitEvent: false}); } - this.valueChangeSubscription = this.createAlarmRulesFormGroup.valueChanges.subscribe(() => { - this.updateModel(); - }); this.updateUsedSeverities(); if (!this.disabled && !this.createAlarmRulesFormGroup.valid) { this.updateModel(); diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.html b/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.html index a7264483f3..d8c9c081f6 100644 --- a/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.html @@ -59,10 +59,10 @@ - + {{ 'device-profile.propagate-alarm' | translate }} -
+
device-profile.alarm-rule-relation-types-list @@ -82,10 +82,10 @@
- + {{ 'device-profile.propagate-alarm-to-owner' | translate }} - + {{ 'device-profile.propagate-alarm-to-tenant' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarms.component.html b/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarms.component.html index a8f2e77fa5..57d64cbc7d 100644 --- a/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarms.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarms.component.html @@ -17,7 +17,7 @@ -->
-
-
+
device-profile.no-alarm-rules
diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarms.component.ts b/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarms.component.ts index 257263c2eb..a828040e9c 100644 --- a/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarms.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarms.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'; import { AbstractControl, ControlValueAccessor, @@ -32,9 +32,9 @@ import { AppState } from '@app/core/core.state'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { DeviceProfileAlarm, deviceProfileAlarmValidator } from '@shared/models/device.models'; import { guid } from '@core/utils'; -import { Subscription } from 'rxjs'; -import { MatDialog } from '@angular/material/dialog'; +import { Subject } from 'rxjs'; import { EntityId } from '@shared/models/id/entity-id'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'tb-device-profile-alarms', @@ -53,7 +53,7 @@ import { EntityId } from '@shared/models/id/entity-id'; } ] }) -export class DeviceProfileAlarmsComponent implements ControlValueAccessor, OnInit, Validator { +export class DeviceProfileAlarmsComponent implements ControlValueAccessor, OnInit, Validator, OnDestroy { deviceProfileAlarmsFormGroup: UntypedFormGroup; @@ -72,13 +72,11 @@ export class DeviceProfileAlarmsComponent implements ControlValueAccessor, OnIni @Input() deviceProfileId: EntityId; - private valueChangeSubscription: Subscription = null; - + private destroy$ = new Subject(); private propagateChange = (v: any) => { }; constructor(private store: Store, - private fb: UntypedFormBuilder, - private dialog: MatDialog) { + private fb: UntypedFormBuilder) { } registerOnChange(fn: any): void { @@ -92,9 +90,17 @@ export class DeviceProfileAlarmsComponent implements ControlValueAccessor, OnIni this.deviceProfileAlarmsFormGroup = this.fb.group({ alarms: this.fb.array([]) }); + this.deviceProfileAlarmsFormGroup.valueChanges.pipe( + takeUntil(this.destroy$) + ).subscribe(() => this.updateModel()); + } + + ngOnDestroy() { + this.destroy$.next(); + this.destroy$.complete(); } - alarmsFormArray(): UntypedFormArray { + get alarmsFormArray(): UntypedFormArray { return this.deviceProfileAlarmsFormGroup.get('alarms') as UntypedFormArray; } @@ -108,24 +114,22 @@ export class DeviceProfileAlarmsComponent implements ControlValueAccessor, OnIni } writeValue(alarms: Array | null): void { - if (this.valueChangeSubscription) { - this.valueChangeSubscription.unsubscribe(); - } - const alarmsControls: Array = []; - if (alarms) { - alarms.forEach((alarm) => { - alarmsControls.push(this.fb.control(alarm, [Validators.required])); - }); - } - this.deviceProfileAlarmsFormGroup.setControl('alarms', this.fb.array(alarmsControls)); - if (this.disabled) { - this.deviceProfileAlarmsFormGroup.disable({emitEvent: false}); + if (alarms?.length === this.alarmsFormArray.length) { + this.alarmsFormArray.patchValue(alarms, {emitEvent: false}); } else { - this.deviceProfileAlarmsFormGroup.enable({emitEvent: false}); + const alarmsControls: Array = []; + if (alarms) { + alarms.forEach((alarm) => { + alarmsControls.push(this.fb.control(alarm, [Validators.required])); + }); + } + this.deviceProfileAlarmsFormGroup.setControl('alarms', this.fb.array(alarmsControls), {emitEvent: false}); + if (this.disabled) { + this.deviceProfileAlarmsFormGroup.disable({emitEvent: false}); + } else { + this.deviceProfileAlarmsFormGroup.enable({emitEvent: false}); + } } - this.valueChangeSubscription = this.deviceProfileAlarmsFormGroup.valueChanges.subscribe(() => { - this.updateModel(); - }); } public trackByAlarm(index: number, alarmControl: AbstractControl): string { diff --git a/ui-ngx/src/app/modules/home/components/profile/device-profile-provision-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/device-profile-provision-configuration.component.html index b588a5ec34..cd711f9e12 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device-profile-provision-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device-profile-provision-configuration.component.html @@ -31,7 +31,7 @@ device-profile.provision-device-key -
-
+
device-profile.snmp.please-add-communication-config
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/snmp/snmp-device-profile-communication-config.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/snmp/snmp-device-profile-communication-config.component.ts index 959fc51ec5..7e0f8dd3b5 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/snmp/snmp-device-profile-communication-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/snmp/snmp-device-profile-communication-config.component.ts @@ -27,7 +27,7 @@ import { Validators } from '@angular/forms'; import { SnmpCommunicationConfig, SnmpSpecType, SnmpSpecTypeTranslationMap } from '@shared/models/device.models'; -import { Subject, Subscription } from 'rxjs'; +import { Subject } from 'rxjs'; import { isUndefinedOrNull } from '@core/utils'; import { takeUntil } from 'rxjs/operators'; @@ -58,7 +58,6 @@ export class SnmpDeviceProfileCommunicationConfigComponent implements OnInit, On disabled: boolean; private usedSpecType: SnmpSpecType[] = []; - private valueChange$: Subscription = null; private destroy$ = new Subject(); private propagateChange = (v: any) => { }; @@ -68,17 +67,17 @@ export class SnmpDeviceProfileCommunicationConfigComponent implements OnInit, On this.deviceProfileCommunicationConfig = this.fb.group({ communicationConfig: this.fb.array([]) }); + this.deviceProfileCommunicationConfig.valueChanges.pipe( + takeUntil(this.destroy$) + ).subscribe(() => this.updateModel()); } ngOnDestroy() { - if (this.valueChange$) { - this.valueChange$.unsubscribe(); - } this.destroy$.next(); this.destroy$.complete(); } - communicationConfigFormArray(): UntypedFormArray { + get communicationConfigFormArray(): UntypedFormArray { return this.deviceProfileCommunicationConfig.get('communicationConfig') as UntypedFormArray; } @@ -99,27 +98,27 @@ export class SnmpDeviceProfileCommunicationConfigComponent implements OnInit, On } writeValue(communicationConfig: SnmpCommunicationConfig[]) { - if (this.valueChange$) { - this.valueChange$.unsubscribe(); - } - const communicationConfigControl: Array = []; - if (communicationConfig) { - communicationConfig.forEach((config) => { - communicationConfigControl.push(this.createdFormGroup(config)); - }); - } - this.deviceProfileCommunicationConfig.setControl('communicationConfig', this.fb.array(communicationConfigControl)); - if (!communicationConfig || !communicationConfig.length) { - this.addCommunicationConfig(); - } - if (this.disabled) { - this.deviceProfileCommunicationConfig.disable({emitEvent: false}); + if (communicationConfig?.length === this.communicationConfigFormArray.length) { + this.communicationConfigFormArray.patchValue(communicationConfig, {emitEvent: false}); } else { - this.deviceProfileCommunicationConfig.enable({emitEvent: false}); + const communicationConfigControl: Array = []; + if (communicationConfig) { + communicationConfig.forEach((config) => { + communicationConfigControl.push(this.createdFormGroup(config)); + }); + } + this.deviceProfileCommunicationConfig.setControl( + 'communicationConfig', this.fb.array(communicationConfigControl), {emitEvent: false} + ); + if (!communicationConfig || !communicationConfig.length) { + this.addCommunicationConfig(); + } + if (this.disabled) { + this.deviceProfileCommunicationConfig.disable({emitEvent: false}); + } else { + this.deviceProfileCommunicationConfig.enable({emitEvent: false}); + } } - this.valueChange$ = this.deviceProfileCommunicationConfig.valueChanges.subscribe(() => { - this.updateModel(); - }); this.updateUsedSpecType(); if (!this.disabled && !this.deviceProfileCommunicationConfig.valid) { this.updateModel(); @@ -133,16 +132,16 @@ export class SnmpDeviceProfileCommunicationConfigComponent implements OnInit, On } public removeCommunicationConfig(index: number) { - this.communicationConfigFormArray().removeAt(index); + this.communicationConfigFormArray.removeAt(index); } get isAddEnabled(): boolean { - return this.communicationConfigFormArray().length !== Object.keys(SnmpSpecType).length; + return this.communicationConfigFormArray.length !== Object.keys(SnmpSpecType).length; } public addCommunicationConfig() { - this.communicationConfigFormArray().push(this.createdFormGroup()); + this.communicationConfigFormArray.push(this.createdFormGroup()); this.deviceProfileCommunicationConfig.updateValueAndValidity(); if (!this.deviceProfileCommunicationConfig.valid) { this.updateModel(); diff --git a/ui-ngx/src/app/modules/home/components/profile/device/snmp/snmp-device-profile-mapping.component.html b/ui-ngx/src/app/modules/home/components/profile/device/snmp/snmp-device-profile-mapping.component.html index d1e68b60c8..94fe06137f 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/snmp/snmp-device-profile-mapping.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/snmp/snmp-device-profile-mapping.component.html @@ -25,7 +25,7 @@
-
@@ -64,7 +64,7 @@
-
+
device-profile.snmp.please-add-mapping-config
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/snmp/snmp-device-profile-mapping.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/snmp/snmp-device-profile-mapping.component.ts index 5543bf6b11..428eb6b86e 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/snmp/snmp-device-profile-mapping.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/snmp/snmp-device-profile-mapping.component.ts @@ -18,19 +18,20 @@ import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'; import { AbstractControl, ControlValueAccessor, + NG_VALIDATORS, + NG_VALUE_ACCESSOR, UntypedFormArray, UntypedFormBuilder, UntypedFormGroup, - NG_VALIDATORS, - NG_VALUE_ACCESSOR, ValidationErrors, Validator, Validators } from '@angular/forms'; import { SnmpMapping } from '@shared/models/device.models'; -import { Subscription } from 'rxjs'; +import { Subject } from 'rxjs'; import { DataType, DataTypeTranslationMap } from '@shared/models/constants'; import { isUndefinedOrNull } from '@core/utils'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'tb-snmp-device-profile-mapping', @@ -60,7 +61,7 @@ export class SnmpDeviceProfileMappingComponent implements OnInit, OnDestroy, Con private readonly oidPattern: RegExp = /^\.?([0-2])((\.0)|(\.[1-9][0-9]*))*$/; - private valueChange$: Subscription = null; + private destroy$ = new Subject(); private propagateChange = (v: any) => { }; constructor(private fb: UntypedFormBuilder) { } @@ -69,12 +70,14 @@ export class SnmpDeviceProfileMappingComponent implements OnInit, OnDestroy, Con this.mappingsConfigForm = this.fb.group({ mappings: this.fb.array([]) }); + this.mappingsConfigForm.valueChanges.pipe( + takeUntil(this.destroy$) + ).subscribe(() => this.updateModel()); } ngOnDestroy() { - if (this.valueChange$) { - this.valueChange$.unsubscribe(); - } + this.destroy$.next(); + this.destroy$.complete(); } registerOnChange(fn: any) { @@ -100,38 +103,36 @@ export class SnmpDeviceProfileMappingComponent implements OnInit, OnDestroy, Con } writeValue(mappings: SnmpMapping[]) { - if (this.valueChange$) { - this.valueChange$.unsubscribe(); - } - const mappingsControl: Array = []; - if (mappings) { - mappings.forEach((config) => { - mappingsControl.push(this.createdFormGroup(config)); - }); - } - this.mappingsConfigForm.setControl('mappings', this.fb.array(mappingsControl)); - if (!mappings || !mappings.length) { - this.addMappingConfig(); - } - if (this.disabled) { - this.mappingsConfigForm.disable({emitEvent: false}); + if (mappings?.length === this.mappingsConfigFormArray.length) { + this.mappingsConfigFormArray.patchValue(mappings, {emitEvent: false}); } else { - this.mappingsConfigForm.enable({emitEvent: false}); + const mappingsControl: Array = []; + if (mappings) { + mappings.forEach((config) => { + mappingsControl.push(this.createdFormGroup(config)); + }); + } + this.mappingsConfigForm.setControl('mappings', this.fb.array(mappingsControl), {emitEvent: false}); + if (!mappings || !mappings.length) { + this.addMappingConfig(); + } + if (this.disabled) { + this.mappingsConfigForm.disable({emitEvent: false}); + } else { + this.mappingsConfigForm.enable({emitEvent: false}); + } } - this.valueChange$ = this.mappingsConfigForm.valueChanges.subscribe(() => { - this.updateModel(); - }); if (!this.disabled && !this.mappingsConfigForm.valid) { this.updateModel(); } } - mappingsConfigFormArray(): UntypedFormArray { + get mappingsConfigFormArray(): UntypedFormArray { return this.mappingsConfigForm.get('mappings') as UntypedFormArray; } public addMappingConfig() { - this.mappingsConfigFormArray().push(this.createdFormGroup()); + this.mappingsConfigFormArray.push(this.createdFormGroup()); this.mappingsConfigForm.updateValueAndValidity(); if (!this.mappingsConfigForm.valid) { this.updateModel(); @@ -139,7 +140,7 @@ export class SnmpDeviceProfileMappingComponent implements OnInit, OnDestroy, Con } public removeMappingConfig(index: number) { - this.mappingsConfigFormArray().removeAt(index); + this.mappingsConfigFormArray.removeAt(index); } private createdFormGroup(value?: SnmpMapping): UntypedFormGroup { diff --git a/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.ts b/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.ts index 2a29ec2e15..c3ff3ccc4c 100644 --- a/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.ts @@ -30,10 +30,11 @@ import { import { Store } from '@ngrx/store'; import { AppState } from '@app/core/core.state'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; -import { Subscription } from 'rxjs'; +import { Subject } from 'rxjs'; import { QueueInfo } from '@shared/models/queue.models'; import { UtilsService } from '@core/services/utils.service'; import { guid } from '@core/utils'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'tb-tenant-profile-queues', @@ -70,8 +71,7 @@ export class TenantProfileQueuesComponent implements ControlValueAccessor, Valid @Input() disabled: boolean; - private valueChangeSubscription$: Subscription = null; - + private destroy$ = new Subject(); private propagateChange = (v: any) => { }; constructor(private store: Store, @@ -83,12 +83,6 @@ export class TenantProfileQueuesComponent implements ControlValueAccessor, Valid this.propagateChange = fn; } - ngOnDestroy() { - if (this.valueChangeSubscription$) { - this.valueChangeSubscription$.unsubscribe(); - } - } - registerOnTouched(fn: any): void { } @@ -96,6 +90,15 @@ export class TenantProfileQueuesComponent implements ControlValueAccessor, Valid this.tenantProfileQueuesFormGroup = this.fb.group({ queues: this.fb.array([]) }); + + this.tenantProfileQueuesFormGroup.valueChanges.pipe( + takeUntil(this.destroy$) + ).subscribe(() => this.updateModel()); + } + + ngOnDestroy() { + this.destroy$.next(); + this.destroy$.complete(); } get queuesFormArray(): UntypedFormArray { @@ -112,30 +115,28 @@ export class TenantProfileQueuesComponent implements ControlValueAccessor, Valid } writeValue(queues: Array | null): void { - if (this.valueChangeSubscription$) { - this.valueChangeSubscription$.unsubscribe(); - } - const queuesControls: Array = []; - if (queues) { - queues.forEach((queue, index) => { - if (!queue.id) { - if (!this.idMap[index]) { - this.idMap.push(guid()); - } - queue.id = this.idMap[index]; - } - queuesControls.push(this.fb.control(queue, [Validators.required])); - }); - } - this.tenantProfileQueuesFormGroup.setControl('queues', this.fb.array(queuesControls)); - if (this.disabled) { - this.tenantProfileQueuesFormGroup.disable({emitEvent: false}); + if (queues.length === this.queuesFormArray.length) { + this.queuesFormArray.patchValue(queues, {emitEvent: false}); } else { - this.tenantProfileQueuesFormGroup.enable({emitEvent: false}); + const queuesControls: Array = []; + if (queues) { + queues.forEach((queue, index) => { + if (!queue.id) { + if (!this.idMap[index]) { + this.idMap.push(guid()); + } + queue.id = this.idMap[index]; + } + queuesControls.push(this.fb.control(queue, [Validators.required])); + }); + } + this.tenantProfileQueuesFormGroup.setControl('queues', this.fb.array(queuesControls), {emitEvent: false}); + if (this.disabled) { + this.tenantProfileQueuesFormGroup.disable({emitEvent: false}); + } else { + this.tenantProfileQueuesFormGroup.enable({emitEvent: false}); + } } - this.valueChangeSubscription$ = this.tenantProfileQueuesFormGroup.valueChanges.subscribe(() => - this.updateModel() - ); } public trackByQueue(index: number, queueControl: AbstractControl) { diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant/rate-limits/rate-limits.models.ts b/ui-ngx/src/app/modules/home/components/profile/tenant/rate-limits/rate-limits.models.ts index 70fb7af11f..09ae3f5139 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant/rate-limits/rate-limits.models.ts +++ b/ui-ngx/src/app/modules/home/components/profile/tenant/rate-limits/rate-limits.models.ts @@ -45,7 +45,7 @@ export const rateLimitsLabelTranslationMap = new Map( [RateLimitsType.DEVICE_MESSAGES, 'tenant-profile.rate-limits.transport-device-msg'], [RateLimitsType.DEVICE_TELEMETRY_MESSAGES, 'tenant-profile.rate-limits.transport-device-telemetry-msg'], [RateLimitsType.DEVICE_TELEMETRY_DATA_POINTS, 'tenant-profile.rate-limits.transport-device-telemetry-data-points'], - [RateLimitsType.TENANT_SERVER_REST_LIMITS_CONFIGURATION, 'tenant-profile.transport-tenant-msg-rate-limit'], + [RateLimitsType.TENANT_SERVER_REST_LIMITS_CONFIGURATION, 'tenant-profile.rest-requests-for-tenant'], [RateLimitsType.CUSTOMER_SERVER_REST_LIMITS_CONFIGURATION, 'tenant-profile.customer-rest-limits'], [RateLimitsType.WS_UPDATE_PER_SESSION_RATE_LIMIT, 'tenant-profile.ws-limit-updates-per-session'], [RateLimitsType.CASSANDRA_QUERY_TENANT_RATE_LIMITS_CONFIGURATION, 'tenant-profile.cassandra-tenant-limits-configuration'], @@ -63,7 +63,7 @@ export const rateLimitsDialogTitleTranslationMap = new Map
-
+
relation.type entity.entity-types  
-
+
+ *ngFor="let relationFilterControl of relationFiltersFormArray.controls; let $index = index">
-
+
relation.any-relation
diff --git a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.ts b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.ts index 31e9ca2f9f..aa027c4846 100644 --- a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.ts +++ b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'; import { AbstractControl, ControlValueAccessor, @@ -28,7 +28,8 @@ import { RelationEntityTypeFilter } from '@shared/models/relation.models'; import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { Subscription } from 'rxjs'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'tb-relation-filters', @@ -42,7 +43,7 @@ import { Subscription } from 'rxjs'; } ] }) -export class RelationFiltersComponent extends PageComponent implements ControlValueAccessor, OnInit { +export class RelationFiltersComponent extends PageComponent implements ControlValueAccessor, OnInit, OnDestroy { @Input() disabled: boolean; @@ -50,22 +51,32 @@ export class RelationFiltersComponent extends PageComponent implements ControlVa relationFiltersFormGroup: UntypedFormGroup; + private destroy$ = new Subject(); private propagateChange = null; - private valueChangeSubscription: Subscription = null; - constructor(protected store: Store, private fb: UntypedFormBuilder) { super(store); } ngOnInit(): void { - this.relationFiltersFormGroup = this.fb.group({}); - this.relationFiltersFormGroup.addControl('relationFilters', - this.fb.array([])); + this.relationFiltersFormGroup = this.fb.group({ + relationFilters: this.fb.array([]) + }); + + this.relationFiltersFormGroup.valueChanges.pipe( + takeUntil(this.destroy$) + ).subscribe(() => { + this.updateModel(); + }); } - relationFiltersFormArray(): UntypedFormArray { + ngOnDestroy() { + this.destroy$.next(); + this.destroy$.complete(); + } + + get relationFiltersFormArray(): UntypedFormArray { return this.relationFiltersFormGroup.get('relationFilters') as UntypedFormArray; } @@ -81,19 +92,17 @@ export class RelationFiltersComponent extends PageComponent implements ControlVa } writeValue(filters: Array): void { - if (this.valueChangeSubscription) { - this.valueChangeSubscription.unsubscribe(); - } - const relationFiltersControls: Array = []; - if (filters && filters.length) { - filters.forEach((filter) => { - relationFiltersControls.push(this.createRelationFilterFormGroup(filter)); - }); + if (filters?.length === this.relationFiltersFormArray.length) { + this.relationFiltersFormArray.patchValue(filters, {emitEvent: false}); + } else { + const relationFiltersControls: Array = []; + if (filters && filters.length) { + filters.forEach((filter) => { + relationFiltersControls.push(this.createRelationFilterFormGroup(filter)); + }); + } + this.relationFiltersFormGroup.setControl('relationFilters', this.fb.array(relationFiltersControls), {emitEvent: false}); } - this.relationFiltersFormGroup.setControl('relationFilters', this.fb.array(relationFiltersControls)); - this.valueChangeSubscription = this.relationFiltersFormGroup.valueChanges.subscribe(() => { - this.updateModel(); - }); } public removeFilter(index: number) { @@ -101,12 +110,11 @@ export class RelationFiltersComponent extends PageComponent implements ControlVa } public addFilter() { - const relationFiltersFormArray = this.relationFiltersFormGroup.get('relationFilters') as UntypedFormArray; const filter: RelationEntityTypeFilter = { relationType: null, entityTypes: [] }; - relationFiltersFormArray.push(this.createRelationFilterFormGroup(filter)); + this.relationFiltersFormArray.push(this.createRelationFilterFormGroup(filter)); } private createRelationFilterFormGroup(filter: RelationEntityTypeFilter): AbstractControl { diff --git a/ui-ngx/src/app/modules/home/components/vc/repository-settings.component.html b/ui-ngx/src/app/modules/home/components/vc/repository-settings.component.html index 8a6c551359..f510217d39 100644 --- a/ui-ngx/src/app/modules/home/components/vc/repository-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/vc/repository-settings.component.html @@ -15,8 +15,10 @@ limitations under the License. --> -
- +
+ admin.repository-settings @@ -41,10 +43,10 @@ admin.default-branch - - {{ 'admin.repository-read-only' | translate }} - -
+
+ + {{ 'admin.repository-read-only' | translate }} + {{ 'admin.show-merge-commits' | translate }} @@ -74,6 +76,7 @@ +
diff --git a/ui-ngx/src/app/modules/home/components/vc/repository-settings.component.scss b/ui-ngx/src/app/modules/home/components/vc/repository-settings.component.scss index a45a4cbfc1..80df7d9d79 100644 --- a/ui-ngx/src/app/modules/home/components/vc/repository-settings.component.scss +++ b/ui-ngx/src/app/modules/home/components/vc/repository-settings.component.scss @@ -17,9 +17,6 @@ .mat-mdc-card.repository-settings { margin: 8px; } - .mat-mdc-checkbox { - padding-bottom: 16px; - } .fields-group { padding: 0 16px 8px; margin-bottom: 10px; diff --git a/ui-ngx/src/app/modules/home/components/widget/data-key-config.component.scss b/ui-ngx/src/app/modules/home/components/widget/data-key-config.component.scss index f0e7f857a3..e5f6c02ef7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/data-key-config.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/data-key-config.component.scss @@ -101,7 +101,7 @@ &.comparison { .mat-expansion-panel-header { - height: 100%; + height: fit-content; } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts index 5b233ba2d1..18290225b6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts @@ -804,11 +804,13 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, if (descriptors.length) { let entityId; let entityName; + let entityLabel; if (alarm && alarm.originator) { entityId = alarm.originator; entityName = alarm.originatorName; + entityLabel = alarm.originatorLabel; } - this.ctx.actionsApi.handleWidgetAction($event, descriptors[0], entityId, entityName, {alarm}); + this.ctx.actionsApi.handleWidgetAction($event, descriptors[0], entityId, entityName, {alarm}, entityLabel); } } @@ -827,11 +829,13 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, } let entityId; let entityName; + let entityLabel; if (alarm && alarm.originator) { entityId = alarm.originator; entityName = alarm.originatorName; + entityLabel = alarm.originatorLabel; } - this.ctx.actionsApi.handleWidgetAction($event, actionDescriptor, entityId, entityName, {alarm}); + this.ctx.actionsApi.handleWidgetAction($event, actionDescriptor, entityId, entityName, {alarm}, entityLabel); } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.ts b/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.ts index 7e3bb168ae..fcb90b06a4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.ts @@ -405,7 +405,7 @@ export class TbCanvasDigitalGauge { (this.gauge.options as CanvasDigitalGaugeOptions).labelTimestamp = filter.transform(timestamp, this.localSettings.timestampFormat); } - const value = tvPair[1]; + const value = parseFloat(tvPair[1]); if (value !== this.gauge.value) { if (!this.gauge.options.animation) { this.gauge._value = value; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/display-columns-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/display-columns-panel.component.html index a02bd79458..595c32f7a8 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/display-columns-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/display-columns-panel.component.html @@ -17,7 +17,7 @@ -->
- {{ column.title }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html index 3091ac7bc6..c0680dfeb9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html @@ -51,7 +51,7 @@ -
+
{{ 'widgets.table.display-entity-name' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-label.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-label.component.html index ff6b2f6bdc..743ecbf8bb 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-label.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-label.component.html @@ -47,7 +47,7 @@
widgets.label-widget.label-position -
+
widgets.label-widget.x-pos diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/doughnut-chart-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/doughnut-chart-widget-settings.component.html index c1f5a26cf1..6f56ee9ecd 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/doughnut-chart-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/doughnut-chart-widget-settings.component.html @@ -24,7 +24,7 @@
widgets.chart.border-settings -
+
widgets.chart.border-width diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-pie-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-pie-widget-settings.component.html index e860995acf..307a494954 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-pie-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-pie-widget-settings.component.html @@ -41,7 +41,7 @@
widgets.chart.stroke-settings -
+
widgets.chart.width-pixels diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-font.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-font.component.html index 6ec910fa08..1fa1aacd92 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-font.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-font.component.html @@ -16,7 +16,7 @@ -->
-
+
widgets.widget-font.font-family @@ -26,7 +26,7 @@
-
+
widgets.widget-font.font-style @@ -68,7 +68,7 @@
-
+
widgets.rpc.initial-value -
+
widgets.rpc.min-value diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/persistent-table-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/persistent-table-widget-settings.component.html index 5db8315329..34105fa0e9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/persistent-table-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/persistent-table-widget-settings.component.html @@ -33,7 +33,7 @@
-
+
{{ 'widgets.persistent-table.display-request-details' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/rpc-button-style.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/rpc-button-style.component.html index 3e330e78ac..74e782c901 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/rpc-button-style.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/rpc-button-style.component.html @@ -24,7 +24,7 @@ {{ 'widgets.rpc.button-primary' | translate }} -
+
widgets.rpc.slide-toggle-label -
+
widgets.rpc.label-position diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/analogue-compass-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/analogue-compass-widget-settings.component.html index 0de8aabd0a..bbb7874523 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/analogue-compass-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/analogue-compass-widget-settings.component.html @@ -42,7 +42,7 @@ icon="format_color_fill" label="{{ 'widgets.gauge.major-ticks-color' | translate }}" openOnInput colorClearButton> -
+
widgets.gauge.minor-ticks-count @@ -71,7 +71,7 @@ {{ 'widgets.gauge.show-plate-border' | translate }} -
+
widgets.gauge.needle-circle-size -
+
widgets.gauge.ticks-settings -
+
widgets.gauge.min-value @@ -41,7 +41,7 @@
-
+
widgets.gauge.major-ticks-count @@ -52,7 +52,7 @@ label="{{ 'widgets.gauge.major-ticks-color' | translate }}" openOnInput colorClearButton>
-
+
widgets.gauge.minor-ticks-count @@ -127,7 +127,7 @@ widgets.gauge.value-font
-
+
-
+
widgets.gauge.needle-settings -
+
-
+
widgets.gauge.radial-gauge-settings -
+
widgets.gauge.start-ticks-angle @@ -314,7 +314,7 @@
widgets.gauge.linear-gauge-settings -
+
widgets.gauge.bar-stroke-width @@ -325,7 +325,7 @@ label="{{ 'widgets.gauge.bar-stroke-color' | translate }}" openOnInput colorClearButton>
-
+
-
+
widgets.gauge.common-settings -
+
widgets.gauge.min-value @@ -182,7 +182,7 @@
widgets.gauge.unit-title-and-timestamp-settings -
+
{{ 'widgets.gauge.show-unit-title' | translate }} @@ -191,7 +191,7 @@
-
+
{{ 'widgets.gauge.show-timestamp' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/gauge-highlight.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/gauge-highlight.component.html index d03f7dc8a1..f92edfcde5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/gauge-highlight.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/gauge-highlight.component.html @@ -40,7 +40,7 @@
-
+
widgets.gauge.highlight-from diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gpio/gpio-item.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gpio/gpio-item.component.html index 472b52555c..9264b82b3e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gpio/gpio-item.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gpio/gpio-item.component.html @@ -45,7 +45,7 @@
-
+
widgets.gpio.pin @@ -55,7 +55,7 @@
-
+
widgets.gpio.row diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-boolean-attribute-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-boolean-attribute-widget-settings.component.html index f23924c9be..a91f3af9a5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-boolean-attribute-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-boolean-attribute-widget-settings.component.html @@ -28,7 +28,7 @@
widgets.input-widgets.checkbox-settings -
+
widgets.input-widgets.true-label diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-double-attribute-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-double-attribute-widget-settings.component.html index 19b695c4b1..512ccc9f8f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-double-attribute-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-double-attribute-widget-settings.component.html @@ -21,7 +21,7 @@
widgets.input-widgets.double-field-settings -
+
widgets.input-widgets.min-value diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-integer-attribute-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-integer-attribute-widget-settings.component.html index 1ec19405bb..d5ab9c976d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-integer-attribute-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-integer-attribute-widget-settings.component.html @@ -21,7 +21,7 @@
widgets.input-widgets.integer-field-settings -
+
widgets.input-widgets.min-value diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-json-attribute-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-json-attribute-widget-settings.component.html index a80ab4e6e9..732b98dc05 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-json-attribute-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-json-attribute-widget-settings.component.html @@ -37,7 +37,7 @@
widgets.input-widgets.attribute-settings -
+
widgets.input-widgets.widget-mode diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-location-attribute-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-location-attribute-widget-settings.component.html index 0344b51d32..f02f840645 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-location-attribute-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-location-attribute-widget-settings.component.html @@ -25,7 +25,7 @@ {{ 'widgets.input-widgets.show-result-message' | translate }} -
+
widgets.input-widgets.latitude-key-name @@ -47,7 +47,7 @@ {{ 'widgets.input-widgets.show-label' | translate }} -
+
widgets.input-widgets.latitude-label diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-widget-settings.component.html index f6239b3e61..9c250e5968 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-widget-settings.component.html @@ -45,7 +45,7 @@ {{ 'widgets.input-widgets.update-all-values' | translate }} -
+
widgets.input-widgets.save-button-label diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-string-attribute-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-string-attribute-widget-settings.component.html index 2b0f1b4599..53ea6b67c9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-string-attribute-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-string-attribute-widget-settings.component.html @@ -21,7 +21,7 @@
widgets.input-widgets.text-field-settings -
+
widgets.input-widgets.min-length diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/common-map-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/common-map-settings.component.html index 8f9269690e..41648b5168 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/common-map-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/common-map-settings.component.html @@ -18,7 +18,7 @@
widgets.maps.common-map-settings -
+
-
+
widgets.maps.default-map-zoom-level @@ -65,7 +65,7 @@
-
+
{{ 'widgets.maps.disable-scroll-zooming' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/marker-clustering-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/marker-clustering-settings.component.html index 49dfc84c5a..403721f65c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/marker-clustering-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/marker-clustering-settings.component.html @@ -34,7 +34,7 @@ {{ 'widgets.maps.zoom-on-cluster-click' | translate }} -
+
widgets.maps.max-cluster-zoom diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/markers-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/markers-settings.component.html index c1445a867d..2b5de971b5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/markers-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/markers-settings.component.html @@ -18,7 +18,7 @@
widgets.maps.markers-settings -
+
widgets.maps.marker-offset-x @@ -113,7 +113,7 @@ functionTitle="{{ 'widgets.maps.tooltip-function' | translate }}" helpId="widget/lib/map/tooltip_fn"> -
+
widgets.maps.tooltip-offset-x diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/route-map-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/route-map-settings.component.html index 9e7756d092..a22ce3e37e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/route-map-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/route-map-settings.component.html @@ -18,7 +18,7 @@
widgets.maps.route-map-settings -
+
widgets.maps.stroke-weight diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts index 68e89ef8d0..20cf5860b5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts @@ -417,9 +417,6 @@ export function constructTableCssString(widgetConfig: WidgetConfig): string { '.mat-mdc-table .mat-mdc-header-cell {\n' + 'color: ' + mdDarkSecondary + ';\n' + '}\n' + - '.mat-mdc-table .mat-mdc-header-cell .mat-sort-header-arrow {\n' + - 'color: ' + mdDarkDisabled + ';\n' + - '}\n' + '.mat-mdc-table .mat-mdc-cell, .mat-mdc-table .mat-mdc-header-cell {\n' + 'border-bottom-color: ' + mdDarkDivider + ';\n' + '}\n' + 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 0b4c433bef..a4e34029f5 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 @@ -19,8 +19,8 @@
-
+ fxLayout.xs="column" fxLayoutGap.gt-xs="8px" fxLayoutAlign.xs="center" fxLayout="row" fxLayoutAlign="start center"> +
{{ 'widget-config.use-dashboard-timewindow' | translate }} @@ -29,7 +29,7 @@
+ fxFlex.gt-xs> widget-config.timewindow
+ fxLayoutGap.gt-xs="8px"> alarm.alarm-status-list
-
+
alarm.alarm-type-list @@ -355,7 +354,7 @@ {{ 'widget-config.display-title' | translate }} -
+
widget-config.title @@ -365,12 +364,12 @@
-
+
widget-config.title-icon {{ 'widget-config.display-icon' | translate }} -
+
@@ -404,8 +403,8 @@
widget-config.widget-style -
-
+
+
-
+
widget-config.padding @@ -477,8 +476,8 @@
widget-config.mobile-mode-settings - - + + {{ 'widget-config.mobile-hide' | translate }} @@ -491,14 +490,14 @@ -
+
widget-config.order widget-config.height - +
diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts index 46b56a1a36..edc5983a24 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts @@ -255,7 +255,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont }); this.layoutSettings = this.fb.group({ mobileOrder: [null, [Validators.pattern(/^-?[0-9]+$/)]], - mobileHeight: [null, [Validators.min(1), Validators.max(10), Validators.pattern(/^\d*$/)]], + mobileHeight: [null, [Validators.min(1), Validators.pattern(/^\d*$/)]], mobileHide: [false], desktopHide: [false] }); diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html index 4fae225ea9..c1485cf450 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html @@ -15,172 +15,172 @@ limitations under the License. --> -
- -

device.add-device-text

- -
- -
- - -
-
- - - check - - - - {{ 'device.wizard.device-details' | translate}} -
- - device.name - - - {{ 'device.name-required' | translate }} - - - {{ 'device.name-max-length' | translate }} - - - - device.label - - - {{ 'device.label-max-length' | translate }} - - -
- - - device.wizard.existing-device-profile - - - device.wizard.new-device-profile - - -
- - - - device-profile.new-device-profile-name - - - {{ 'device-profile.new-device-profile-name-required' | translate }} - - -
-
- - -
-
- - -
+ +

device.add-device-text

+ +
+ +
+ + +
+
+ + + check + + + + {{ 'device.wizard.device-details' | translate}} +
+ + device.name + + + {{ 'device.name-required' | translate }} + + + {{ 'device.name-max-length' | translate }} + + + + device.label + + + {{ 'device.label-max-length' | translate }} + + +
+ + + device.wizard.existing-device-profile + + + device.wizard.new-device-profile + + +
+ + + + device-profile.new-device-profile-name + + + {{ 'device-profile.new-device-profile-name-required' | translate }} + +
-
- - {{ 'device.is-gateway' | translate }} - - - {{ 'device.overwrite-activity-time' | translate }} - +
+ +
- - device.description - - -
- -
- -
- {{ 'device-profile.transport-configuration' | translate }} - device-profile.transport-type - - - {{deviceTransportTypeTranslations.get(type) | translate}} - - - - {{deviceTransportTypeHints.get(transportConfigFormGroup.get('transportType').value) | translate}} - - - {{ 'device-profile.transport-type-required' | translate }} - - - - -
-
- -
- {{'device-profile.alarm-rules-with-count' | translate: - {count: alarmRulesFormGroup.get('alarms').value ? - alarmRulesFormGroup.get('alarms').value.length : 0} }} - - -
-
- -
- {{ 'device-profile.device-provisioning' | translate }} - - -
-
- - {{ 'device.credentials' | translate }} -
- {{ 'device.wizard.add-credentials' | translate }} - - -
-
- - {{ 'customer.customer' | translate }} -
- - -
-
-
-
-
+
+ + +
+
+
+ + {{ 'device.is-gateway' | translate }} + + + {{ 'device.overwrite-activity-time' | translate }} + +
+ + device.description + + +
+ +
+ +
+ {{ 'device-profile.transport-configuration' | translate }} + device-profile.transport-type + + + {{deviceTransportTypeTranslations.get(type) | translate}} + + + + {{deviceTransportTypeHints.get(transportConfigFormGroup.get('transportType').value) | translate}} + + + {{ 'device-profile.transport-type-required' | translate }} + + + + +
+
+ +
+ {{'device-profile.alarm-rules-with-count' | translate: + {count: alarmRulesFormGroup.get('alarms').value ? + alarmRulesFormGroup.get('alarms').value.length : 0} }} + + +
+
+ +
+ {{ 'device-profile.device-provisioning' | translate }} + + +
+
+ + {{ 'device.credentials' | translate }} +
+ {{ 'device.wizard.add-credentials' | translate }} + + +
+
+ + {{ 'customer.customer' | translate }} +
+ + +
+
+
+
+
+
@@ -191,8 +191,8 @@ [disabled]="(isLoading$ | async)" (click)="nextStep()">{{ 'action.next-with-label' | translate:{label: (getFormLabel(this.selectedIndex+1) | translate)} }}
- -
+ +
diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.scss b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.scss index 292d6b3867..0fe18467fd 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.scss @@ -15,6 +15,15 @@ */ @import "../../../../../scss/constants"; +:host { + height: 100%; + display: grid; + + .dialog-actions-row { + padding: 8px; + } +} + :host-context(.tb-fullscreen-dialog .mat-mdc-dialog-container) { @media #{$mat-lt-sm} { .mat-mdc-dialog-content { @@ -36,31 +45,21 @@ .mat-stepper-horizontal { display: flex; - flex-direction: column; height: 100%; overflow: hidden; - @media #{$mat-lt-sm} { - .mat-step-label { - white-space: normal; - overflow: visible; - .mat-step-text-label { - overflow: visible; - } - } + + .mat-horizontal-stepper-wrapper { + flex: 1 1 100%; } + .mat-horizontal-content-container { - height: 530px; + height: 680px; max-height: 100%; width: 100%;; overflow-y: auto; + scrollbar-gutter: stable; @media #{$mat-gt-sm} { - min-width: 800px; - } - } - .mat-horizontal-stepper-content[aria-expanded=true] { - height: 100%; - form { - height: 100%; + min-width: 500px; } } } diff --git a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.html b/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.html index 61367ab02f..3514b0d919 100644 --- a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.html +++ b/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.html @@ -124,13 +124,13 @@
-
dashboard.mobile-app-settings
+
dashboard.mobile-app-settings
- + {{ 'dashboard.mobile-hide' | translate }} diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-library.component.scss b/ui-ngx/src/app/modules/home/pages/widget/widget-library.component.scss index c0f3e21329..8fcd595570 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-library.component.scss +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-library.component.scss @@ -15,6 +15,7 @@ */ :host { button.tb-add-new-widget { + height: auto; padding-right: 12px; font-size: 24px; border-style: dashed; diff --git a/ui-ngx/src/app/shared/components/dashboard-select.component.ts b/ui-ngx/src/app/shared/components/dashboard-select.component.ts index c14e3924d2..40db63932a 100644 --- a/ui-ngx/src/app/shared/components/dashboard-select.component.ts +++ b/ui-ngx/src/app/shared/components/dashboard-select.component.ts @@ -16,6 +16,7 @@ import { Component, + ElementRef, forwardRef, Inject, Injector, @@ -45,8 +46,7 @@ import { WINDOW } from '@core/services/window.service'; import { ComponentPortal } from '@angular/cdk/portal'; import { DASHBOARD_SELECT_PANEL_DATA, - DashboardSelectPanelComponent, - DashboardSelectPanelData + DashboardSelectPanelComponent } from './dashboard-select-panel.component'; import { NULL_UUID } from '@shared/models/id/has-uuid'; @@ -97,6 +97,7 @@ export class DashboardSelectComponent implements ControlValueAccessor, OnInit { private overlay: Overlay, private breakpointObserver: BreakpointObserver, private viewContainerRef: ViewContainerRef, + private nativeElement: ElementRef, @Inject(DOCUMENT) private document: Document, @Inject(WINDOW) private window: Window) { } @@ -131,77 +132,48 @@ export class DashboardSelectComponent implements ControlValueAccessor, OnInit { } openDashboardSelectPanel() { - if (this.disabled) { - return; - } - const panelHeight = this.breakpointObserver.isMatched('min-height: 350px') ? 250 : 150; - const panelWidth = 300; - const position = this.overlay.position(); - const config = new OverlayConfig({ - panelClass: 'tb-dashboard-select-panel', - backdropClass: 'cdk-overlay-transparent-backdrop', - hasBackdrop: true, - }); - const el = this.dashboardSelectPanelOrigin.elementRef.nativeElement; - const offset = el.getBoundingClientRect(); - const scrollTop = this.window.pageYOffset || this.document.documentElement.scrollTop || this.document.body.scrollTop || 0; - const scrollLeft = this.window.pageXOffset || this.document.documentElement.scrollLeft || this.document.body.scrollLeft || 0; - const bottomY = offset.bottom - scrollTop; - const leftX = offset.left - scrollLeft; - let originX; - let originY; - let overlayX; - let overlayY; - const wHeight = this.document.documentElement.clientHeight; - const wWidth = this.document.documentElement.clientWidth; - if (bottomY + panelHeight > wHeight) { - originY = 'top'; - overlayY = 'bottom'; - } else { - originY = 'bottom'; - overlayY = 'top'; - } - if (leftX + panelWidth > wWidth) { - originX = 'end'; - overlayX = 'end'; - } else { - originX = 'start'; - overlayX = 'start'; - } - const connectedPosition: ConnectedPosition = { - originX, - originY, - overlayX, - overlayY - }; - config.positionStrategy = position.flexibleConnectedTo(this.dashboardSelectPanelOrigin.elementRef) - .withPositions([connectedPosition]); - const overlayRef = this.overlay.create(config); - overlayRef.backdropClick().subscribe(() => { - overlayRef.dispose(); - }); - - const injector = this._createDashboardSelectPanelInjector( - overlayRef, - { - dashboards$: this.dashboards$, - dashboardId: this.dashboardId, - onDashboardSelected: (dashboardId) => { - overlayRef.dispose(); - this.dashboardId = dashboardId; - this.updateView(); + if (!this.disabled) { + const config = new OverlayConfig({ + panelClass: 'tb-dashboard-select-panel', + backdropClass: 'cdk-overlay-transparent-backdrop', + hasBackdrop: true + }); + + const connectedPosition: ConnectedPosition = { + originX: 'start', + originY: 'bottom', + overlayX: 'start', + overlayY: 'top' + }; + + config.positionStrategy = this.overlay.position().flexibleConnectedTo(this.nativeElement) + .withPositions([connectedPosition]); + const overlayRef = this.overlay.create(config); + overlayRef.backdropClick().subscribe(() => { + overlayRef.dispose(); + }); + + const providers: StaticProvider[] = [ + { + provide: DASHBOARD_SELECT_PANEL_DATA, + useValue: { + dashboards$: this.dashboards$, + dashboardId: this.dashboardId, + onDashboardSelected: (dashboardId) => { + overlayRef.dispose(); + this.dashboardId = dashboardId; + this.updateView(); + } + } + }, + { + provide: OverlayRef, + useValue: overlayRef } - } - ); - overlayRef.attach(new ComponentPortal(DashboardSelectPanelComponent, this.viewContainerRef, injector)); - } - - private _createDashboardSelectPanelInjector(overlayRef: OverlayRef, data: DashboardSelectPanelData): Injector { - const providers: StaticProvider[] = [ - {provide: DASHBOARD_SELECT_PANEL_DATA, useValue: data}, - {provide: OverlayRef, useValue: overlayRef} - ]; - return Injector.create({parent: this.viewContainerRef.injector, providers}); + ]; + const injector = Injector.create({parent: this.viewContainerRef.injector, providers}); + overlayRef.attach(new ComponentPortal(DashboardSelectPanelComponent, this.viewContainerRef, injector)); + } } private updateView() { diff --git a/ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.html b/ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.html index 2b69495a3c..6d8a424352 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.html +++ b/ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.html @@ -16,7 +16,7 @@ --> - {{ entityText | translate }} + {{ label | translate }} - {{ entityRequiredText | translate }} + {{ requiredErrorText | translate }} diff --git a/ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.ts b/ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.ts index 18a79fdb51..6a7e6c087c 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.ts +++ b/ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.ts @@ -36,10 +36,10 @@ import { AliasEntityType, EntityType } from '@shared/models/entity-type.models'; import { BaseData } from '@shared/models/base-data'; import { EntityId } from '@shared/models/id/entity-id'; import { EntityService } from '@core/http/entity.service'; -import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { getCurrentAuthUser } from '@core/auth/auth.selectors'; import { Authority } from '@shared/models/authority.enum'; import { isEqual } from '@core/utils'; +import { coerceBoolean } from '@shared/decorators/coerce-boolean'; @Component({ selector: 'tb-entity-autocomplete', @@ -61,6 +61,22 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit entitySubtypeValue: string; + entityText: string; + + noEntitiesMatchingText: string; + + entityRequiredText: string; + + filteredEntities: Observable>>; + + searchText = ''; + + private dirty = false; + + private refresh$ = new Subject>>(); + + private propagateChange = (v: any) => { }; + @Input() set entityType(entityType: EntityType) { if (this.entityTypeValue !== entityType) { @@ -100,16 +116,12 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit @Input() appearance: MatFormFieldAppearance = 'fill'; - private requiredValue: boolean; - get required(): boolean { - return this.requiredValue; - } @Input() - set required(value: boolean) { - this.requiredValue = coerceBooleanProperty(value); - } + @coerceBoolean() + required: boolean; @Input() + @coerceBoolean() disabled: boolean; @Output() @@ -117,19 +129,20 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit @ViewChild('entityInput', {static: true}) entityInput: ElementRef; - entityText: string; - noEntitiesMatchingText: string; - entityRequiredText: string; - - filteredEntities: Observable>>; - - searchText = ''; - - private dirty = false; + get requiredErrorText(): string { + if (this.requiredText && this.requiredText.length) { + return this.requiredText; + } + return this.entityRequiredText; + } - private refresh$ = new Subject>>(); + get label(): string { + if (this.labelText && this.labelText.length) { + return this.labelText; + } + return this.entityText; + } - private propagateChange = (v: any) => { }; constructor(private store: Store, public translate: TranslateService, @@ -249,12 +262,6 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit break; } } - if (this.labelText && this.labelText.length) { - this.entityText = this.labelText; - } - if (this.requiredText && this.requiredText.length) { - this.entityRequiredText = this.requiredText; - } const currentEntity = this.getCurrentEntity(); if (currentEntity) { const currentEntityType = currentEntity.id.entityType; @@ -342,12 +349,9 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit map((data) => { if (data) { if (this.excludeEntityIds && this.excludeEntityIds.length) { + const excludeEntityIdsSet = new Set(this.excludeEntityIds); const entities: Array> = []; - data.forEach((entity) => { - if (this.excludeEntityIds.indexOf(entity.id.id) === -1) { - entities.push(entity); - } - }); + data.forEach(entity => !excludeEntityIdsSet.has(entity.id.id) && entities.push(entity)); return entities; } else { return data; diff --git a/ui-ngx/src/app/shared/components/entity/entity-subtype-autocomplete.component.html b/ui-ngx/src/app/shared/components/entity/entity-subtype-autocomplete.component.html index ff2be0d53e..bc03a7f61b 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-subtype-autocomplete.component.html +++ b/ui-ngx/src/app/shared/components/entity/entity-subtype-autocomplete.component.html @@ -15,7 +15,7 @@ limitations under the License. --> - + {{ entitySubtypeText | translate }} ; + + @Input() + appearance: MatFormFieldAppearance = 'fill'; + @ViewChild('subTypeInput', {static: true}) subTypeInput: ElementRef; selectEntitySubtypeText: string; @@ -238,9 +245,14 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, break; } if (subTypesObservable) { + const excludeSubTypesSet = new Set(this.excludeSubTypes); this.subTypes = subTypesObservable.pipe( catchError(() => of([] as Array)), - map(subTypes => subTypes.map(subType => subType.type)), + map(subTypes => { + const filteredSubTypes: Array = []; + subTypes.forEach(subType => !excludeSubTypesSet.has(subType.type) && filteredSubTypes.push(subType.type)); + return filteredSubTypes; + }), publishReplay(1), refCount() ); diff --git a/ui-ngx/src/app/shared/components/help.component.html b/ui-ngx/src/app/shared/components/help.component.html index c5603ad2cd..5ebac09c00 100644 --- a/ui-ngx/src/app/shared/components/help.component.html +++ b/ui-ngx/src/app/shared/components/help.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -