Showing
18 changed files
with
279 additions
and
240 deletions
@@ -184,6 +184,10 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo | @@ -184,6 +184,10 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo | ||
184 | swap: false, | 184 | swap: false, |
185 | maxRows: 100, | 185 | maxRows: 100, |
186 | minCols: this.columns ? this.columns : 24, | 186 | minCols: this.columns ? this.columns : 24, |
187 | + maxCols: 3000, | ||
188 | + maxItemCols: 1000, | ||
189 | + maxItemRows: 1000, | ||
190 | + maxItemArea: 1000000, | ||
187 | outerMargin: true, | 191 | outerMargin: true, |
188 | margin: this.margin ? this.margin : 10, | 192 | margin: this.margin ? this.margin : 10, |
189 | minItemCols: 1, | 193 | minItemCols: 1, |
@@ -299,14 +299,16 @@ export class ManageWidgetActionsComponent extends PageComponent implements OnIni | @@ -299,14 +299,16 @@ export class ManageWidgetActionsComponent extends PageComponent implements OnIni | ||
299 | 299 | ||
300 | writeValue(obj: WidgetActionsData): void { | 300 | writeValue(obj: WidgetActionsData): void { |
301 | this.innerValue = obj; | 301 | this.innerValue = obj; |
302 | - setTimeout(() => { | ||
303 | - this.dataSource.setActions(this.innerValue); | ||
304 | - if (this.viewsInited) { | ||
305 | - this.resetSortAndFilter(true); | ||
306 | - } else { | ||
307 | - this.dirtyValue = true; | ||
308 | - } | ||
309 | - }, 0); | 302 | + if (this.innerValue) { |
303 | + setTimeout(() => { | ||
304 | + this.dataSource.setActions(this.innerValue); | ||
305 | + if (this.viewsInited) { | ||
306 | + this.resetSortAndFilter(true); | ||
307 | + } else { | ||
308 | + this.dirtyValue = true; | ||
309 | + } | ||
310 | + }, 0); | ||
311 | + } | ||
310 | } | 312 | } |
311 | 313 | ||
312 | private onActionsUpdated() { | 314 | private onActionsUpdated() { |
@@ -29,7 +29,7 @@ | @@ -29,7 +29,7 @@ | ||
29 | <div class="tb-color-preview" (click)="showColorPicker(key)" style="margin-right: 5px;"> | 29 | <div class="tb-color-preview" (click)="showColorPicker(key)" style="margin-right: 5px;"> |
30 | <div class="tb-color-result" [ngStyle]="{background: key.color}"></div> | 30 | <div class="tb-color-result" [ngStyle]="{background: key.color}"></div> |
31 | </div> | 31 | </div> |
32 | - <div style="flex: 1; min-width: 0px;" fxLayout="row"> | 32 | + <div class="tb-chip-labels"> |
33 | <div class="tb-chip-label"> | 33 | <div class="tb-chip-label"> |
34 | <span *ngIf="datasourceType !== datasourceTypes.function && widgetType !== widgetTypes.alarm"> | 34 | <span *ngIf="datasourceType !== datasourceTypes.function && widgetType !== widgetTypes.alarm"> |
35 | <span *ngIf="key.type === dataKeyTypes.attribute" | 35 | <span *ngIf="key.type === dataKeyTypes.attribute" |
@@ -30,14 +30,19 @@ | @@ -30,14 +30,19 @@ | ||
30 | } | 30 | } |
31 | } | 31 | } |
32 | 32 | ||
33 | - .tb-chip-label { | ||
34 | - overflow: hidden; | ||
35 | - text-overflow: ellipsis; | ||
36 | - white-space: nowrap; | ||
37 | - } | 33 | + .tb-chip-labels { |
34 | + display: flex; | ||
35 | + flex-direction: row; | ||
36 | + min-width: 0px; | ||
37 | + .tb-chip-label { | ||
38 | + overflow: hidden; | ||
39 | + text-overflow: ellipsis; | ||
40 | + white-space: nowrap; | ||
41 | + } | ||
38 | 42 | ||
39 | - .tb-chip-separator { | ||
40 | - white-space: pre; | 43 | + .tb-chip-separator { |
44 | + white-space: pre; | ||
45 | + } | ||
41 | } | 46 | } |
42 | 47 | ||
43 | .mat-chip-remove.mat-icon { | 48 | .mat-chip-remove.mat-icon { |
@@ -38,16 +38,16 @@ | @@ -38,16 +38,16 @@ | ||
38 | </mat-option> | 38 | </mat-option> |
39 | </mat-select> | 39 | </mat-select> |
40 | </mat-form-field> | 40 | </mat-form-field> |
41 | - <mat-checkbox fxFlex formControlName="showMin"> | 41 | + <mat-checkbox formControlName="showMin"> |
42 | {{ 'legend.show-min' | translate }} | 42 | {{ 'legend.show-min' | translate }} |
43 | </mat-checkbox> | 43 | </mat-checkbox> |
44 | - <mat-checkbox fxFlex formControlName="showMax"> | 44 | + <mat-checkbox formControlName="showMax"> |
45 | {{ 'legend.show-max' | translate }} | 45 | {{ 'legend.show-max' | translate }} |
46 | </mat-checkbox> | 46 | </mat-checkbox> |
47 | - <mat-checkbox fxFlex formControlName="showAvg"> | 47 | + <mat-checkbox formControlName="showAvg"> |
48 | {{ 'legend.show-avg' | translate }} | 48 | {{ 'legend.show-avg' | translate }} |
49 | </mat-checkbox> | 49 | </mat-checkbox> |
50 | - <mat-checkbox fxFlex formControlName="showTotal"> | 50 | + <mat-checkbox formControlName="showTotal"> |
51 | {{ 'legend.show-total' | translate }} | 51 | {{ 'legend.show-total' | translate }} |
52 | </mat-checkbox> | 52 | </mat-checkbox> |
53 | </section> | 53 | </section> |
@@ -22,11 +22,10 @@ | @@ -22,11 +22,10 @@ | ||
22 | <div *ngIf="widgetType === widgetTypes.timeseries || widgetType === widgetTypes.alarm" | 22 | <div *ngIf="widgetType === widgetTypes.timeseries || widgetType === widgetTypes.alarm" |
23 | fxLayout="column" fxLayoutGap="8px" fxLayoutAlign="center" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center"> | 23 | fxLayout="column" fxLayoutGap="8px" fxLayoutAlign="center" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center"> |
24 | <div fxLayout="column" fxLayoutGap="8px" fxFlex> | 24 | <div fxLayout="column" fxLayoutGap="8px" fxFlex> |
25 | - <mat-checkbox fxFlex formControlName="useDashboardTimewindow"> | 25 | + <mat-checkbox formControlName="useDashboardTimewindow"> |
26 | {{ 'widget-config.use-dashboard-timewindow' | translate }} | 26 | {{ 'widget-config.use-dashboard-timewindow' | translate }} |
27 | </mat-checkbox> | 27 | </mat-checkbox> |
28 | - <mat-checkbox fxFlex | ||
29 | - formControlName="displayTimewindow"> | 28 | + <mat-checkbox formControlName="displayTimewindow"> |
30 | {{ 'widget-config.display-timewindow' | translate }} | 29 | {{ 'widget-config.display-timewindow' | translate }} |
31 | </mat-checkbox> | 30 | </mat-checkbox> |
32 | </div> | 31 | </div> |
@@ -163,6 +163,10 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont | @@ -163,6 +163,10 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont | ||
163 | } else { | 163 | } else { |
164 | this.datasourceTypes = [DatasourceType.function, DatasourceType.entity]; | 164 | this.datasourceTypes = [DatasourceType.function, DatasourceType.entity]; |
165 | } | 165 | } |
166 | + this.dataSettings = this.fb.group({}); | ||
167 | + this.targetDeviceSettings = this.fb.group({}); | ||
168 | + this.alarmSourceSettings = this.fb.group({}); | ||
169 | + this.advancedSettings = this.fb.group({}); | ||
166 | this.widgetSettings = this.fb.group({ | 170 | this.widgetSettings = this.fb.group({ |
167 | title: [null, []], | 171 | title: [null, []], |
168 | showTitleIcon: [null, []], | 172 | showTitleIcon: [null, []], |
@@ -574,7 +578,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont | @@ -574,7 +578,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont | ||
574 | } | 578 | } |
575 | 579 | ||
576 | public displayAdvanced(): boolean { | 580 | public displayAdvanced(): boolean { |
577 | - return this.modelValue.settingsSchema && this.modelValue.settingsSchema.schema; | 581 | + return this.modelValue && this.modelValue.settingsSchema && this.modelValue.settingsSchema.schema; |
578 | } | 582 | } |
579 | 583 | ||
580 | public removeDatasource(index: number) { | 584 | public removeDatasource(index: number) { |
@@ -772,7 +776,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont | @@ -772,7 +776,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont | ||
772 | valid: false | 776 | valid: false |
773 | } | 777 | } |
774 | }; | 778 | }; |
775 | - } else { | 779 | + } else if (this.modelValue) { |
776 | const config = this.modelValue.config; | 780 | const config = this.modelValue.config; |
777 | if (this.widgetType === widgetType.rpc && this.modelValue.isDataEnabled) { | 781 | if (this.widgetType === widgetType.rpc && this.modelValue.isDataEnabled) { |
778 | if (!config.targetDeviceAliasIds || !config.targetDeviceAliasIds.length) { | 782 | if (!config.targetDeviceAliasIds || !config.targetDeviceAliasIds.length) { |
@@ -120,59 +120,90 @@ | @@ -120,59 +120,90 @@ | ||
120 | 'tb-dashboard-toolbar-opened': toolbarOpened, | 120 | 'tb-dashboard-toolbar-opened': toolbarOpened, |
121 | 'tb-dashboard-toolbar-animated': isToolbarOpenedAnimate, | 121 | 'tb-dashboard-toolbar-animated': isToolbarOpenedAnimate, |
122 | 'tb-dashboard-toolbar-closed': !toolbarOpened }"> | 122 | 'tb-dashboard-toolbar-closed': !toolbarOpened }"> |
123 | - <section *ngIf="!widgetEditMode" class="tb-dashboard-title" fxLayout="row" fxLayoutAlign="center center" | ||
124 | - [ngStyle]="{'color': dashboard.configuration.settings.titleColor}"> | ||
125 | - <h3 [fxShow]="!isEdit && displayTitle()">{{ dashboard.title }}</h3> | ||
126 | - <mat-form-field [fxShow]="isEdit" class="mat-block" style="height: 30px;"> | ||
127 | - <mat-label translate [ngStyle]="{'color': dashboard.configuration.settings.titleColor}">dashboard.title</mat-label> | ||
128 | - <input matInput class="tb-dashboard-title" | ||
129 | - [ngStyle]="{'color': dashboard.configuration.settings.titleColor}" | ||
130 | - required name="title" [(ngModel)]="dashboard.title"> | ||
131 | - </mat-form-field> | ||
132 | - </section> | ||
133 | - <div class="tb-absolute-fill tb-dashboard-layouts" fxLayout="{{forceDashboardMobileMode ? 'column' : 'row'}}" | ||
134 | - [ngClass]="{ 'tb-padded' : !widgetEditMode && (isEdit || displayTitle()), 'tb-shrinked' : isEditingWidget }"> | ||
135 | - <mat-drawer-container class="tb-absolute-fill"> | ||
136 | - <mat-drawer *ngIf="layouts.right.show" | ||
137 | - id="tb-right-layout" | ||
138 | - [ngStyle]="{minWidth: rightLayoutWidth(), | ||
139 | - maxWidth: rightLayoutWidth(), | ||
140 | - height: rightLayoutHeight(), | ||
141 | - borderLeft: 'none'}" | ||
142 | - disableClose="true" | ||
143 | - position="end" | ||
144 | - [mode]="isMobile ? 'over' : 'side'" | ||
145 | - [(opened)]="rightLayoutOpened"> | ||
146 | - <tb-dashboard-layout style="height: 100%;" | ||
147 | - [layoutCtx]="layouts.right.layoutCtx" | ||
148 | - [dashboardCtx]="dashboardCtx" | ||
149 | - [isEdit]="isEdit" | ||
150 | - [isEditingWidget]="isEditingWidget" | ||
151 | - [isMobile]="forceDashboardMobileMode" | ||
152 | - [widgetEditMode]="widgetEditMode"> | ||
153 | - </tb-dashboard-layout> | ||
154 | - </mat-drawer> | ||
155 | - <mat-drawer-content [fxShow]="layouts.main.show" | ||
156 | - id="tb-main-layout" | ||
157 | - [ngStyle]="{width: mainLayoutWidth(), | ||
158 | - height: mainLayoutHeight()}"> | ||
159 | - <tb-dashboard-layout | ||
160 | - [layoutCtx]="layouts.main.layoutCtx" | ||
161 | - [dashboardCtx]="dashboardCtx" | ||
162 | - [isEdit]="isEdit" | ||
163 | - [isEditingWidget]="isEditingWidget" | ||
164 | - [isMobile]="forceDashboardMobileMode" | ||
165 | - [widgetEditMode]="widgetEditMode"> | ||
166 | - </tb-dashboard-layout> | ||
167 | - </mat-drawer-content> | ||
168 | - </mat-drawer-container> | ||
169 | - </div> | ||
170 | - <mat-drawer-container hasBackdrop="false" class="tb-widget-details-sidenav"> | 123 | + <mat-drawer-container hasBackdrop="false" class="tb-absolute-fill tb-dashboard-drawer-container"> |
124 | + <mat-drawer-content fxLayout="column" fxLayoutAlign="center start"> | ||
125 | + <section *ngIf="!widgetEditMode" class="tb-dashboard-title" | ||
126 | + [ngStyle]="{'color': dashboard.configuration.settings.titleColor}"> | ||
127 | + <h3 [fxShow]="!isEdit && displayTitle()">{{ dashboard.title }}</h3> | ||
128 | + <mat-form-field [fxShow]="isEdit" class="mat-block"> | ||
129 | + <mat-label translate [ngStyle]="{'color': dashboard.configuration.settings.titleColor}">dashboard.title</mat-label> | ||
130 | + <input matInput class="tb-dashboard-title" | ||
131 | + [ngStyle]="{'color': dashboard.configuration.settings.titleColor}" | ||
132 | + required name="title" [(ngModel)]="dashboard.title"> | ||
133 | + </mat-form-field> | ||
134 | + </section> | ||
135 | + <mat-drawer-container class="tb-dashboard-layouts" fxFlex | ||
136 | + [ngClass]="{ 'tb-shrinked' : isEditingWidget }"> | ||
137 | + <mat-drawer *ngIf="layouts.right.show" | ||
138 | + id="tb-right-layout" | ||
139 | + [ngStyle]="{minWidth: rightLayoutWidth(), | ||
140 | + maxWidth: rightLayoutWidth(), | ||
141 | + height: rightLayoutHeight(), | ||
142 | + borderLeft: 'none'}" | ||
143 | + disableClose="true" | ||
144 | + position="end" | ||
145 | + [mode]="isMobile ? 'over' : 'side'" | ||
146 | + [(opened)]="rightLayoutOpened"> | ||
147 | + <tb-dashboard-layout style="height: 100%;" | ||
148 | + [layoutCtx]="layouts.right.layoutCtx" | ||
149 | + [dashboardCtx]="dashboardCtx" | ||
150 | + [isEdit]="isEdit" | ||
151 | + [isEditingWidget]="isEditingWidget" | ||
152 | + [isMobile]="forceDashboardMobileMode" | ||
153 | + [widgetEditMode]="widgetEditMode"> | ||
154 | + </tb-dashboard-layout> | ||
155 | + </mat-drawer> | ||
156 | + <mat-drawer-content [fxShow]="layouts.main.show" | ||
157 | + id="tb-main-layout" | ||
158 | + [ngStyle]="{width: mainLayoutWidth(), | ||
159 | + height: mainLayoutHeight()}"> | ||
160 | + <tb-dashboard-layout | ||
161 | + [layoutCtx]="layouts.main.layoutCtx" | ||
162 | + [dashboardCtx]="dashboardCtx" | ||
163 | + [isEdit]="isEdit" | ||
164 | + [isEditingWidget]="isEditingWidget" | ||
165 | + [isMobile]="forceDashboardMobileMode" | ||
166 | + [widgetEditMode]="widgetEditMode"> | ||
167 | + </tb-dashboard-layout> | ||
168 | + </mat-drawer-content> | ||
169 | + </mat-drawer-container> | ||
170 | + <section fxLayout="row" class="layout-wrap tb-footer-buttons" fxLayoutAlign="start end"> | ||
171 | + <tb-footer-fab-buttons [fxShow]="!isAddingWidget && isEdit && !widgetEditMode" | ||
172 | + relative | ||
173 | + [footerFabButtons]="addWidgetFabButtons"> | ||
174 | + </tb-footer-fab-buttons> | ||
175 | + <button *ngIf="(isTenantAdmin() || isSystemAdmin()) && !forceFullscreen" | ||
176 | + mat-fab color="accent" class="tb-btn-footer" | ||
177 | + [ngClass]="{'tb-hide': !isEdit || isAddingWidget}" | ||
178 | + [disabled]="isLoading$ | async" | ||
179 | + (click)="saveDashboard()" | ||
180 | + matTooltip="{{ 'action.apply-changes' | translate }}" | ||
181 | + matTooltipPosition="above"> | ||
182 | + <mat-icon>done</mat-icon> | ||
183 | + </button> | ||
184 | + <button *ngIf="(isTenantAdmin() || isSystemAdmin()) && !forceFullscreen" | ||
185 | + mat-fab color="accent" class="tb-btn-footer" | ||
186 | + [ngClass]="{'tb-hide': isAddingWidget || (isLoading$ | async)}" | ||
187 | + [disabled]="isLoading$ | async" | ||
188 | + (click)="toggleDashboardEditMode()" | ||
189 | + matTooltip="{{ (isEdit ? 'action.decline-changes': 'action.enter-edit-mode') | translate }}" | ||
190 | + matTooltipPosition="above"> | ||
191 | + <mat-icon>{{ isEdit ? 'close' : 'edit' }}</mat-icon> | ||
192 | + </button> | ||
193 | + </section> | ||
194 | + <section class="tb-powered-by-footer" [ngStyle]="{'color': dashboard.configuration.settings.titleColor}"> | ||
195 | + <span>Powered by <a href="https://thingsboard.io" target="_blank">Thingsboard v.{{ thingsboardVersion }}</a></span> | ||
196 | + </section> | ||
197 | + </mat-drawer-content> | ||
171 | <mat-drawer class="tb-details-drawer" | 198 | <mat-drawer class="tb-details-drawer" |
172 | - [opened]="isEditingWidget" | 199 | + [opened]="isEditingWidget || isAddingWidget" |
200 | + (openedStart)="detailsDrawerOpenedStart()" | ||
201 | + (opened)="detailsDrawerOpened()" | ||
202 | + (closedStart)="detailsDrawerClosedStart()" | ||
203 | + (closed)="detailsDrawerClosed()" | ||
173 | mode="over" | 204 | mode="over" |
174 | position="end"> | 205 | position="end"> |
175 | - <tb-details-panel *ngIf="isEditingWidget" fxFlex | 206 | + <tb-details-panel *ngIf="!isEditingWidgetClosed" fxFlex |
176 | headerTitle="{{editingWidget?.config.title}}" | 207 | headerTitle="{{editingWidget?.config.title}}" |
177 | headerSubtitle="{{ editingWidgetSubtitle }}" | 208 | headerSubtitle="{{ editingWidgetSubtitle }}" |
178 | [isReadOnly]="false" | 209 | [isReadOnly]="false" |
@@ -185,21 +216,14 @@ | @@ -185,21 +216,14 @@ | ||
185 | <div [tb-help]="helpLinkIdForWidgetType()"></div> | 216 | <div [tb-help]="helpLinkIdForWidgetType()"></div> |
186 | </div> | 217 | </div> |
187 | <tb-edit-widget #tbEditWidget | 218 | <tb-edit-widget #tbEditWidget |
188 | - [dashboard]="dashboard" | ||
189 | - [aliasController]="dashboardCtx.aliasController" | ||
190 | - [widgetEditMode]="widgetEditMode" | ||
191 | - [widget]="editingWidget" | ||
192 | - [widgetLayout]="editingWidgetLayout"> | 219 | + [dashboard]="dashboard" |
220 | + [aliasController]="dashboardCtx.aliasController" | ||
221 | + [widgetEditMode]="widgetEditMode" | ||
222 | + [widget]="editingWidget" | ||
223 | + [widgetLayout]="editingWidgetLayout"> | ||
193 | </tb-edit-widget> | 224 | </tb-edit-widget> |
194 | </tb-details-panel> | 225 | </tb-details-panel> |
195 | - </mat-drawer> | ||
196 | - </mat-drawer-container> | ||
197 | - <mat-drawer-container *ngIf="!widgetEditMode" hasBackdrop="false" class="tb-select-widget-sidenav"> | ||
198 | - <mat-drawer class="tb-details-drawer" | ||
199 | - [opened]="isAddingWidget" | ||
200 | - mode="over" | ||
201 | - position="end"> | ||
202 | - <tb-details-panel *ngIf="isAddingWidget" fxFlex | 226 | + <tb-details-panel *ngIf="!isAddingWidgetClosed && !widgetEditMode" fxFlex |
203 | headerTitle="{{'dashboard.select-widget-title' | translate}}" | 227 | headerTitle="{{'dashboard.select-widget-title' | translate}}" |
204 | headerHeightPx="120" | 228 | headerHeightPx="120" |
205 | [isReadOnly]="true" | 229 | [isReadOnly]="true" |
@@ -218,40 +242,12 @@ | @@ -218,40 +242,12 @@ | ||
218 | </div> | 242 | </div> |
219 | </div> | 243 | </div> |
220 | <tb-dashboard-widget-select *ngIf="isAddingWidget" | 244 | <tb-dashboard-widget-select *ngIf="isAddingWidget" |
221 | - [aliasController]="dashboardCtx.aliasController" | ||
222 | - [widgetsBundle]="widgetsBundle" | ||
223 | - (widgetSelected)="addWidgetFromType($event)"> | 245 | + [aliasController]="dashboardCtx.aliasController" |
246 | + [widgetsBundle]="widgetsBundle" | ||
247 | + (widgetSelected)="addWidgetFromType($event)"> | ||
224 | </tb-dashboard-widget-select> | 248 | </tb-dashboard-widget-select> |
225 | </tb-details-panel> | 249 | </tb-details-panel> |
226 | </mat-drawer> | 250 | </mat-drawer> |
227 | </mat-drawer-container> | 251 | </mat-drawer-container> |
228 | - <!--tb-details-sidenav TODO --> | ||
229 | - <section fxLayout="row" class="layout-wrap tb-footer-buttons" fxLayoutAlign="start end"> | ||
230 | - <tb-footer-fab-buttons [fxShow]="!isAddingWidget && isEdit && !widgetEditMode" | ||
231 | - relative | ||
232 | - [footerFabButtons]="addWidgetFabButtons"> | ||
233 | - </tb-footer-fab-buttons> | ||
234 | - <button *ngIf="(isTenantAdmin() || isSystemAdmin()) && !forceFullscreen" | ||
235 | - mat-fab color="accent" class="tb-btn-footer" | ||
236 | - [ngClass]="{'tb-hide': !isEdit || isAddingWidget}" | ||
237 | - [disabled]="isLoading$ | async" | ||
238 | - (click)="saveDashboard()" | ||
239 | - matTooltip="{{ 'action.apply-changes' | translate }}" | ||
240 | - matTooltipPosition="above"> | ||
241 | - <mat-icon>done</mat-icon> | ||
242 | - </button> | ||
243 | - <button *ngIf="(isTenantAdmin() || isSystemAdmin()) && !forceFullscreen" | ||
244 | - mat-fab color="accent" class="tb-btn-footer" | ||
245 | - [ngClass]="{'tb-hide': isAddingWidget || (isLoading$ | async)}" | ||
246 | - [disabled]="isLoading$ | async" | ||
247 | - (click)="toggleDashboardEditMode()" | ||
248 | - matTooltip="{{ (isEdit ? 'action.decline-changes': 'action.enter-edit-mode') | translate }}" | ||
249 | - matTooltipPosition="above"> | ||
250 | - <mat-icon>{{ isEdit ? 'close' : 'edit' }}</mat-icon> | ||
251 | - </button> | ||
252 | - </section> | ||
253 | - </section> | ||
254 | - <section class="tb-powered-by-footer" [ngStyle]="{'color': dashboard.configuration.settings.titleColor}"> | ||
255 | - <span>Powered by <a href="https://thingsboard.io" target="_blank">Thingsboard v.{{ thingsboardVersion }}</a></span> | ||
256 | </section> | 252 | </section> |
257 | </div> | 253 | </div> |
@@ -32,9 +32,9 @@ div.tb-dashboard-page { | @@ -32,9 +32,9 @@ div.tb-dashboard-page { | ||
32 | background-color: #eee; | 32 | background-color: #eee; |
33 | } | 33 | } |
34 | section.tb-dashboard-title { | 34 | section.tb-dashboard-title { |
35 | - position: absolute; | ||
36 | - top: 0; | ||
37 | - left: 20px; | 35 | + position: relative; |
36 | + padding-left: 20px; | ||
37 | + max-height: 60px; | ||
38 | mat-form-field { | 38 | mat-form-field { |
39 | .mat-form-field-infix { | 39 | .mat-form-field-infix { |
40 | width: 100%; | 40 | width: 100%; |
@@ -47,17 +47,6 @@ div.tb-dashboard-page { | @@ -47,17 +47,6 @@ div.tb-dashboard-page { | ||
47 | letter-spacing: .005em; | 47 | letter-spacing: .005em; |
48 | } | 48 | } |
49 | } | 49 | } |
50 | - div.tb-padded { | ||
51 | - top: 60px; | ||
52 | - } | ||
53 | - | ||
54 | - section.tb-padded { | ||
55 | - top: 60px; | ||
56 | - } | ||
57 | - | ||
58 | - div.tb-shrinked { | ||
59 | - width: 40%; | ||
60 | - } | ||
61 | 50 | ||
62 | section.tb-dashboard-toolbar { | 51 | section.tb-dashboard-toolbar { |
63 | position: absolute; | 52 | position: absolute; |
@@ -106,21 +95,16 @@ div.tb-dashboard-page { | @@ -106,21 +95,16 @@ div.tb-dashboard-page { | ||
106 | transition: margin-top .3s cubic-bezier(.55, 0, .55, .2) .2s; | 95 | transition: margin-top .3s cubic-bezier(.55, 0, .55, .2) .2s; |
107 | } | 96 | } |
108 | } | 97 | } |
98 | + } | ||
109 | 99 | ||
110 | - .tb-dashboard-layouts { | ||
111 | - /*md-backdrop { | ||
112 | - z-index: 1; | ||
113 | - }*/ | ||
114 | - #tb-right-layout { | ||
115 | - mat-drawer { | ||
116 | - z-index: 1; | ||
117 | - } | 100 | + mat-drawer-container.tb-dashboard-drawer-container { |
101 | + mat-drawer-container.tb-dashboard-layouts { | ||
102 | + width: 100%; | ||
103 | + &.tb-shrinked { | ||
104 | + width: 40%; | ||
118 | } | 105 | } |
119 | } | 106 | } |
120 | - } | ||
121 | 107 | ||
122 | - mat-drawer-container.tb-widget-details-sidenav { | ||
123 | - position: initial; | ||
124 | mat-drawer.tb-details-drawer { | 108 | mat-drawer.tb-details-drawer { |
125 | @media #{$mat-gt-sm} { | 109 | @media #{$mat-gt-sm} { |
126 | width: 85% !important; | 110 | width: 85% !important; |
@@ -136,10 +120,6 @@ div.tb-dashboard-page { | @@ -136,10 +120,6 @@ div.tb-dashboard-page { | ||
136 | } | 120 | } |
137 | } | 121 | } |
138 | 122 | ||
139 | - mat-drawer-container.tb-select-widget-sidenav { | ||
140 | - position: initial; | ||
141 | - } | ||
142 | - | ||
143 | section.tb-powered-by-footer { | 123 | section.tb-powered-by-footer { |
144 | position: absolute; | 124 | position: absolute; |
145 | right: 25px; | 125 | right: 25px; |
@@ -104,9 +104,11 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC | @@ -104,9 +104,11 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC | ||
104 | isFullscreen = false; | 104 | isFullscreen = false; |
105 | isEdit = false; | 105 | isEdit = false; |
106 | isEditingWidget = false; | 106 | isEditingWidget = false; |
107 | + isEditingWidgetClosed = true; | ||
107 | isMobile = !this.breakpointObserver.isMatched(MediaBreakpoints['gt-sm']); | 108 | isMobile = !this.breakpointObserver.isMatched(MediaBreakpoints['gt-sm']); |
108 | forceDashboardMobileMode = false; | 109 | forceDashboardMobileMode = false; |
109 | isAddingWidget = false; | 110 | isAddingWidget = false; |
111 | + isAddingWidgetClosed = true; | ||
110 | widgetsBundle: WidgetsBundle = null; | 112 | widgetsBundle: WidgetsBundle = null; |
111 | 113 | ||
112 | isToolbarOpened = false; | 114 | isToolbarOpened = false; |
@@ -284,8 +286,10 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC | @@ -284,8 +286,10 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC | ||
284 | this.isFullscreen = false; | 286 | this.isFullscreen = false; |
285 | this.isEdit = false; | 287 | this.isEdit = false; |
286 | this.isEditingWidget = false; | 288 | this.isEditingWidget = false; |
289 | + this.isEditingWidgetClosed = true; | ||
287 | this.forceDashboardMobileMode = false; | 290 | this.forceDashboardMobileMode = false; |
288 | this.isAddingWidget = false; | 291 | this.isAddingWidget = false; |
292 | + this.isAddingWidgetClosed = true; | ||
289 | this.widgetsBundle = null; | 293 | this.widgetsBundle = null; |
290 | 294 | ||
291 | this.isToolbarOpened = false; | 295 | this.isToolbarOpened = false; |
@@ -694,6 +698,31 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC | @@ -694,6 +698,31 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC | ||
694 | this.isAddingWidget = false; | 698 | this.isAddingWidget = false; |
695 | } | 699 | } |
696 | 700 | ||
701 | + detailsDrawerOpenedStart() { | ||
702 | + if (this.isEditingWidget) { | ||
703 | + this.isEditingWidgetClosed = false; | ||
704 | + } else if (this.isAddingWidget) { | ||
705 | + this.isAddingWidgetClosed = false; | ||
706 | + } | ||
707 | + setTimeout(() => { | ||
708 | + this.cd.detach(); | ||
709 | + }, 0); | ||
710 | + } | ||
711 | + | ||
712 | + detailsDrawerOpened() { | ||
713 | + this.cd.reattach(); | ||
714 | + } | ||
715 | + | ||
716 | + detailsDrawerClosedStart() { | ||
717 | + this.cd.detach(); | ||
718 | + } | ||
719 | + | ||
720 | + detailsDrawerClosed() { | ||
721 | + this.isEditingWidgetClosed = true; | ||
722 | + this.isAddingWidgetClosed = true; | ||
723 | + this.cd.reattach(); | ||
724 | + } | ||
725 | + | ||
697 | private addWidgetToLayout(widget: Widget, layoutId: DashboardLayoutId) { | 726 | private addWidgetToLayout(widget: Widget, layoutId: DashboardLayoutId) { |
698 | this.dashboardUtils.addWidgetToLayout(this.dashboard, this.dashboardCtx.state, layoutId, widget); | 727 | this.dashboardUtils.addWidgetToLayout(this.dashboard, this.dashboardCtx.state, layoutId, widget); |
699 | this.layouts[layoutId].layoutCtx.widgets.addWidgetId(widget.id); | 728 | this.layouts[layoutId].layoutCtx.widgets.addWidgetId(widget.id); |
@@ -77,6 +77,8 @@ export class LayoutWidgetsArray implements Iterable<Widget> { | @@ -77,6 +77,8 @@ export class LayoutWidgetsArray implements Iterable<Widget> { | ||
77 | private widgetIds: string[] = []; | 77 | private widgetIds: string[] = []; |
78 | private pointer = 0; | 78 | private pointer = 0; |
79 | 79 | ||
80 | + private loaded = false; | ||
81 | + | ||
80 | constructor(private dashboard: Dashboard) { | 82 | constructor(private dashboard: Dashboard) { |
81 | } | 83 | } |
82 | 84 | ||
@@ -84,8 +86,17 @@ export class LayoutWidgetsArray implements Iterable<Widget> { | @@ -84,8 +86,17 @@ export class LayoutWidgetsArray implements Iterable<Widget> { | ||
84 | return this.widgetIds.length; | 86 | return this.widgetIds.length; |
85 | } | 87 | } |
86 | 88 | ||
89 | + isLoading() { | ||
90 | + return !this.loaded; | ||
91 | + } | ||
92 | + | ||
93 | + isEmpty() { | ||
94 | + return this.loaded && this.widgetIds.length === 0; | ||
95 | + } | ||
96 | + | ||
87 | setWidgetIds(widgetIds: string[]) { | 97 | setWidgetIds(widgetIds: string[]) { |
88 | this.widgetIds = widgetIds; | 98 | this.widgetIds = widgetIds; |
99 | + this.loaded = true; | ||
89 | } | 100 | } |
90 | 101 | ||
91 | addWidgetId(widgetId: string) { | 102 | addWidgetId(widgetId: string) { |
@@ -102,6 +102,9 @@ export class EditWidgetComponent extends PageComponent implements OnInit, OnChan | @@ -102,6 +102,9 @@ export class EditWidgetComponent extends PageComponent implements OnInit, OnChan | ||
102 | } | 102 | } |
103 | 103 | ||
104 | private loadWidgetConfig() { | 104 | private loadWidgetConfig() { |
105 | + if (!this.widget) { | ||
106 | + return; | ||
107 | + } | ||
105 | const widgetInfo = this.widgetComponentService.getInstantWidgetInfo(this.widget); | 108 | const widgetInfo = this.widgetComponentService.getInstantWidgetInfo(this.widget); |
106 | const rawSettingsSchema = widgetInfo.typeSettingsSchema || widgetInfo.settingsSchema; | 109 | const rawSettingsSchema = widgetInfo.typeSettingsSchema || widgetInfo.settingsSchema; |
107 | const rawDataKeySettingsSchema = widgetInfo.typeDataKeySettingsSchema || widgetInfo.dataKeySettingsSchema; | 110 | const rawDataKeySettingsSchema = widgetInfo.typeDataKeySettingsSchema || widgetInfo.dataKeySettingsSchema; |
@@ -16,10 +16,15 @@ | @@ -16,10 +16,15 @@ | ||
16 | 16 | ||
17 | --> | 17 | --> |
18 | <hotkeys-cheatsheet></hotkeys-cheatsheet> | 18 | <hotkeys-cheatsheet></hotkeys-cheatsheet> |
19 | +<div fxLayout="column" class="tb-progress-cover" fxLayoutAlign="center center" | ||
20 | + *ngIf="layoutCtx.widgets.isLoading()"> | ||
21 | + <mat-spinner color="warn" mode="indeterminate" diameter="100"> | ||
22 | + </mat-spinner> | ||
23 | +</div> | ||
19 | <div class="mat-content" style="position: relative; width: 100%; height: 100%;" | 24 | <div class="mat-content" style="position: relative; width: 100%; height: 100%;" |
20 | [style.backgroundImage]="backgroundImage" | 25 | [style.backgroundImage]="backgroundImage" |
21 | [ngStyle]="dashboardStyle"> | 26 | [ngStyle]="dashboardStyle"> |
22 | - <section *ngIf="layoutCtx.widgets.size() === 0" fxLayoutAlign="center center" | 27 | + <section *ngIf="layoutCtx.widgets.isEmpty()" fxLayoutAlign="center center" |
23 | [ngStyle]="{'color': layoutCtx.gridSettings.color}" | 28 | [ngStyle]="{'color': layoutCtx.gridSettings.color}" |
24 | style="text-transform: uppercase; display: flex; z-index: 1; pointer-events: none;" | 29 | style="text-transform: uppercase; display: flex; z-index: 1; pointer-events: none;" |
25 | class="mat-headline tb-absolute-fill"> | 30 | class="mat-headline tb-absolute-fill"> |
@@ -31,8 +31,8 @@ | @@ -31,8 +31,8 @@ | ||
31 | <mat-icon class="material-icons">{{ fullscreen ? 'fullscreen_exit' : 'fullscreen' }}</mat-icon> | 31 | <mat-icon class="material-icons">{{ fullscreen ? 'fullscreen_exit' : 'fullscreen' }}</mat-icon> |
32 | </button> | 32 | </button> |
33 | </div> | 33 | </div> |
34 | - <div fxFlex="0%" id="tb-javascript-panel" class="tb-js-func-panel" fxLayout="column" tb-toast toastTarget="jsFuncEditor"> | ||
35 | - <div fxFlex #javascriptEditor id="tb-javascript-input" [ngClass]="{'fill-height': fillHeight}"></div> | 34 | + <div id="tb-javascript-panel" class="tb-js-func-panel" fxLayout="column" tb-toast toastTarget="jsFuncEditor"> |
35 | + <div #javascriptEditor id="tb-javascript-input" [ngClass]="{'fill-height': fillHeight}"></div> | ||
36 | </div> | 36 | </div> |
37 | <div fxLayout="row" fxLayoutAlign="start center" style="height: 40px;"> | 37 | <div fxLayout="row" fxLayoutAlign="start center" style="height: 40px;"> |
38 | <label class="tb-title no-padding">}</label> | 38 | <label class="tb-title no-padding">}</label> |
@@ -30,7 +30,7 @@ | @@ -30,7 +30,7 @@ | ||
30 | <mat-icon class="material-icons">{{ fullscreen ? 'fullscreen_exit' : 'fullscreen' }}</mat-icon> | 30 | <mat-icon class="material-icons">{{ fullscreen ? 'fullscreen_exit' : 'fullscreen' }}</mat-icon> |
31 | </button> | 31 | </button> |
32 | </div> | 32 | </div> |
33 | - <div fxFlex="0%" id="tb-json-panel" tb-toast toastTarget="jsonObjectEditor" | 33 | + <div id="tb-json-panel" tb-toast toastTarget="jsonObjectEditor" |
34 | class="tb-json-object-panel" fxLayout="column"> | 34 | class="tb-json-object-panel" fxLayout="column"> |
35 | <div #jsonEditor id="tb-json-input" [ngStyle]="editorStyle" [ngClass]="{'fill-height': fillHeight}"></div> | 35 | <div #jsonEditor id="tb-json-input" [ngStyle]="editorStyle" [ngClass]="{'fill-height': fillHeight}"></div> |
36 | </div> | 36 | </div> |
@@ -144,7 +144,7 @@ class DraggableChip { | @@ -144,7 +144,7 @@ class DraggableChip { | ||
144 | const dataTransfer = event.dataTransfer; | 144 | const dataTransfer = event.dataTransfer; |
145 | dataTransfer.effectAllowed = 'copyMove'; | 145 | dataTransfer.effectAllowed = 'copyMove'; |
146 | dataTransfer.dropEffect = 'move'; | 146 | dataTransfer.dropEffect = 'move'; |
147 | - dataTransfer.setData('text/plain', this.index() + ''); | 147 | + dataTransfer.setData('text', this.index() + ''); |
148 | } | 148 | } |
149 | } | 149 | } |
150 | 150 | ||
@@ -222,7 +222,7 @@ class DraggableChip { | @@ -222,7 +222,7 @@ class DraggableChip { | ||
222 | return; | 222 | return; |
223 | } | 223 | } |
224 | event = (event as any).originalEvent || event; | 224 | event = (event as any).originalEvent || event; |
225 | - const droppedItemIndex = parseInt(event.dataTransfer.getData('text/plain'), 10); | 225 | + const droppedItemIndex = parseInt(event.dataTransfer.getData('text'), 10); |
226 | const currentIndex = this.index(); | 226 | const currentIndex = this.index(); |
227 | let newIndex; | 227 | let newIndex; |
228 | if (this.dropPosition === 'before') { | 228 | if (this.dropPosition === 'before') { |
@@ -17,94 +17,92 @@ | @@ -17,94 +17,92 @@ | ||
17 | --> | 17 | --> |
18 | <form [formGroup]="timewindowForm" (ngSubmit)="update()"> | 18 | <form [formGroup]="timewindowForm" (ngSubmit)="update()"> |
19 | <fieldset [disabled]="(isLoading$ | async)"> | 19 | <fieldset [disabled]="(isLoading$ | async)"> |
20 | - <div class="mat-content" style="height: 100%;" fxFlex fxLayout="column"> | ||
21 | - <section fxLayout="column"> | ||
22 | - <mat-tab-group dynamicHeight [ngClass]="{'tb-headless': historyOnly}" | ||
23 | - (selectedIndexChange)="timewindowForm.markAsDirty()" [(selectedIndex)]="timewindow.selectedTab"> | ||
24 | - <mat-tab label="{{ 'timewindow.realtime' | translate }}"> | ||
25 | - <div formGroupName="realtime" class="mat-content mat-padding" fxLayout="column"> | ||
26 | - <tb-timeinterval | ||
27 | - formControlName="timewindowMs" | ||
28 | - predefinedName="timewindow.last" | ||
29 | - [required]="timewindow.selectedTab === timewindowTypes.REALTIME" | ||
30 | - style="padding-top: 8px;"></tb-timeinterval> | ||
31 | - </div> | ||
32 | - </mat-tab> | ||
33 | - <mat-tab label="{{ 'timewindow.history' | translate }}"> | ||
34 | - <div formGroupName="history" class="mat-content mat-padding" style="padding-top: 8px;"> | ||
35 | - <mat-radio-group formControlName="historyType"> | ||
36 | - <mat-radio-button [value]="historyTypes.LAST_INTERVAL" color="primary"> | ||
37 | - <section fxLayout="column"> | ||
38 | - <tb-timeinterval | ||
39 | - formControlName="timewindowMs" | ||
40 | - predefinedName="timewindow.last" | ||
41 | - [fxShow]="timewindowForm.get('history').get('historyType').value === historyTypes.LAST_INTERVAL" | ||
42 | - [required]="timewindow.selectedTab === timewindowTypes.HISTORY && | ||
43 | - timewindowForm.get('history').get('historyType').value === historyTypes.LAST_INTERVAL" | ||
44 | - style="padding-top: 8px;"></tb-timeinterval> | ||
45 | - </section> | ||
46 | - </mat-radio-button> | ||
47 | - <mat-radio-button [value]="historyTypes.FIXED" color="primary"> | ||
48 | - <section fxLayout="column"> | ||
49 | - <span translate>timewindow.time-period</span> | ||
50 | - <tb-datetime-period | ||
51 | - formControlName="fixedTimewindow" | ||
52 | - [fxShow]="timewindowForm.get('history').get('historyType').value === historyTypes.FIXED" | ||
53 | - [required]="timewindow.selectedTab === timewindowTypes.HISTORY && | ||
54 | - timewindowForm.get('history').get('historyType').value === historyTypes.FIXED" | ||
55 | - style="padding-top: 8px;"></tb-datetime-period> | ||
56 | - </section> | ||
57 | - </mat-radio-button> | ||
58 | - </mat-radio-group> | ||
59 | - </div> | ||
60 | - </mat-tab> | ||
61 | - </mat-tab-group> | ||
62 | - <div *ngIf="aggregation" formGroupName="aggregation" class="mat-content mat-padding" fxLayout="column"> | ||
63 | - <mat-form-field> | ||
64 | - <mat-label translate>aggregation.function</mat-label> | ||
65 | - <mat-select matInput formControlName="type" style="min-width: 150px;"> | ||
66 | - <mat-option *ngFor="let aggregation of aggregations" [value]="aggregation"> | ||
67 | - {{ aggregationTypesTranslations.get(aggregation) | translate }} | ||
68 | - </mat-option> | ||
69 | - </mat-select> | ||
70 | - </mat-form-field> | ||
71 | - <div *ngIf="timewindowForm.get('aggregation').get('type').value === aggregationTypes.NONE" | ||
72 | - class="limit-slider-container" | ||
73 | - fxLayout="row" fxLayoutAlign="start center"> | ||
74 | - <span translate>aggregation.limit</span> | ||
75 | - <mat-slider fxFlex formControlName="limit" | ||
76 | - thumbLabel | ||
77 | - [value]="timewindowForm.get('aggregation').get('limit').value" | ||
78 | - min="{{minDatapointsLimit()}}" | ||
79 | - max="{{maxDatapointsLimit()}}"> | ||
80 | - </mat-slider> | ||
81 | - <mat-form-field style="max-width: 80px;"> | ||
82 | - <input matInput formControlName="limit" type="number" step="1" | ||
83 | - [value]="timewindowForm.get('aggregation').get('limit').value" | ||
84 | - min="{{minDatapointsLimit()}}" | ||
85 | - max="{{maxDatapointsLimit()}}"/> | ||
86 | - </mat-form-field> | 20 | + <div class="mat-content" style="height: 100%;" fxLayout="column"> |
21 | + <mat-tab-group dynamicHeight [ngClass]="{'tb-headless': historyOnly}" | ||
22 | + (selectedIndexChange)="timewindowForm.markAsDirty()" [(selectedIndex)]="timewindow.selectedTab"> | ||
23 | + <mat-tab label="{{ 'timewindow.realtime' | translate }}"> | ||
24 | + <div formGroupName="realtime" class="mat-content mat-padding" fxLayout="column"> | ||
25 | + <tb-timeinterval | ||
26 | + formControlName="timewindowMs" | ||
27 | + predefinedName="timewindow.last" | ||
28 | + [required]="timewindow.selectedTab === timewindowTypes.REALTIME" | ||
29 | + style="padding-top: 8px;"></tb-timeinterval> | ||
87 | </div> | 30 | </div> |
31 | + </mat-tab> | ||
32 | + <mat-tab label="{{ 'timewindow.history' | translate }}"> | ||
33 | + <div formGroupName="history" class="mat-content mat-padding" style="padding-top: 8px;"> | ||
34 | + <mat-radio-group formControlName="historyType"> | ||
35 | + <mat-radio-button [value]="historyTypes.LAST_INTERVAL" color="primary"> | ||
36 | + <section fxLayout="column"> | ||
37 | + <tb-timeinterval | ||
38 | + formControlName="timewindowMs" | ||
39 | + predefinedName="timewindow.last" | ||
40 | + [fxShow]="timewindowForm.get('history').get('historyType').value === historyTypes.LAST_INTERVAL" | ||
41 | + [required]="timewindow.selectedTab === timewindowTypes.HISTORY && | ||
42 | + timewindowForm.get('history').get('historyType').value === historyTypes.LAST_INTERVAL" | ||
43 | + style="padding-top: 8px;"></tb-timeinterval> | ||
44 | + </section> | ||
45 | + </mat-radio-button> | ||
46 | + <mat-radio-button [value]="historyTypes.FIXED" color="primary"> | ||
47 | + <section fxLayout="column"> | ||
48 | + <span translate>timewindow.time-period</span> | ||
49 | + <tb-datetime-period | ||
50 | + formControlName="fixedTimewindow" | ||
51 | + [fxShow]="timewindowForm.get('history').get('historyType').value === historyTypes.FIXED" | ||
52 | + [required]="timewindow.selectedTab === timewindowTypes.HISTORY && | ||
53 | + timewindowForm.get('history').get('historyType').value === historyTypes.FIXED" | ||
54 | + style="padding-top: 8px;"></tb-datetime-period> | ||
55 | + </section> | ||
56 | + </mat-radio-button> | ||
57 | + </mat-radio-group> | ||
58 | + </div> | ||
59 | + </mat-tab> | ||
60 | + </mat-tab-group> | ||
61 | + <div *ngIf="aggregation" formGroupName="aggregation" class="mat-content mat-padding" fxLayout="column"> | ||
62 | + <mat-form-field> | ||
63 | + <mat-label translate>aggregation.function</mat-label> | ||
64 | + <mat-select matInput formControlName="type" style="min-width: 150px;"> | ||
65 | + <mat-option *ngFor="let aggregation of aggregations" [value]="aggregation"> | ||
66 | + {{ aggregationTypesTranslations.get(aggregation) | translate }} | ||
67 | + </mat-option> | ||
68 | + </mat-select> | ||
69 | + </mat-form-field> | ||
70 | + <div *ngIf="timewindowForm.get('aggregation').get('type').value === aggregationTypes.NONE" | ||
71 | + class="limit-slider-container" | ||
72 | + fxLayout="row" fxLayoutAlign="start center"> | ||
73 | + <span translate>aggregation.limit</span> | ||
74 | + <mat-slider fxFlex formControlName="limit" | ||
75 | + thumbLabel | ||
76 | + [value]="timewindowForm.get('aggregation').get('limit').value" | ||
77 | + min="{{minDatapointsLimit()}}" | ||
78 | + max="{{maxDatapointsLimit()}}"> | ||
79 | + </mat-slider> | ||
80 | + <mat-form-field style="max-width: 80px;"> | ||
81 | + <input matInput formControlName="limit" type="number" step="1" | ||
82 | + [value]="timewindowForm.get('aggregation').get('limit').value" | ||
83 | + min="{{minDatapointsLimit()}}" | ||
84 | + max="{{maxDatapointsLimit()}}"/> | ||
85 | + </mat-form-field> | ||
88 | </div> | 86 | </div> |
89 | - <div formGroupName="realtime" | ||
90 | - *ngIf="aggregation && timewindowForm.get('aggregation').get('type').value !== aggregationTypes.NONE && | ||
91 | - timewindow.selectedTab === timewindowTypes.REALTIME" class="mat-content mat-padding" fxLayout="column"> | ||
92 | - <tb-timeinterval | ||
93 | - formControlName="interval" | ||
94 | - [min]="minRealtimeAggInterval()" [max]="maxRealtimeAggInterval()" | ||
95 | - predefinedName="aggregation.group-interval"> | ||
96 | - </tb-timeinterval> | ||
97 | - </div> | ||
98 | - <div formGroupName="history" | ||
99 | - *ngIf="aggregation && timewindowForm.get('aggregation').get('type').value !== aggregationTypes.NONE && | ||
100 | - timewindow.selectedTab === timewindowTypes.HISTORY" class="mat-content mat-padding" fxLayout="column"> | ||
101 | - <tb-timeinterval | ||
102 | - formControlName="interval" | ||
103 | - [min]="minHistoryAggInterval()" [max]="maxHistoryAggInterval()" | ||
104 | - predefinedName="aggregation.group-interval"> | ||
105 | - </tb-timeinterval> | ||
106 | - </div> | ||
107 | - </section> | 87 | + </div> |
88 | + <div formGroupName="realtime" | ||
89 | + *ngIf="aggregation && timewindowForm.get('aggregation').get('type').value !== aggregationTypes.NONE && | ||
90 | + timewindow.selectedTab === timewindowTypes.REALTIME" class="mat-content mat-padding" fxLayout="column"> | ||
91 | + <tb-timeinterval | ||
92 | + formControlName="interval" | ||
93 | + [min]="minRealtimeAggInterval()" [max]="maxRealtimeAggInterval()" | ||
94 | + predefinedName="aggregation.group-interval"> | ||
95 | + </tb-timeinterval> | ||
96 | + </div> | ||
97 | + <div formGroupName="history" | ||
98 | + *ngIf="aggregation && timewindowForm.get('aggregation').get('type').value !== aggregationTypes.NONE && | ||
99 | + timewindow.selectedTab === timewindowTypes.HISTORY" class="mat-content mat-padding" fxLayout="column"> | ||
100 | + <tb-timeinterval | ||
101 | + formControlName="interval" | ||
102 | + [min]="minHistoryAggInterval()" [max]="maxHistoryAggInterval()" | ||
103 | + predefinedName="aggregation.group-interval"> | ||
104 | + </tb-timeinterval> | ||
105 | + </div> | ||
108 | <span fxFlex></span> | 106 | <span fxFlex></span> |
109 | <div fxLayout="row" class="tb-panel-actions"> | 107 | <div fxLayout="row" class="tb-panel-actions"> |
110 | <span fxFlex></span> | 108 | <span fxFlex></span> |