Commit 76485dfdaddcb989c9e5196008eb4acfb8d62bbf

Authored by Vladyslav_Prykhodko
1 parent 30a6a462

UI: Improvement UI device profile alarm scheduler, added text select time interval

@@ -29,7 +29,7 @@ import { AlarmConditionType, AlarmConditionTypeTranslationMap, AlarmRule } from @@ -29,7 +29,7 @@ import { AlarmConditionType, AlarmConditionTypeTranslationMap, AlarmRule } from
29 import { MatDialog } from '@angular/material/dialog'; 29 import { MatDialog } from '@angular/material/dialog';
30 import { TimeUnit, timeUnitTranslationMap } from '@shared/models/time/time.models'; 30 import { TimeUnit, timeUnitTranslationMap } from '@shared/models/time/time.models';
31 import { coerceBooleanProperty } from '@angular/cdk/coercion'; 31 import { coerceBooleanProperty } from '@angular/cdk/coercion';
32 -import { isDefinedAndNotNull } from '@core/utils'; 32 +import { isUndefined } from '@core/utils';
33 33
34 @Component({ 34 @Component({
35 selector: 'tb-alarm-rule', 35 selector: 'tb-alarm-rule',
@@ -118,11 +118,11 @@ export class AlarmRuleComponent implements ControlValueAccessor, OnInit, Validat @@ -118,11 +118,11 @@ export class AlarmRuleComponent implements ControlValueAccessor, OnInit, Validat
118 118
119 writeValue(value: AlarmRule): void { 119 writeValue(value: AlarmRule): void {
120 this.modelValue = value; 120 this.modelValue = value;
121 - if (!isDefinedAndNotNull(this.modelValue?.condition?.spec)) {  
122 - this.modelValue = Object.assign({}, this.modelValue, {condition: {spec: {type: AlarmConditionType.SIMPLE}}}); 121 + if (this.modelValue !== null && isUndefined(this.modelValue?.condition?.spec)) {
  122 + this.modelValue = Object.assign(this.modelValue, {condition: {spec: {type: AlarmConditionType.SIMPLE}}});
123 } 123 }
124 this.alarmRuleFormGroup.reset(this.modelValue || undefined, {emitEvent: false}); 124 this.alarmRuleFormGroup.reset(this.modelValue || undefined, {emitEvent: false});
125 - this.updateValidators(this.modelValue.condition.spec.type); 125 + this.updateValidators(this.modelValue?.condition?.spec?.type);
126 } 126 }
127 127
128 public validate(c: FormControl) { 128 public validate(c: FormControl) {
@@ -35,7 +35,7 @@ @@ -35,7 +35,7 @@
35 </tb-timezone-select> 35 </tb-timezone-select>
36 <section *ngIf="alarmScheduleForm.get('type').value === alarmScheduleType.SPECIFIC_TIME"> 36 <section *ngIf="alarmScheduleForm.get('type').value === alarmScheduleType.SPECIFIC_TIME">
37 <div class="tb-small" style="margin-bottom: 0.5em" translate>device-profile.schedule-days</div> 37 <div class="tb-small" style="margin-bottom: 0.5em" translate>device-profile.schedule-days</div>
38 - <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="16px" style="padding-bottom: 16px;"> 38 + <div fxLayout="column" fxLayout.gt-md="row" fxLayoutGap="16px" style="padding-bottom: 16px;">
39 <div fxLayout="row" fxLayoutGap="16px"> 39 <div fxLayout="row" fxLayoutGap="16px">
40 <mat-checkbox [formControl]="weeklyRepeatControl(0)"> 40 <mat-checkbox [formControl]="weeklyRepeatControl(0)">
41 {{ 'device-profile.schedule-day.monday' | translate }} 41 {{ 'device-profile.schedule-day.monday' | translate }}
@@ -64,158 +64,189 @@ @@ -64,158 +64,189 @@
64 </div> 64 </div>
65 <div class="tb-small" style="margin-bottom: 0.5em" translate>device-profile.schedule-time</div> 65 <div class="tb-small" style="margin-bottom: 0.5em" translate>device-profile.schedule-time</div>
66 <div fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px"> 66 <div fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px">
67 - <mat-form-field fxFlex>  
68 - <mat-label translate>device-profile.schedule-time-from</mat-label>  
69 - <mat-datetimepicker-toggle [for]="startTimePicker" matPrefix></mat-datetimepicker-toggle>  
70 - <mat-datetimepicker #startTimePicker type="time" openOnFocus="true"></mat-datetimepicker>  
71 - <input required matInput formControlName="startsOn" [matDatetimepicker]="startTimePicker">  
72 - </mat-form-field>  
73 - <mat-form-field fxFlex>  
74 - <mat-label translate>device-profile.schedule-time-to</mat-label>  
75 - <mat-datetimepicker-toggle [for]="endTimePicker" matPrefix></mat-datetimepicker-toggle>  
76 - <mat-datetimepicker #endTimePicker type="time" openOnFocus="true"></mat-datetimepicker>  
77 - <input required matInput formControlName="endsOn" [matDatetimepicker]="endTimePicker">  
78 - </mat-form-field> 67 + <div fxLayout="row" fxLayoutGap="8px" fxFlex.gt-md>
  68 + <mat-form-field fxFlex.xs fxFlex.sm="150px" fxFlex.md="150px" fxFlex.gt-md>
  69 + <mat-label translate>device-profile.schedule-time-from</mat-label>
  70 + <mat-datetimepicker-toggle [for]="startTimePicker" matPrefix></mat-datetimepicker-toggle>
  71 + <mat-datetimepicker #startTimePicker type="time" openOnFocus="true"></mat-datetimepicker>
  72 + <input required matInput formControlName="startsOn" [matDatetimepicker]="startTimePicker">
  73 + </mat-form-field>
  74 + <mat-form-field fxFlex.xs fxFlex.sm="150px" fxFlex.md="150px" fxFlex.gt-md>
  75 + <mat-label translate>device-profile.schedule-time-to</mat-label>
  76 + <mat-datetimepicker-toggle [for]="endTimePicker" matPrefix></mat-datetimepicker-toggle>
  77 + <mat-datetimepicker #endTimePicker type="time" openOnFocus="true"></mat-datetimepicker>
  78 + <input required matInput formControlName="endsOn" [matDatetimepicker]="endTimePicker">
  79 + </mat-form-field>
  80 + </div>
  81 + <div fxFlex fxLayoutAlign="center center" style="margin: auto">
  82 + <div style="text-align: center"
  83 + [innerHTML]="getSchedulerRangeText(alarmScheduleForm)">
  84 + </div>
  85 + </div>
79 </div> 86 </div>
80 </section> 87 </section>
81 <section *ngIf="alarmScheduleForm.get('type').value === alarmScheduleType.CUSTOM"> 88 <section *ngIf="alarmScheduleForm.get('type').value === alarmScheduleType.CUSTOM">
82 <div class="tb-small" style="margin-bottom: 0.5em" translate>device-profile.schedule-days</div> 89 <div class="tb-small" style="margin-bottom: 0.5em" translate>device-profile.schedule-days</div>
83 - <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.gt-sm="16px" formArrayName="items">  
84 - <div fxLayout="column" fxFlex fxFlex.gt-sm="50">  
85 - <div fxLayout="row" fxLayoutGap="8px" formGroupName="0" fxLayoutAlign="start center">  
86 - <mat-checkbox formControlName="enabled" fxFlex="40" (change)="changeCustomScheduler($event, 0)">  
87 - {{ 'device-profile.schedule-day.monday' | translate }}  
88 - </mat-checkbox>  
89 - <div fxLayout="row" fxLayoutGap="8px" fxFlex>  
90 - <mat-form-field fxFlex="100px">  
91 - <mat-label translate>device-profile.schedule-time-from</mat-label>  
92 - <mat-datetimepicker-toggle [for]="startTimePicker1" matPrefix></mat-datetimepicker-toggle>  
93 - <mat-datetimepicker #startTimePicker1 type="time" openOnFocus="true"></mat-datetimepicker>  
94 - <input required matInput formControlName="startsOn" [matDatetimepicker]="startTimePicker1">  
95 - </mat-form-field>  
96 - <mat-form-field fxFlex="100px">  
97 - <mat-label translate>device-profile.schedule-time-to</mat-label>  
98 - <mat-datetimepicker-toggle [for]="endTimePicker1" matPrefix></mat-datetimepicker-toggle>  
99 - <mat-datetimepicker #endTimePicker1 type="time" openOnFocus="true"></mat-datetimepicker>  
100 - <input required matInput formControlName="endsOn" [matDatetimepicker]="endTimePicker1">  
101 - </mat-form-field>  
102 - </div> 90 + <div fxLayout="column" formArrayName="items" fxLayoutGap="1em">
  91 + <div fxLayout.xs="column" fxLayout="row" fxLayoutGap="8px" formGroupName="0" fxLayoutAlign="start center" fxLayoutAlign.xs="center start">
  92 + <mat-checkbox formControlName="enabled" fxFlex="17" (change)="changeCustomScheduler($event, 0)">
  93 + {{ 'device-profile.schedule-day.monday' | translate }}
  94 + </mat-checkbox>
  95 + <div fxLayout="row" fxLayoutGap="8px" fxFlex>
  96 + <mat-form-field fxFlex.xs fxFlex.sm="100px" fxFlex.md="100px">
  97 + <mat-label translate>device-profile.schedule-time-from</mat-label>
  98 + <mat-datetimepicker-toggle [for]="startTimePicker1" matPrefix></mat-datetimepicker-toggle>
  99 + <mat-datetimepicker #startTimePicker1 type="time" openOnFocus="true"></mat-datetimepicker>
  100 + <input required matInput formControlName="startsOn" [matDatetimepicker]="startTimePicker1">
  101 + </mat-form-field>
  102 + <mat-form-field fxFlex.xs fxFlex.sm="100px" fxFlex.md="100px">
  103 + <mat-label translate>device-profile.schedule-time-to</mat-label>
  104 + <mat-datetimepicker-toggle [for]="endTimePicker1" matPrefix></mat-datetimepicker-toggle>
  105 + <mat-datetimepicker #endTimePicker1 type="time" openOnFocus="true"></mat-datetimepicker>
  106 + <input required matInput formControlName="endsOn" [matDatetimepicker]="endTimePicker1">
  107 + </mat-form-field>
103 </div> 108 </div>
104 - <div fxLayout="row" fxLayoutGap="8px" formGroupName="1" fxLayoutAlign="start center">  
105 - <mat-checkbox formControlName="enabled" fxFlex="40" (change)="changeCustomScheduler($event, 1)">  
106 - {{ 'device-profile.schedule-day.tuesday' | translate }}  
107 - </mat-checkbox>  
108 - <div fxLayout="row" fxLayoutGap="8px" fxFlex>  
109 - <mat-form-field fxFlex="100px">  
110 - <mat-label translate>device-profile.schedule-time-from</mat-label>  
111 - <mat-datetimepicker-toggle [for]="startTimePicker2" matPrefix></mat-datetimepicker-toggle>  
112 - <mat-datetimepicker #startTimePicker2 type="time" openOnFocus="true"></mat-datetimepicker>  
113 - <input required matInput formControlName="startsOn" [matDatetimepicker]="startTimePicker2">  
114 - </mat-form-field>  
115 - <mat-form-field fxFlex="100px">  
116 - <mat-label translate>device-profile.schedule-time-to</mat-label>  
117 - <mat-datetimepicker-toggle [for]="endTimePicker2" matPrefix></mat-datetimepicker-toggle>  
118 - <mat-datetimepicker #endTimePicker2 type="time" openOnFocus="true"></mat-datetimepicker>  
119 - <input required matInput formControlName="endsOn" [matDatetimepicker]="endTimePicker2">  
120 - </mat-form-field>  
121 - </div> 109 + <div fxFlex fxLayoutAlign="center center"
  110 + style="text-align: center"
  111 + [innerHTML]="getSchedulerRangeText(itemsSchedulerForm.at(0))">
122 </div> 112 </div>
123 - <div fxLayout="row" fxLayoutGap="8px" formGroupName="2" fxLayoutAlign="start center">  
124 - <mat-checkbox formControlName="enabled" fxFlex="40" (change)="changeCustomScheduler($event, 2)">  
125 - {{ 'device-profile.schedule-day.wednesday' | translate }}  
126 - </mat-checkbox>  
127 - <div fxLayout="row" fxLayoutGap="8px" fxFlex>  
128 - <mat-form-field fxFlex="100px">  
129 - <mat-label translate>device-profile.schedule-time-from</mat-label>  
130 - <mat-datetimepicker-toggle [for]="startTimePicker3" matPrefix></mat-datetimepicker-toggle>  
131 - <mat-datetimepicker #startTimePicker3 type="time" openOnFocus="true"></mat-datetimepicker>  
132 - <input required matInput formControlName="startsOn" [matDatetimepicker]="startTimePicker3">  
133 - </mat-form-field>  
134 - <mat-form-field fxFlex="100px">  
135 - <mat-label translate>device-profile.schedule-time-to</mat-label>  
136 - <mat-datetimepicker-toggle [for]="endTimePicker3" matPrefix></mat-datetimepicker-toggle>  
137 - <mat-datetimepicker #endTimePicker3 type="time" openOnFocus="true"></mat-datetimepicker>  
138 - <input required matInput formControlName="endsOn" [matDatetimepicker]="endTimePicker3">  
139 - </mat-form-field>  
140 - </div> 113 + </div>
  114 + <div fxLayout.xs="column" fxLayout="row" fxLayoutGap="8px" formGroupName="1" fxLayoutAlign="start center" fxLayoutAlign.xs="center start">
  115 + <mat-checkbox formControlName="enabled" fxFlex="17" (change)="changeCustomScheduler($event, 1)">
  116 + {{ 'device-profile.schedule-day.tuesday' | translate }}
  117 + </mat-checkbox>
  118 + <div fxLayout="row" fxLayoutGap="8px" fxFlex>
  119 + <mat-form-field fxFlex.xs fxFlex.sm="100px" fxFlex.md="100px">
  120 + <mat-label translate>device-profile.schedule-time-from</mat-label>
  121 + <mat-datetimepicker-toggle [for]="startTimePicker2" matPrefix></mat-datetimepicker-toggle>
  122 + <mat-datetimepicker #startTimePicker2 type="time" openOnFocus="true"></mat-datetimepicker>
  123 + <input required matInput formControlName="startsOn" [matDatetimepicker]="startTimePicker2">
  124 + </mat-form-field>
  125 + <mat-form-field fxFlex.xs fxFlex.sm="100px" fxFlex.md="100px">
  126 + <mat-label translate>device-profile.schedule-time-to</mat-label>
  127 + <mat-datetimepicker-toggle [for]="endTimePicker2" matPrefix></mat-datetimepicker-toggle>
  128 + <mat-datetimepicker #endTimePicker2 type="time" openOnFocus="true"></mat-datetimepicker>
  129 + <input required matInput formControlName="endsOn" [matDatetimepicker]="endTimePicker2">
  130 + </mat-form-field>
141 </div> 131 </div>
142 - <div fxLayout="row" fxLayoutGap="8px" formGroupName="3" fxLayoutAlign="start center">  
143 - <mat-checkbox formControlName="enabled" fxFlex="40" (change)="changeCustomScheduler($event, 3)">  
144 - {{ 'device-profile.schedule-day.thursday' | translate }}  
145 - </mat-checkbox>  
146 - <div fxLayout="row" fxLayoutGap="8px" fxFlex>  
147 - <mat-form-field fxFlex="100px">  
148 - <mat-label translate>device-profile.schedule-time-from</mat-label>  
149 - <mat-datetimepicker-toggle [for]="startTimePicker4" matPrefix></mat-datetimepicker-toggle>  
150 - <mat-datetimepicker #startTimePicker4 type="time" openOnFocus="true"></mat-datetimepicker>  
151 - <input required matInput formControlName="startsOn" [matDatetimepicker]="startTimePicker4">  
152 - </mat-form-field>  
153 - <mat-form-field fxFlex="100px">  
154 - <mat-label translate>device-profile.schedule-time-to</mat-label>  
155 - <mat-datetimepicker-toggle [for]="endTimePicker4" matPrefix></mat-datetimepicker-toggle>  
156 - <mat-datetimepicker #endTimePicker4 type="time" openOnFocus="true"></mat-datetimepicker>  
157 - <input required matInput formControlName="endsOn" [matDatetimepicker]="endTimePicker4">  
158 - </mat-form-field>  
159 - </div> 132 + <div fxFlex fxLayoutAlign="center center"
  133 + style="text-align: center"
  134 + [innerHTML]="getSchedulerRangeText(itemsSchedulerForm.at(1))">
160 </div> 135 </div>
161 </div> 136 </div>
162 - <div fxLayout="column" fxFlex fxFlex.gt-sm="50">  
163 - <div fxLayout="row" fxLayoutGap="8px" formGroupName="4" fxLayoutAlign="start center">  
164 - <mat-checkbox formControlName="enabled" fxFlex="40" (change)="changeCustomScheduler($event, 4)">  
165 - {{ 'device-profile.schedule-day.friday' | translate }}  
166 - </mat-checkbox>  
167 - <div fxLayout="row" fxLayoutGap="8px" fxFlex>  
168 - <mat-form-field fxFlex="100px">  
169 - <mat-label translate>device-profile.schedule-time-from</mat-label>  
170 - <mat-datetimepicker-toggle [for]="startTimePicker5" matPrefix></mat-datetimepicker-toggle>  
171 - <mat-datetimepicker #startTimePicker5 type="time" openOnFocus="true"></mat-datetimepicker>  
172 - <input required matInput formControlName="startsOn" [matDatetimepicker]="startTimePicker5">  
173 - </mat-form-field>  
174 - <mat-form-field fxFlex="100px">  
175 - <mat-label translate>device-profile.schedule-time-to</mat-label>  
176 - <mat-datetimepicker-toggle [for]="endTimePicker5" matPrefix></mat-datetimepicker-toggle>  
177 - <mat-datetimepicker #endTimePicker5 type="time" openOnFocus="true"></mat-datetimepicker>  
178 - <input required matInput formControlName="endsOn" [matDatetimepicker]="endTimePicker5">  
179 - </mat-form-field>  
180 - </div> 137 + <div fxLayout.xs="column" fxLayout="row" fxLayoutGap="8px" formGroupName="2" fxLayoutAlign="start center" fxLayoutAlign.xs="center start">
  138 + <mat-checkbox formControlName="enabled" fxFlex="17" (change)="changeCustomScheduler($event, 2)">
  139 + {{ 'device-profile.schedule-day.wednesday' | translate }}
  140 + </mat-checkbox>
  141 + <div fxLayout="row" fxLayoutGap="8px" fxFlex>
  142 + <mat-form-field fxFlex.xs fxFlex.sm="100px" fxFlex.md="100px">
  143 + <mat-label translate>device-profile.schedule-time-from</mat-label>
  144 + <mat-datetimepicker-toggle [for]="startTimePicker3" matPrefix></mat-datetimepicker-toggle>
  145 + <mat-datetimepicker #startTimePicker3 type="time" openOnFocus="true"></mat-datetimepicker>
  146 + <input required matInput formControlName="startsOn" [matDatetimepicker]="startTimePicker3">
  147 + </mat-form-field>
  148 + <mat-form-field fxFlex.xs fxFlex.sm="100px" fxFlex.md="100px">
  149 + <mat-label translate>device-profile.schedule-time-to</mat-label>
  150 + <mat-datetimepicker-toggle [for]="endTimePicker3" matPrefix></mat-datetimepicker-toggle>
  151 + <mat-datetimepicker #endTimePicker3 type="time" openOnFocus="true"></mat-datetimepicker>
  152 + <input required matInput formControlName="endsOn" [matDatetimepicker]="endTimePicker3">
  153 + </mat-form-field>
  154 + </div>
  155 + <div fxFlex fxLayoutAlign="center center"
  156 + style="text-align: center"
  157 + [innerHTML]="getSchedulerRangeText(itemsSchedulerForm.at(2))">
  158 + </div>
  159 + </div>
  160 + <div fxLayout.xs="column" fxLayout="row" fxLayoutGap="8px" formGroupName="3" fxLayoutAlign="start center" fxLayoutAlign.xs="center start">
  161 + <mat-checkbox formControlName="enabled" fxFlex="17" (change)="changeCustomScheduler($event, 3)">
  162 + {{ 'device-profile.schedule-day.thursday' | translate }}
  163 + </mat-checkbox>
  164 + <div fxLayout="row" fxLayoutGap="8px" fxFlex>
  165 + <mat-form-field fxFlex.xs fxFlex.sm="100px" fxFlex.md="100px">
  166 + <mat-label translate>device-profile.schedule-time-from</mat-label>
  167 + <mat-datetimepicker-toggle [for]="startTimePicker4" matPrefix></mat-datetimepicker-toggle>
  168 + <mat-datetimepicker #startTimePicker4 type="time" openOnFocus="true"></mat-datetimepicker>
  169 + <input required matInput formControlName="startsOn" [matDatetimepicker]="startTimePicker4">
  170 + </mat-form-field>
  171 + <mat-form-field fxFlex.xs fxFlex.sm="100px" fxFlex.md="100px">
  172 + <mat-label translate>device-profile.schedule-time-to</mat-label>
  173 + <mat-datetimepicker-toggle [for]="endTimePicker4" matPrefix></mat-datetimepicker-toggle>
  174 + <mat-datetimepicker #endTimePicker4 type="time" openOnFocus="true"></mat-datetimepicker>
  175 + <input required matInput formControlName="endsOn" [matDatetimepicker]="endTimePicker4">
  176 + </mat-form-field>
181 </div> 177 </div>
182 - <div fxLayout="row" fxLayoutGap="8px" formGroupName="5" fxLayoutAlign="start center">  
183 - <mat-checkbox formControlName="enabled" fxFlex="40" (change)="changeCustomScheduler($event, 5)">  
184 - {{ 'device-profile.schedule-day.saturday' | translate }}  
185 - </mat-checkbox>  
186 - <div fxLayout="row" fxLayoutGap="8px" fxFlex>  
187 - <mat-form-field fxFlex="100px">  
188 - <mat-label translate>device-profile.schedule-time-from</mat-label>  
189 - <mat-datetimepicker-toggle [for]="startTimePicker6" matPrefix></mat-datetimepicker-toggle>  
190 - <mat-datetimepicker #startTimePicker6 type="time" openOnFocus="true"></mat-datetimepicker>  
191 - <input required matInput formControlName="startsOn" [matDatetimepicker]="startTimePicker6">  
192 - </mat-form-field>  
193 - <mat-form-field fxFlex="100px">  
194 - <mat-label translate>device-profile.schedule-time-to</mat-label>  
195 - <mat-datetimepicker-toggle [for]="endTimePicker6" matPrefix></mat-datetimepicker-toggle>  
196 - <mat-datetimepicker #endTimePicker6 type="time" openOnFocus="true"></mat-datetimepicker>  
197 - <input required matInput formControlName="endsOn" [matDatetimepicker]="endTimePicker6">  
198 - </mat-form-field>  
199 - </div> 178 + <div fxFlex fxLayoutAlign="center center"
  179 + style="text-align: center"
  180 + [innerHTML]="getSchedulerRangeText(itemsSchedulerForm.at(3))">
  181 + </div>
  182 + </div>
  183 + <div fxLayout.xs="column" fxLayout="row" fxLayoutGap="8px" formGroupName="4" fxLayoutAlign="start center" fxLayoutAlign.xs="center start">
  184 + <mat-checkbox formControlName="enabled" fxFlex="17" (change)="changeCustomScheduler($event, 4)">
  185 + {{ 'device-profile.schedule-day.friday' | translate }}
  186 + </mat-checkbox>
  187 + <div fxLayout="row" fxLayoutGap="8px" fxFlex>
  188 + <mat-form-field fxFlex.xs fxFlex.sm="100px" fxFlex.md="100px">
  189 + <mat-label translate>device-profile.schedule-time-from</mat-label>
  190 + <mat-datetimepicker-toggle [for]="startTimePicker5" matPrefix></mat-datetimepicker-toggle>
  191 + <mat-datetimepicker #startTimePicker5 type="time" openOnFocus="true"></mat-datetimepicker>
  192 + <input required matInput formControlName="startsOn" [matDatetimepicker]="startTimePicker5">
  193 + </mat-form-field>
  194 + <mat-form-field fxFlex.xs fxFlex.sm="100px" fxFlex.md="100px">
  195 + <mat-label translate>device-profile.schedule-time-to</mat-label>
  196 + <mat-datetimepicker-toggle [for]="endTimePicker5" matPrefix></mat-datetimepicker-toggle>
  197 + <mat-datetimepicker #endTimePicker5 type="time" openOnFocus="true"></mat-datetimepicker>
  198 + <input required matInput formControlName="endsOn" [matDatetimepicker]="endTimePicker5">
  199 + </mat-form-field>
  200 + </div>
  201 + <div fxFlex fxLayoutAlign="center center"
  202 + style="text-align: center"
  203 + [innerHTML]="getSchedulerRangeText(itemsSchedulerForm.at(4))">
  204 + </div>
  205 + </div>
  206 + <div fxLayout.xs="column" fxLayout="row" fxLayoutGap="8px" formGroupName="5" fxLayoutAlign="start center" fxLayoutAlign.xs="center start">
  207 + <mat-checkbox formControlName="enabled" fxFlex="17" (change)="changeCustomScheduler($event, 5)">
  208 + {{ 'device-profile.schedule-day.saturday' | translate }}
  209 + </mat-checkbox>
  210 + <div fxLayout="row" fxLayoutGap="8px" fxFlex>
  211 + <mat-form-field fxFlex.xs fxFlex.sm="100px" fxFlex.md="100px">
  212 + <mat-label translate>device-profile.schedule-time-from</mat-label>
  213 + <mat-datetimepicker-toggle [for]="startTimePicker6" matPrefix></mat-datetimepicker-toggle>
  214 + <mat-datetimepicker #startTimePicker6 type="time" openOnFocus="true"></mat-datetimepicker>
  215 + <input required matInput formControlName="startsOn" [matDatetimepicker]="startTimePicker6">
  216 + </mat-form-field>
  217 + <mat-form-field fxFlex.xs fxFlex.sm="100px" fxFlex.md="100px">
  218 + <mat-label translate>device-profile.schedule-time-to</mat-label>
  219 + <mat-datetimepicker-toggle [for]="endTimePicker6" matPrefix></mat-datetimepicker-toggle>
  220 + <mat-datetimepicker #endTimePicker6 type="time" openOnFocus="true"></mat-datetimepicker>
  221 + <input required matInput formControlName="endsOn" [matDatetimepicker]="endTimePicker6">
  222 + </mat-form-field>
  223 + </div>
  224 + <div fxFlex fxLayoutAlign="center center"
  225 + style="text-align: center"
  226 + [innerHTML]="getSchedulerRangeText(itemsSchedulerForm.at(5))">
  227 + </div>
  228 + </div>
  229 + <div fxLayout.xs="column" fxLayout="row" fxLayoutGap="8px" formGroupName="6" fxLayoutAlign="start center" fxLayoutAlign.xs="center start">
  230 + <mat-checkbox formControlName="enabled" fxFlex="17" (change)="changeCustomScheduler($event, 6)">
  231 + {{ 'device-profile.schedule-day.sunday' | translate }}
  232 + </mat-checkbox>
  233 + <div fxLayout="row" fxLayoutGap="8px" fxFlex>
  234 + <mat-form-field fxFlex.xs fxFlex.sm="100px" fxFlex.md="100px">
  235 + <mat-label translate>device-profile.schedule-time-from</mat-label>
  236 + <mat-datetimepicker-toggle [for]="startTimePicker7" matPrefix></mat-datetimepicker-toggle>
  237 + <mat-datetimepicker #startTimePicker7 type="time" openOnFocus="true"></mat-datetimepicker>
  238 + <input required matInput formControlName="startsOn" [matDatetimepicker]="startTimePicker7">
  239 + </mat-form-field>
  240 + <mat-form-field fxFlex.xs fxFlex.sm="100px" fxFlex.md="100px">
  241 + <mat-label translate>device-profile.schedule-time-to</mat-label>
  242 + <mat-datetimepicker-toggle [for]="endTimePicker7" matPrefix></mat-datetimepicker-toggle>
  243 + <mat-datetimepicker #endTimePicker7 type="time" openOnFocus="true"></mat-datetimepicker>
  244 + <input required matInput formControlName="endsOn" [matDatetimepicker]="endTimePicker7">
  245 + </mat-form-field>
200 </div> 246 </div>
201 - <div fxLayout="row" fxLayoutGap="8px" formGroupName="6" fxLayoutAlign="start center">  
202 - <mat-checkbox formControlName="enabled" fxFlex="40" (change)="changeCustomScheduler($event, 6)">  
203 - {{ 'device-profile.schedule-day.sunday' | translate }}  
204 - </mat-checkbox>  
205 - <div fxLayout="row" fxLayoutGap="8px" fxFlex>  
206 - <mat-form-field fxFlex="100px">  
207 - <mat-label translate>device-profile.schedule-time-from</mat-label>  
208 - <mat-datetimepicker-toggle [for]="startTimePicker7" matPrefix></mat-datetimepicker-toggle>  
209 - <mat-datetimepicker #startTimePicker7 type="time" openOnFocus="true"></mat-datetimepicker>  
210 - <input required matInput formControlName="startsOn" [matDatetimepicker]="startTimePicker7">  
211 - </mat-form-field>  
212 - <mat-form-field fxFlex="100px">  
213 - <mat-label translate>device-profile.schedule-time-to</mat-label>  
214 - <mat-datetimepicker-toggle [for]="endTimePicker7" matPrefix></mat-datetimepicker-toggle>  
215 - <mat-datetimepicker #endTimePicker7 type="time" openOnFocus="true"></mat-datetimepicker>  
216 - <input required matInput formControlName="endsOn" [matDatetimepicker]="endTimePicker7">  
217 - </mat-form-field>  
218 - </div> 247 + <div fxFlex fxLayoutAlign="center center"
  248 + style="text-align: center"
  249 + [innerHTML]="getSchedulerRangeText(itemsSchedulerForm.at(6))">
219 </div> 250 </div>
220 </div> 251 </div>
221 </div> 252 </div>
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +::ng-deep {
  17 + .nowrap {
  18 + white-space: nowrap;
  19 + }
  20 +}
@@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
16 16
17 import { Component, forwardRef, Input, OnInit } from '@angular/core'; 17 import { Component, forwardRef, Input, OnInit } from '@angular/core';
18 import { 18 import {
  19 + AbstractControl,
19 ControlValueAccessor, 20 ControlValueAccessor,
20 FormArray, 21 FormArray,
21 FormBuilder, 22 FormBuilder,
@@ -35,6 +36,7 @@ import { MatCheckboxChange } from '@angular/material/checkbox'; @@ -35,6 +36,7 @@ import { MatCheckboxChange } from '@angular/material/checkbox';
35 @Component({ 36 @Component({
36 selector: 'tb-alarm-schedule', 37 selector: 'tb-alarm-schedule',
37 templateUrl: './alarm-schedule.component.html', 38 templateUrl: './alarm-schedule.component.html',
  39 + styleUrls: ['./alarm-schedule.component.scss'],
38 providers: [{ 40 providers: [{
39 provide: NG_VALUE_ACCESSOR, 41 provide: NG_VALUE_ACCESSOR,
40 useExisting: forwardRef(() => AlarmScheduleComponent), 42 useExisting: forwardRef(() => AlarmScheduleComponent),
@@ -79,7 +81,7 @@ export class AlarmScheduleComponent implements ControlValueAccessor, Validator, @@ -79,7 +81,7 @@ export class AlarmScheduleComponent implements ControlValueAccessor, Validator,
79 items: this.fb.array(Array.from({length: 7}, (value, i) => this.defaultItemsScheduler(i))) 81 items: this.fb.array(Array.from({length: 7}, (value, i) => this.defaultItemsScheduler(i)))
80 }); 82 });
81 this.alarmScheduleForm.get('type').valueChanges.subscribe((type) => { 83 this.alarmScheduleForm.get('type').valueChanges.subscribe((type) => {
82 - this.alarmScheduleForm.reset({type, items: this.defaultItems}, {emitEvent: false}); 84 + this.alarmScheduleForm.reset({type, items: this.defaultItems, timezone: this.defaultTimezone}, {emitEvent: false});
83 this.updateValidators(type, true); 85 this.updateValidators(type, true);
84 this.alarmScheduleForm.updateValueAndValidity(); 86 this.alarmScheduleForm.updateValueAndValidity();
85 }); 87 });
@@ -131,13 +133,7 @@ export class AlarmScheduleComponent implements ControlValueAccessor, Validator, @@ -131,13 +133,7 @@ export class AlarmScheduleComponent implements ControlValueAccessor, Validator,
131 this.modelValue.items 133 this.modelValue.items
132 .sort((a, b) => a.dayOfWeek - b.dayOfWeek) 134 .sort((a, b) => a.dayOfWeek - b.dayOfWeek)
133 .forEach((item, index) => { 135 .forEach((item, index) => {
134 - if (item.enabled) {  
135 - this.itemsSchedulerForm.at(index).get('startsOn').enable({emitEvent: false});  
136 - this.itemsSchedulerForm.at(index).get('endsOn').enable({emitEvent: false});  
137 - } else {  
138 - this.itemsSchedulerForm.at(index).get('startsOn').disable({emitEvent: false});  
139 - this.itemsSchedulerForm.at(index).get('endsOn').disable({emitEvent: false});  
140 - } 136 + this.disabledSelectedTime(item.enabled, index);
141 alarmDays.push({ 137 alarmDays.push({
142 enabled: item.enabled, 138 enabled: item.enabled,
143 startsOn: this.timestampToTime(item.startsOn), 139 startsOn: this.timestampToTime(item.startsOn),
@@ -206,15 +202,15 @@ export class AlarmScheduleComponent implements ControlValueAccessor, Validator, @@ -206,15 +202,15 @@ export class AlarmScheduleComponent implements ControlValueAccessor, Validator,
206 .filter(day => !!day); 202 .filter(day => !!day);
207 } 203 }
208 if (isDefined(value.startsOn) && value.startsOn !== 0) { 204 if (isDefined(value.startsOn) && value.startsOn !== 0) {
209 - value.startsOn = this.timeToTimestamp(value.startsOn); 205 + value.startsOn = this.timeToTimestampUTC(value.startsOn);
210 } 206 }
211 if (isDefined(value.endsOn) && value.endsOn !== 0) { 207 if (isDefined(value.endsOn) && value.endsOn !== 0) {
212 - value.endsOn = this.timeToTimestamp(value.endsOn); 208 + value.endsOn = this.timeToTimestampUTC(value.endsOn);
213 } 209 }
214 if (isDefined(value.items)){ 210 if (isDefined(value.items)){
215 value.items = this.alarmScheduleForm.getRawValue().items; 211 value.items = this.alarmScheduleForm.getRawValue().items;
216 value.items = value.items.map((item) => { 212 value.items = value.items.map((item) => {
217 - return { ...item, startsOn: this.timeToTimestamp(item.startsOn), endsOn: this.timeToTimestamp(item.endsOn)}; 213 + return { ...item, startsOn: this.timeToTimestampUTC(item.startsOn), endsOn: this.timeToTimestampUTC(item.endsOn)};
218 }); 214 });
219 } 215 }
220 this.modelValue = value; 216 this.modelValue = value;
@@ -222,7 +218,7 @@ export class AlarmScheduleComponent implements ControlValueAccessor, Validator, @@ -222,7 +218,7 @@ export class AlarmScheduleComponent implements ControlValueAccessor, Validator,
222 } 218 }
223 } 219 }
224 220
225 - private timeToTimestamp(date: Date | number): number { 221 + private timeToTimestampUTC(date: Date | number): number {
226 if (typeof date === 'number' || date === null) { 222 if (typeof date === 'number' || date === null) {
227 return 0; 223 return 0;
228 } 224 }
@@ -244,16 +240,39 @@ export class AlarmScheduleComponent implements ControlValueAccessor, Validator, @@ -244,16 +240,39 @@ export class AlarmScheduleComponent implements ControlValueAccessor, Validator,
244 240
245 changeCustomScheduler($event: MatCheckboxChange, index: number) { 241 changeCustomScheduler($event: MatCheckboxChange, index: number) {
246 const value = $event.checked; 242 const value = $event.checked;
247 - if (value) { 243 + this.disabledSelectedTime(value, index, true);
  244 + }
  245 +
  246 + private disabledSelectedTime(enable: boolean, index: number, emitEvent = false) {
  247 + if (enable) {
248 this.itemsSchedulerForm.at(index).get('startsOn').enable({emitEvent: false}); 248 this.itemsSchedulerForm.at(index).get('startsOn').enable({emitEvent: false});
249 - this.itemsSchedulerForm.at(index).get('endsOn').enable(); 249 + this.itemsSchedulerForm.at(index).get('endsOn').enable({emitEvent});
250 } else { 250 } else {
251 this.itemsSchedulerForm.at(index).get('startsOn').disable({emitEvent: false}); 251 this.itemsSchedulerForm.at(index).get('startsOn').disable({emitEvent: false});
252 - this.itemsSchedulerForm.at(index).get('endsOn').disable(); 252 + this.itemsSchedulerForm.at(index).get('endsOn').disable({emitEvent});
  253 + }
  254 + }
  255 +
  256 + private timeToMoment(date: Date | number): _moment.Moment {
  257 + if (typeof date === 'number' || date === null) {
  258 + return _moment([1970, 0, 1, 0, 0, 0, 0]);
  259 + }
  260 + return _moment([1970, 0, 1, date.getHours(), date.getMinutes(), 0, 0]);
  261 + }
  262 +
  263 + getSchedulerRangeText(control: FormGroup | AbstractControl): string {
  264 + const start = this.timeToMoment(control.get('startsOn').value);
  265 + const end = this.timeToMoment(control.get('endsOn').value);
  266 + if (start < end) {
  267 + return `<span><span class="nowrap">${start.format('hh:mm A')}</span> – <span class="nowrap">${end.format('hh:mm A')}</span></span>`;
  268 + } else if (start.valueOf() === 0 && end.valueOf() === 0 || start.isSame(_moment([1970, 0])) && end.isSame(_moment([1970, 0]))) {
  269 + return '<span><span class="nowrap">12:00 AM</span> – <span class="nowrap">12:00 PM</span></span>';
253 } 270 }
  271 + return `<span><span class="nowrap">12:00 AM</span> – <span class="nowrap">${end.format('hh:mm A')}</span>` +
  272 + ` and <span class="nowrap">${start.format('hh:mm A')}</span> – <span class="nowrap">12:00 PM</span></span>`;
254 } 273 }
255 274
256 - private get itemsSchedulerForm(): FormArray { 275 + get itemsSchedulerForm(): FormArray {
257 return this.alarmScheduleForm.get('items') as FormArray; 276 return this.alarmScheduleForm.get('items') as FormArray;
258 } 277 }
259 } 278 }
@@ -39,7 +39,7 @@ @@ -39,7 +39,7 @@
39 </mat-tab> 39 </mat-tab>
40 <mat-tab *ngIf="entity" 40 <mat-tab *ngIf="entity"
41 label="{{'device-profile.alarm-rules' | translate: 41 label="{{'device-profile.alarm-rules' | translate:
42 - {count: entity.profileData.alarms.length ? 42 + {count: entity.profileData.alarms && entity.profileData.alarms.length ?
43 entity.profileData.alarms.length : 0} }}" #alarmRules="matTab"> 43 entity.profileData.alarms.length : 0} }}" #alarmRules="matTab">
44 <div class="mat-padding" [formGroup]="detailsForm"> 44 <div class="mat-padding" [formGroup]="detailsForm">
45 <div formGroupName="profileData"> 45 <div formGroupName="profileData">