diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule.component.ts b/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule.component.ts index e9a6428533..fe2916b854 100644 --- a/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule.component.ts @@ -29,7 +29,7 @@ import { AlarmConditionType, AlarmConditionTypeTranslationMap, AlarmRule } from import { MatDialog } from '@angular/material/dialog'; import { TimeUnit, timeUnitTranslationMap } from '@shared/models/time/time.models'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; -import { isDefinedAndNotNull } from '@core/utils'; +import { isUndefined } from '@core/utils'; @Component({ selector: 'tb-alarm-rule', @@ -118,11 +118,11 @@ export class AlarmRuleComponent implements ControlValueAccessor, OnInit, Validat writeValue(value: AlarmRule): void { this.modelValue = value; - if (!isDefinedAndNotNull(this.modelValue?.condition?.spec)) { - this.modelValue = Object.assign({}, this.modelValue, {condition: {spec: {type: AlarmConditionType.SIMPLE}}}); + if (this.modelValue !== null && isUndefined(this.modelValue?.condition?.spec)) { + this.modelValue = Object.assign(this.modelValue, {condition: {spec: {type: AlarmConditionType.SIMPLE}}}); } this.alarmRuleFormGroup.reset(this.modelValue || undefined, {emitEvent: false}); - this.updateValidators(this.modelValue.condition.spec.type); + this.updateValidators(this.modelValue?.condition?.spec?.type); } public validate(c: FormControl) { diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-schedule.component.html b/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-schedule.component.html index cad6e5cf03..03c0586bb3 100644 --- a/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-schedule.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-schedule.component.html @@ -35,7 +35,7 @@
device-profile.schedule-days
-
+
{{ 'device-profile.schedule-day.monday' | translate }} @@ -64,158 +64,189 @@
device-profile.schedule-time
- - device-profile.schedule-time-from - - - - - - device-profile.schedule-time-to - - - - +
+ + device-profile.schedule-time-from + + + + + + device-profile.schedule-time-to + + + + +
+
+
+
+
device-profile.schedule-days
-
-
-
- - {{ 'device-profile.schedule-day.monday' | translate }} - -
- - device-profile.schedule-time-from - - - - - - device-profile.schedule-time-to - - - - -
+
+
+ + {{ 'device-profile.schedule-day.monday' | translate }} + +
+ + device-profile.schedule-time-from + + + + + + device-profile.schedule-time-to + + + +
-
- - {{ 'device-profile.schedule-day.tuesday' | translate }} - -
- - device-profile.schedule-time-from - - - - - - device-profile.schedule-time-to - - - - -
+
-
- - {{ 'device-profile.schedule-day.wednesday' | translate }} - -
- - device-profile.schedule-time-from - - - - - - device-profile.schedule-time-to - - - - -
+
+
+ + {{ 'device-profile.schedule-day.tuesday' | translate }} + +
+ + device-profile.schedule-time-from + + + + + + device-profile.schedule-time-to + + + +
-
- - {{ 'device-profile.schedule-day.thursday' | translate }} - -
- - device-profile.schedule-time-from - - - - - - device-profile.schedule-time-to - - - - -
+
-
-
- - {{ 'device-profile.schedule-day.friday' | translate }} - -
- - device-profile.schedule-time-from - - - - - - device-profile.schedule-time-to - - - - -
+
+ + {{ 'device-profile.schedule-day.wednesday' | translate }} + +
+ + device-profile.schedule-time-from + + + + + + device-profile.schedule-time-to + + + + +
+
+
+
+
+ + {{ 'device-profile.schedule-day.thursday' | translate }} + +
+ + device-profile.schedule-time-from + + + + + + device-profile.schedule-time-to + + + +
-
- - {{ 'device-profile.schedule-day.saturday' | translate }} - -
- - device-profile.schedule-time-from - - - - - - device-profile.schedule-time-to - - - - -
+
+
+
+
+ + {{ 'device-profile.schedule-day.friday' | translate }} + +
+ + device-profile.schedule-time-from + + + + + + device-profile.schedule-time-to + + + + +
+
+
+
+
+ + {{ 'device-profile.schedule-day.saturday' | translate }} + +
+ + device-profile.schedule-time-from + + + + + + device-profile.schedule-time-to + + + + +
+
+
+
+
+ + {{ 'device-profile.schedule-day.sunday' | translate }} + +
+ + device-profile.schedule-time-from + + + + + + device-profile.schedule-time-to + + + +
-
- - {{ 'device-profile.schedule-day.sunday' | translate }} - -
- - device-profile.schedule-time-from - - - - - - device-profile.schedule-time-to - - - - -
+
diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-schedule.component.scss b/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-schedule.component.scss new file mode 100644 index 0000000000..1746a5fbf5 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-schedule.component.scss @@ -0,0 +1,20 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +::ng-deep { + .nowrap { + white-space: nowrap; + } +} diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-schedule.component.ts b/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-schedule.component.ts index 8cf9dc8d30..0062687d5d 100644 --- a/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-schedule.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-schedule.component.ts @@ -16,6 +16,7 @@ import { Component, forwardRef, Input, OnInit } from '@angular/core'; import { + AbstractControl, ControlValueAccessor, FormArray, FormBuilder, @@ -35,6 +36,7 @@ import { MatCheckboxChange } from '@angular/material/checkbox'; @Component({ selector: 'tb-alarm-schedule', templateUrl: './alarm-schedule.component.html', + styleUrls: ['./alarm-schedule.component.scss'], providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => AlarmScheduleComponent), @@ -79,7 +81,7 @@ export class AlarmScheduleComponent implements ControlValueAccessor, Validator, items: this.fb.array(Array.from({length: 7}, (value, i) => this.defaultItemsScheduler(i))) }); this.alarmScheduleForm.get('type').valueChanges.subscribe((type) => { - this.alarmScheduleForm.reset({type, items: this.defaultItems}, {emitEvent: false}); + this.alarmScheduleForm.reset({type, items: this.defaultItems, timezone: this.defaultTimezone}, {emitEvent: false}); this.updateValidators(type, true); this.alarmScheduleForm.updateValueAndValidity(); }); @@ -131,13 +133,7 @@ export class AlarmScheduleComponent implements ControlValueAccessor, Validator, this.modelValue.items .sort((a, b) => a.dayOfWeek - b.dayOfWeek) .forEach((item, index) => { - if (item.enabled) { - this.itemsSchedulerForm.at(index).get('startsOn').enable({emitEvent: false}); - this.itemsSchedulerForm.at(index).get('endsOn').enable({emitEvent: false}); - } else { - this.itemsSchedulerForm.at(index).get('startsOn').disable({emitEvent: false}); - this.itemsSchedulerForm.at(index).get('endsOn').disable({emitEvent: false}); - } + this.disabledSelectedTime(item.enabled, index); alarmDays.push({ enabled: item.enabled, startsOn: this.timestampToTime(item.startsOn), @@ -206,15 +202,15 @@ export class AlarmScheduleComponent implements ControlValueAccessor, Validator, .filter(day => !!day); } if (isDefined(value.startsOn) && value.startsOn !== 0) { - value.startsOn = this.timeToTimestamp(value.startsOn); + value.startsOn = this.timeToTimestampUTC(value.startsOn); } if (isDefined(value.endsOn) && value.endsOn !== 0) { - value.endsOn = this.timeToTimestamp(value.endsOn); + value.endsOn = this.timeToTimestampUTC(value.endsOn); } if (isDefined(value.items)){ value.items = this.alarmScheduleForm.getRawValue().items; value.items = value.items.map((item) => { - return { ...item, startsOn: this.timeToTimestamp(item.startsOn), endsOn: this.timeToTimestamp(item.endsOn)}; + return { ...item, startsOn: this.timeToTimestampUTC(item.startsOn), endsOn: this.timeToTimestampUTC(item.endsOn)}; }); } this.modelValue = value; @@ -222,7 +218,7 @@ export class AlarmScheduleComponent implements ControlValueAccessor, Validator, } } - private timeToTimestamp(date: Date | number): number { + private timeToTimestampUTC(date: Date | number): number { if (typeof date === 'number' || date === null) { return 0; } @@ -244,16 +240,39 @@ export class AlarmScheduleComponent implements ControlValueAccessor, Validator, changeCustomScheduler($event: MatCheckboxChange, index: number) { const value = $event.checked; - if (value) { + this.disabledSelectedTime(value, index, true); + } + + private disabledSelectedTime(enable: boolean, index: number, emitEvent = false) { + if (enable) { this.itemsSchedulerForm.at(index).get('startsOn').enable({emitEvent: false}); - this.itemsSchedulerForm.at(index).get('endsOn').enable(); + this.itemsSchedulerForm.at(index).get('endsOn').enable({emitEvent}); } else { this.itemsSchedulerForm.at(index).get('startsOn').disable({emitEvent: false}); - this.itemsSchedulerForm.at(index).get('endsOn').disable(); + this.itemsSchedulerForm.at(index).get('endsOn').disable({emitEvent}); + } + } + + private timeToMoment(date: Date | number): _moment.Moment { + if (typeof date === 'number' || date === null) { + return _moment([1970, 0, 1, 0, 0, 0, 0]); + } + return _moment([1970, 0, 1, date.getHours(), date.getMinutes(), 0, 0]); + } + + getSchedulerRangeText(control: FormGroup | AbstractControl): string { + const start = this.timeToMoment(control.get('startsOn').value); + const end = this.timeToMoment(control.get('endsOn').value); + if (start < end) { + return `${start.format('hh:mm A')}${end.format('hh:mm A')}`; + } else if (start.valueOf() === 0 && end.valueOf() === 0 || start.isSame(_moment([1970, 0])) && end.isSame(_moment([1970, 0]))) { + return '12:00 AM12:00 PM'; } + return `12:00 AM${end.format('hh:mm A')}` + + ` and ${start.format('hh:mm A')}12:00 PM`; } - private get itemsSchedulerForm(): FormArray { + get itemsSchedulerForm(): FormArray { return this.alarmScheduleForm.get('items') as FormArray; } } diff --git a/ui-ngx/src/app/modules/home/pages/device-profile/device-profile-tabs.component.html b/ui-ngx/src/app/modules/home/pages/device-profile/device-profile-tabs.component.html index 7531eed659..9a79af3202 100644 --- a/ui-ngx/src/app/modules/home/pages/device-profile/device-profile-tabs.component.html +++ b/ui-ngx/src/app/modules/home/pages/device-profile/device-profile-tabs.component.html @@ -39,7 +39,7 @@