37 changed files with 1830 additions and 170 deletions
@ -0,0 +1,65 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2019 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. |
|||
|
|||
--> |
|||
<div class="mat-content" style="position: relative; width: 100%; height: 100%;" |
|||
[ngStyle]="{'background-color': layoutCtx.gridSettings.backgroundColor, |
|||
'background-image': layoutCtx.gridSettings.backgroundImageUrl ? |
|||
'url('+layoutCtx.gridSettings.backgroundImageUrl+')' : 'none', |
|||
'background-repeat': 'no-repeat', |
|||
'background-attachment': 'scroll', |
|||
'background-size': layoutCtx.gridSettings.backgroundSizeMode || '100%', |
|||
'background-position': '0% 0%'}"> |
|||
<section *ngIf="layoutCtx.widgets.length === 0" fxLayoutAlign="center center" |
|||
[ngStyle]="{'color': layoutCtx.gridSettings.color}" |
|||
style="text-transform: uppercase; display: flex; z-index: 1; pointer-events: none;" |
|||
class="mat-headline tb-absolute-fill"> |
|||
<span *ngIf="!isEdit"> |
|||
{{'dashboard.no-widgets' | translate}} |
|||
</span> |
|||
<button mat-button *ngIf="isEdit && !widgetEditMode" class="tb-add-new-widget" |
|||
(click)="addWidget($event)"> |
|||
<mat-icon class="tb-mat-96">add</mat-icon> |
|||
{{ 'dashboard.add-widget' | translate }} |
|||
</button> |
|||
</section> |
|||
<tb-dashboard #dashboard [dashboardStyle]="{'background-color': layoutCtx.gridSettings.backgroundColor, |
|||
'background-image': layoutCtx.gridSettings.backgroundImageUrl ? |
|||
'url('+layoutCtx.gridSettings.backgroundImageUrl+')' : 'none', |
|||
'background-repeat': 'no-repeat', |
|||
'background-attachment': 'scroll', |
|||
'background-size': layoutCtx.gridSettings.backgroundSizeMode || '100%', |
|||
'background-position': '0% 0%'}" |
|||
[widgets]="layoutCtx.widgets" |
|||
[widgetLayouts]="layoutCtx.widgetLayouts" |
|||
[columns]="layoutCtx.gridSettings.columns" |
|||
[horizontalMargin]="layoutCtx.gridSettings.margins ? layoutCtx.gridSettings.margins[0] : 10" |
|||
[verticalMargin]="layoutCtx.gridSettings.margins ? layoutCtx.gridSettings.margins[1]: 10" |
|||
[aliasController]="dashboardCtx.aliasController" |
|||
[stateController]="dashboardCtx.stateController" |
|||
[dashboardTimewindow]="dashboardCtx.dashboardTimewindow" |
|||
[isEdit]="isEdit" |
|||
[autofillHeight]="layoutCtx.gridSettings.autoFillHeight && !isEdit" |
|||
[mobileAutofillHeight]="layoutCtx.gridSettings.mobileAutoFillHeight && !isEdit" |
|||
[mobileRowHeight]="layoutCtx.gridSettings.mobileRowHeight" |
|||
[isMobile]="isMobile" |
|||
[isMobileDisabled]="widgetEditMode" |
|||
[isEditActionEnabled]="isEdit" |
|||
[isExportActionEnabled]="isEdit && !widgetEditMode" |
|||
[isRemoveActionEnabled]="isEdit && !widgetEditMode" |
|||
[ignoreLoading]="layoutCtx.ignoreLoading"> |
|||
</tb-dashboard> |
|||
</div> |
|||
@ -0,0 +1,23 @@ |
|||
/** |
|||
* Copyright © 2016-2019 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. |
|||
*/ |
|||
:host { |
|||
button.tb-add-new-widget { |
|||
padding-right: 12px; |
|||
font-size: 24px; |
|||
border-style: dashed; |
|||
border-width: 2px; |
|||
} |
|||
} |
|||
@ -0,0 +1,80 @@ |
|||
///
|
|||
/// Copyright © 2016-2019 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.
|
|||
///
|
|||
|
|||
import { Component, OnDestroy, OnInit, Input, ChangeDetectorRef, ViewChild } from '@angular/core'; |
|||
import { StateControllerComponent } from '@home/pages/dashboard/states/state-controller.component'; |
|||
import { ILayoutController } from '@home/pages/dashboard/layout/layout.models'; |
|||
import { DashboardContext, DashboardPageLayoutContext } from '@home/pages/dashboard/dashboard-page.models'; |
|||
import { PageComponent } from '@shared/components/page.component'; |
|||
import { Store } from '@ngrx/store'; |
|||
import { AppState } from '@core/core.state'; |
|||
import { Widget } from '@shared/models/widget.models'; |
|||
import { WidgetLayouts } from '@shared/models/dashboard.models'; |
|||
import { GridsterComponent } from 'angular-gridster2'; |
|||
import { IDashboardComponent } from '@home/models/dashboard-component.models'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-dashboard-layout', |
|||
templateUrl: './dashboard-layout.component.html', |
|||
styleUrls: ['./dashboard-layout.component.scss'] |
|||
}) |
|||
export class DashboardLayoutComponent extends PageComponent implements ILayoutController, OnInit, OnDestroy { |
|||
|
|||
layoutCtxValue: DashboardPageLayoutContext; |
|||
|
|||
@Input() |
|||
set layoutCtx(val: DashboardPageLayoutContext) { |
|||
this.layoutCtxValue = val; |
|||
if (this.layoutCtxValue) { |
|||
this.layoutCtxValue.ctrl = this; |
|||
} |
|||
} |
|||
get layoutCtx(): DashboardPageLayoutContext { |
|||
return this.layoutCtxValue; |
|||
} |
|||
|
|||
@Input() |
|||
dashboardCtx: DashboardContext; |
|||
|
|||
@Input() |
|||
isEdit: boolean; |
|||
|
|||
@Input() |
|||
isMobile: boolean; |
|||
|
|||
@Input() |
|||
widgetEditMode: boolean; |
|||
|
|||
@ViewChild('dashboard', {static: true}) dashboard: IDashboardComponent; |
|||
|
|||
constructor(protected store: Store<AppState>, |
|||
private cd: ChangeDetectorRef) { |
|||
super(store); |
|||
} |
|||
|
|||
ngOnInit(): void { |
|||
} |
|||
|
|||
ngOnDestroy(): void { |
|||
} |
|||
|
|||
reload() { |
|||
} |
|||
|
|||
setResizing(layoutVisibilityChanged: boolean) { |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
///
|
|||
/// Copyright © 2016-2019 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.
|
|||
///
|
|||
|
|||
export interface ILayoutController { |
|||
reload(); |
|||
setResizing(layoutVisibilityChanged: boolean); |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2019 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. |
|||
|
|||
--> |
|||
<mat-select class="default-state-controller" [fxShow]="displayStateSelection()" |
|||
[(ngModel)]="stateObject[0].id" (ngModelChange)="selectedStateIdChanged()"> |
|||
<mat-option *ngFor="let stateKv of states | keyvalue" [value]="stateKv.key"> |
|||
{{getStateName(stateKv.key, stateKv.value)}} |
|||
</mat-option> |
|||
</mat-select> |
|||
@ -0,0 +1,20 @@ |
|||
/** |
|||
* Copyright © 2016-2019 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. |
|||
*/ |
|||
:host { |
|||
mat-select.default-state-controller { |
|||
margin: 0; |
|||
} |
|||
} |
|||
@ -0,0 +1,255 @@ |
|||
///
|
|||
/// Copyright © 2016-2019 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.
|
|||
///
|
|||
|
|||
import { |
|||
Component, |
|||
OnInit, |
|||
ViewEncapsulation, |
|||
Input, |
|||
OnDestroy, |
|||
OnChanges, |
|||
SimpleChanges, |
|||
NgZone |
|||
} from '@angular/core'; |
|||
import { IStateController, StateParams, StateObject } from '@core/api/widget-api.models'; |
|||
import { ActivatedRoute, Router } from '@angular/router'; |
|||
import { Observable, Subscription, of } from 'rxjs'; |
|||
import { IDashboardController } from '@home/pages/dashboard/dashboard-page.models'; |
|||
import { DashboardState } from '@shared/models/dashboard.models'; |
|||
import { IStateControllerComponent, StateControllerState } from './state-controller.models'; |
|||
import { StateControllerComponent } from './state-controller.component'; |
|||
import { StatesControllerService } from '@home/pages/dashboard/states/states-controller.service'; |
|||
import { EntityId } from '@app/shared/models/id/entity-id'; |
|||
import { UtilsService } from '@core/services/utils.service'; |
|||
import { base64toObj, objToBase64 } from '@app/core/utils'; |
|||
import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; |
|||
import { EntityService } from '@core/http/entity.service'; |
|||
import { EntityType } from '@shared/models/entity-type.models'; |
|||
import { map } from 'rxjs/operators'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-default-state-controller', |
|||
templateUrl: './default-state-controller.component.html', |
|||
styleUrls: ['./default-state-controller.component.scss'] |
|||
}) |
|||
export class DefaultStateControllerComponent extends StateControllerComponent implements OnInit, OnDestroy { |
|||
|
|||
constructor(protected router: Router, |
|||
protected route: ActivatedRoute, |
|||
protected statesControllerService: StatesControllerService, |
|||
private utils: UtilsService, |
|||
private entityService: EntityService, |
|||
private dashboardUtils: DashboardUtilsService) { |
|||
super(router, route, statesControllerService); |
|||
} |
|||
|
|||
ngOnInit(): void { |
|||
super.ngOnInit(); |
|||
} |
|||
|
|||
ngOnDestroy(): void { |
|||
super.ngOnDestroy(); |
|||
} |
|||
|
|||
protected init() { |
|||
if (this.preservedState) { |
|||
this.stateObject = this.preservedState; |
|||
setTimeout(() => { |
|||
this.gotoState(this.stateObject[0].id, true); |
|||
}, 1); |
|||
} else { |
|||
const initialState = this.currentState; |
|||
this.stateObject = this.parseState(initialState); |
|||
setTimeout(() => { |
|||
this.gotoState(this.stateObject[0].id, false); |
|||
}, 1); |
|||
} |
|||
} |
|||
|
|||
protected onMobileChanged() { |
|||
} |
|||
|
|||
protected onStateIdChanged() { |
|||
} |
|||
|
|||
protected onStatesChanged() { |
|||
} |
|||
|
|||
protected onStateChanged() { |
|||
this.stateObject = this.parseState(this.currentState); |
|||
this.gotoState(this.stateObject[0].id, true); |
|||
} |
|||
|
|||
protected stateControllerId(): string { |
|||
return 'default'; |
|||
} |
|||
|
|||
public getStateParams(): StateParams { |
|||
if (this.stateObject && this.stateObject.length) { |
|||
return this.stateObject[this.stateObject.length - 1].params; |
|||
} else { |
|||
return {}; |
|||
} |
|||
} |
|||
|
|||
public openState(id: string, params?: StateParams, openRightLayout?: boolean): void { |
|||
if (this.states && this.states[id]) { |
|||
if (!params) { |
|||
params = {}; |
|||
} |
|||
const newState: StateObject = { |
|||
id, |
|||
params |
|||
}; |
|||
this.stateObject[0] = newState; |
|||
this.gotoState(this.stateObject[0].id, true, openRightLayout); |
|||
} |
|||
} |
|||
|
|||
public updateState(id: string, params?: StateParams, openRightLayout?: boolean): void { |
|||
if (!id) { |
|||
id = this.getStateId(); |
|||
} |
|||
if (this.states && this.states[id]) { |
|||
if (!params) { |
|||
params = {}; |
|||
} |
|||
const newState: StateObject = { |
|||
id, |
|||
params |
|||
}; |
|||
this.stateObject[0] = newState; |
|||
this.gotoState(this.stateObject[0].id, true, openRightLayout); |
|||
} |
|||
} |
|||
|
|||
public getEntityId(entityParamName: string): EntityId { |
|||
return null; |
|||
} |
|||
|
|||
public getStateId(): string { |
|||
if (this.stateObject && this.stateObject.length) { |
|||
return this.stateObject[this.stateObject.length - 1].id; |
|||
} else { |
|||
return ''; |
|||
} |
|||
} |
|||
|
|||
public getStateIdAtIndex(index: number): string { |
|||
if (this.stateObject && this.stateObject[index]) { |
|||
return this.stateObject[index].id; |
|||
} else { |
|||
return ''; |
|||
} |
|||
} |
|||
|
|||
public getStateIndex(): number { |
|||
if (this.stateObject && this.stateObject.length) { |
|||
return this.stateObject.length - 1; |
|||
} else { |
|||
return -1; |
|||
} |
|||
} |
|||
|
|||
public getStateParamsByStateId(stateId: string): StateParams { |
|||
const stateObj = this.getStateObjById(stateId); |
|||
if (stateObj) { |
|||
return stateObj.params; |
|||
} else { |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
public navigatePrevState(index: number): void { |
|||
if (index < this.stateObject.length - 1) { |
|||
this.stateObject.splice(index + 1, this.stateObject.length - index - 1); |
|||
this.gotoState(this.stateObject[this.stateObject.length - 1].id, true); |
|||
} |
|||
} |
|||
|
|||
public resetState(): void { |
|||
const rootStateId = this.dashboardUtils.getRootStateId(this.states); |
|||
this.stateObject = [ { id: rootStateId, params: {} } ]; |
|||
this.gotoState(rootStateId, true); |
|||
} |
|||
|
|||
public getStateName(id: string, state: DashboardState): string { |
|||
return this.utils.customTranslation(state.name, id); |
|||
} |
|||
|
|||
public displayStateSelection(): boolean { |
|||
return this.states && Object.keys(this.states).length > 1; |
|||
} |
|||
|
|||
public selectedStateIdChanged() { |
|||
this.gotoState(this.stateObject[0].id, true); |
|||
} |
|||
|
|||
private parseState(stateBase64: string): StateControllerState { |
|||
let result: StateControllerState; |
|||
if (stateBase64) { |
|||
try { |
|||
result = base64toObj(stateBase64); |
|||
} catch (e) { |
|||
result = [ { id: null, params: {} } ]; |
|||
} |
|||
} |
|||
if (!result) { |
|||
result = []; |
|||
} |
|||
if (!result.length) { |
|||
result[0] = { id: null, params: {} }; |
|||
} else if (result.length > 1) { |
|||
const newResult = []; |
|||
newResult.push(result[result.length - 1]); |
|||
result = newResult; |
|||
} |
|||
const rootStateId = this.dashboardUtils.getRootStateId(this.states); |
|||
if (!result[0].id) { |
|||
result[0].id = rootStateId; |
|||
} |
|||
if (!this.states[result[0].id]) { |
|||
result[0].id = rootStateId; |
|||
} |
|||
let i = result.length; |
|||
while (i--) { |
|||
if (!result[i].id || !this.states[result[i].id]) { |
|||
result.splice(i, 1); |
|||
} |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
private gotoState(stateId: string, update: boolean, openRightLayout?: boolean) { |
|||
if (this.dashboardCtrl.dashboardCtx.state !== stateId) { |
|||
this.dashboardCtrl.openDashboardState(stateId, openRightLayout); |
|||
if (update) { |
|||
this.updateLocation(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private updateLocation() { |
|||
if (this.stateObject[0].id) { |
|||
const newState = objToBase64(this.stateObject); |
|||
this.updateStateParam(newState); |
|||
} |
|||
} |
|||
|
|||
private getStateObjById(id: string): StateObject { |
|||
return this.stateObject.find((stateObj) => stateObj.id === id); |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2019 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. |
|||
|
|||
--> |
|||
|
|||
<div class="entity-state-controller" fxLayout="row" fxLayoutAlign="start center"> |
|||
<div *ngIf="!isMobile || stateObject.length === 1" fxLayout="row" fxLayoutAlign="start center"> |
|||
<span *ngFor="let state of stateObject; index as i; last as isLast" class="state-entry" [ngStyle]="{fontWeight: isLast ? 'bold' : 'normal', |
|||
cursor: isLast ? 'default' : 'pointer'}" (click)="navigatePrevState(i)"> |
|||
{{getStateName(i)}} |
|||
<span class='state-divider' [fxHide]="isLast"> > </span> |
|||
</span> |
|||
</div> |
|||
<mat-select *ngIf="isMobile && stateObject.length > 1" |
|||
[(ngModel)]="selectedStateIndex" (ngModelChange)="selectedStateIndexChanged()"> |
|||
<mat-option *ngFor="let state of stateObject; index as i" [value]="i"> |
|||
{{getStateName(i)}} |
|||
</mat-option> |
|||
</mat-select> |
|||
</div> |
|||
|
|||
|
|||
|
|||
@ -0,0 +1,45 @@ |
|||
/** |
|||
* Copyright © 2016-2019 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. |
|||
*/ |
|||
:host { |
|||
.entity-state-controller { |
|||
.state-divider { |
|||
padding-right: 15px; |
|||
padding-left: 15px; |
|||
overflow: hidden; |
|||
font-size: 18px; |
|||
text-overflow: ellipsis; |
|||
white-space: nowrap; |
|||
pointer-events: none; |
|||
} |
|||
|
|||
.state-entry { |
|||
overflow: hidden; |
|||
font-size: 18px; |
|||
text-overflow: ellipsis; |
|||
white-space: nowrap; |
|||
outline: none; |
|||
} |
|||
|
|||
mat-select { |
|||
margin: 0; |
|||
|
|||
.mat-select-value-text { |
|||
font-size: 18px; |
|||
font-weight: 700; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,316 @@ |
|||
///
|
|||
/// Copyright © 2016-2019 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.
|
|||
///
|
|||
|
|||
import { |
|||
Component, |
|||
OnInit, |
|||
ViewEncapsulation, |
|||
Input, |
|||
OnDestroy, |
|||
OnChanges, |
|||
SimpleChanges, |
|||
NgZone |
|||
} from '@angular/core'; |
|||
import { IStateController, StateParams, StateObject } from '@core/api/widget-api.models'; |
|||
import { ActivatedRoute, Router } from '@angular/router'; |
|||
import { Observable, Subscription, of } from 'rxjs'; |
|||
import { IDashboardController } from '@home/pages/dashboard/dashboard-page.models'; |
|||
import { DashboardState } from '@shared/models/dashboard.models'; |
|||
import { IStateControllerComponent, StateControllerState } from './state-controller.models'; |
|||
import { StateControllerComponent } from './state-controller.component'; |
|||
import { StatesControllerService } from '@home/pages/dashboard/states/states-controller.service'; |
|||
import { EntityId } from '@app/shared/models/id/entity-id'; |
|||
import { UtilsService } from '@core/services/utils.service'; |
|||
import { base64toObj, objToBase64 } from '@app/core/utils'; |
|||
import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; |
|||
import { EntityService } from '@core/http/entity.service'; |
|||
import { EntityType } from '@shared/models/entity-type.models'; |
|||
import { map } from 'rxjs/operators'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-entity-state-controller', |
|||
templateUrl: './entity-state-controller.component.html', |
|||
styleUrls: ['./entity-state-controller.component.scss'] |
|||
}) |
|||
export class EntityStateControllerComponent extends StateControllerComponent implements OnInit, OnDestroy { |
|||
|
|||
private selectedStateIndex = -1; |
|||
|
|||
constructor(protected router: Router, |
|||
protected route: ActivatedRoute, |
|||
protected statesControllerService: StatesControllerService, |
|||
private utils: UtilsService, |
|||
private entityService: EntityService, |
|||
private dashboardUtils: DashboardUtilsService) { |
|||
super(router, route, statesControllerService); |
|||
} |
|||
|
|||
ngOnInit(): void { |
|||
super.ngOnInit(); |
|||
} |
|||
|
|||
ngOnDestroy(): void { |
|||
super.ngOnDestroy(); |
|||
} |
|||
|
|||
protected init() { |
|||
if (this.preservedState) { |
|||
this.stateObject = this.preservedState; |
|||
this.selectedStateIndex = this.stateObject.length - 1; |
|||
setTimeout(() => { |
|||
this.gotoState(this.stateObject[this.stateObject.length - 1].id, true); |
|||
}, 1); |
|||
} else { |
|||
const initialState = this.currentState; |
|||
this.stateObject = this.parseState(initialState); |
|||
this.selectedStateIndex = this.stateObject.length - 1; |
|||
setTimeout(() => { |
|||
this.gotoState(this.stateObject[this.stateObject.length - 1].id, false); |
|||
}, 1); |
|||
} |
|||
} |
|||
|
|||
protected onMobileChanged() { |
|||
} |
|||
|
|||
protected onStateIdChanged() { |
|||
} |
|||
|
|||
protected onStatesChanged() { |
|||
} |
|||
|
|||
protected onStateChanged() { |
|||
this.stateObject = this.parseState(this.currentState); |
|||
this.selectedStateIndex = this.stateObject.length - 1; |
|||
this.gotoState(this.stateObject[this.stateObject.length - 1].id, true); |
|||
} |
|||
|
|||
protected stateControllerId(): string { |
|||
return 'entity'; |
|||
} |
|||
|
|||
public getStateParams(): StateParams { |
|||
if (this.stateObject && this.stateObject.length) { |
|||
return this.stateObject[this.stateObject.length - 1].params; |
|||
} else { |
|||
return {}; |
|||
} |
|||
} |
|||
|
|||
public openState(id: string, params?: StateParams, openRightLayout?: boolean): void { |
|||
if (this.states && this.states[id]) { |
|||
this.resolveEntity(params).subscribe( |
|||
(entityName) => { |
|||
params.entityName = entityName; |
|||
const newState: StateObject = { |
|||
id, |
|||
params |
|||
}; |
|||
this.stateObject.push(newState); |
|||
this.selectedStateIndex = this.stateObject.length - 1; |
|||
this.gotoState(this.stateObject[this.stateObject.length - 1].id, true, openRightLayout); |
|||
} |
|||
); |
|||
} |
|||
} |
|||
|
|||
public updateState(id: string, params?: StateParams, openRightLayout?: boolean): void { |
|||
if (!id) { |
|||
id = this.getStateId(); |
|||
} |
|||
if (this.states && this.states[id]) { |
|||
this.resolveEntity(params).subscribe( |
|||
(entityName) => { |
|||
params.entityName = entityName; |
|||
const newState: StateObject = { |
|||
id, |
|||
params |
|||
}; |
|||
this.stateObject[this.stateObject.length - 1] = newState; |
|||
this.gotoState(this.stateObject[this.stateObject.length - 1].id, true, openRightLayout); |
|||
} |
|||
); |
|||
} |
|||
} |
|||
|
|||
public getEntityId(entityParamName: string): EntityId { |
|||
const stateParams = this.getStateParams(); |
|||
if (!entityParamName || !entityParamName.length) { |
|||
return stateParams.entityId; |
|||
} else if (stateParams[entityParamName]) { |
|||
return stateParams[entityParamName].entityId; |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
public getStateId(): string { |
|||
if (this.stateObject && this.stateObject.length) { |
|||
return this.stateObject[this.stateObject.length - 1].id; |
|||
} else { |
|||
return ''; |
|||
} |
|||
} |
|||
|
|||
public getStateIdAtIndex(index: number): string { |
|||
if (this.stateObject && this.stateObject[index]) { |
|||
return this.stateObject[index].id; |
|||
} else { |
|||
return ''; |
|||
} |
|||
} |
|||
|
|||
public getStateIndex(): number { |
|||
if (this.stateObject && this.stateObject.length) { |
|||
return this.stateObject.length - 1; |
|||
} else { |
|||
return -1; |
|||
} |
|||
} |
|||
|
|||
public getStateParamsByStateId(stateId: string): StateParams { |
|||
const stateObj = this.getStateObjById(stateId); |
|||
if (stateObj) { |
|||
return stateObj.params; |
|||
} else { |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
public navigatePrevState(index: number): void { |
|||
if (index < this.stateObject.length - 1) { |
|||
this.stateObject.splice(index + 1, this.stateObject.length - index - 1); |
|||
this.selectedStateIndex = this.stateObject.length - 1; |
|||
this.gotoState(this.stateObject[this.stateObject.length - 1].id, true); |
|||
} |
|||
} |
|||
|
|||
public resetState(): void { |
|||
const rootStateId = this.dashboardUtils.getRootStateId(this.states); |
|||
this.stateObject = [ { id: rootStateId, params: {} } ]; |
|||
this.gotoState(rootStateId, true); |
|||
} |
|||
|
|||
public getStateName(index: number): string { |
|||
let result = ''; |
|||
if (this.stateObject[index]) { |
|||
let stateName = this.states[this.stateObject[index].id].name; |
|||
stateName = this.utils.customTranslation(stateName, stateName); |
|||
const params = this.stateObject[index].params; |
|||
const entityName = params && params.entityName ? params.entityName : ''; |
|||
result = this.utils.insertVariable(stateName, 'entityName', entityName); |
|||
for (const prop of Object.keys(params)) { |
|||
if (params[prop] && params[prop].entityName) { |
|||
result = this.utils.insertVariable(result, prop + ':entityName', params[prop].entityName); |
|||
} |
|||
} |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
public selectedStateIndexChanged() { |
|||
this.navigatePrevState(this.selectedStateIndex); |
|||
} |
|||
|
|||
private parseState(stateBase64: string): StateControllerState { |
|||
let result: StateControllerState; |
|||
if (stateBase64) { |
|||
try { |
|||
result = base64toObj(stateBase64); |
|||
} catch (e) { |
|||
result = [ { id: null, params: {} } ]; |
|||
} |
|||
} |
|||
if (!result) { |
|||
result = []; |
|||
} |
|||
if (!result.length) { |
|||
result[0] = { id: null, params: {} }; |
|||
} |
|||
const rootStateId = this.dashboardUtils.getRootStateId(this.states); |
|||
if (!result[0].id) { |
|||
result[0].id = rootStateId; |
|||
} |
|||
if (!this.states[result[0].id]) { |
|||
result[0].id = rootStateId; |
|||
} |
|||
let i = result.length; |
|||
while (i--) { |
|||
if (!result[i].id || !this.states[result[i].id]) { |
|||
result.splice(i, 1); |
|||
} |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
private gotoState(stateId: string, update: boolean, openRightLayout?: boolean) { |
|||
this.dashboardCtrl.openDashboardState(stateId, openRightLayout); |
|||
if (update) { |
|||
this.updateLocation(); |
|||
} |
|||
} |
|||
|
|||
private updateLocation() { |
|||
if (this.stateObject[this.stateObject.length - 1].id) { |
|||
let newState; |
|||
if (this.isDefaultState()) { |
|||
newState = null; |
|||
} else { |
|||
newState = objToBase64(this.stateObject); |
|||
} |
|||
this.updateStateParam(newState); |
|||
} |
|||
} |
|||
|
|||
private isDefaultState(): boolean { |
|||
if (this.stateObject.length === 1) { |
|||
const state = this.stateObject[0]; |
|||
const rootStateId = this.dashboardUtils.getRootStateId(this.states); |
|||
if (state.id === rootStateId && (!state.params || this.isEmpty(state.params))) { |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
private isEmpty(obj: any): boolean { |
|||
for (const key of Object.keys(obj)) { |
|||
return !Object.prototype.hasOwnProperty.call(obj, key); |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
private resolveEntity(params: StateParams): Observable<string> { |
|||
if (params && params.targetEntityParamName) { |
|||
params = params[params.targetEntityParamName]; |
|||
} |
|||
if (params && params.entityId && params.entityId.id && params.entityId.entityType) { |
|||
if (params.entityName && params.entityName.length) { |
|||
return of(params.entityName); |
|||
} else { |
|||
return this.entityService.getEntity(params.entityId.entityType as EntityType, |
|||
params.entityId.id, true, true).pipe( |
|||
map((entity) => entity.name) |
|||
); |
|||
} |
|||
} else { |
|||
return of(''); |
|||
} |
|||
} |
|||
|
|||
private getStateObjById(id: string): StateObject { |
|||
return this.stateObject.find((stateObj) => stateObj.id === id); |
|||
} |
|||
} |
|||
@ -0,0 +1,173 @@ |
|||
///
|
|||
/// Copyright © 2016-2019 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.
|
|||
///
|
|||
|
|||
import { IStateControllerComponent, StateControllerState } from '@home/pages/dashboard/states/state-controller.models'; |
|||
import { IDashboardController } from '../dashboard-page.models'; |
|||
import { DashboardState } from '@app/shared/models/dashboard.models'; |
|||
import { Subscription } from 'rxjs'; |
|||
import { OnDestroy, OnInit } from '@angular/core'; |
|||
import { ActivatedRoute, Router, Params } from '@angular/router'; |
|||
import { StatesControllerService } from '@home/pages/dashboard/states/states-controller.service'; |
|||
import { EntityId } from '@app/shared/models/id/entity-id'; |
|||
import { StateParams } from '@app/core/api/widget-api.models'; |
|||
|
|||
export abstract class StateControllerComponent implements IStateControllerComponent, OnInit, OnDestroy { |
|||
|
|||
stateObject: StateControllerState = []; |
|||
dashboardCtrl: IDashboardController; |
|||
preservedState: any; |
|||
|
|||
isMobileValue: boolean; |
|||
set isMobile(val: boolean) { |
|||
if (this.isMobileValue !== val) { |
|||
this.isMobileValue = val; |
|||
if (this.inited) { |
|||
this.onMobileChanged(); |
|||
} |
|||
} |
|||
} |
|||
get isMobile(): boolean { |
|||
return this.isMobileValue; |
|||
} |
|||
|
|||
stateValue: string; |
|||
set state(val: string) { |
|||
if (this.stateValue !== val) { |
|||
this.stateValue = val; |
|||
if (this.inited) { |
|||
this.onStateIdChanged(); |
|||
} |
|||
} |
|||
} |
|||
get state(): string { |
|||
return this.stateValue; |
|||
} |
|||
|
|||
dashboardIdValue: string; |
|||
set dashboardId(val: string) { |
|||
if (this.dashboardIdValue !== val) { |
|||
this.dashboardIdValue = val; |
|||
if (this.inited) { |
|||
this.init(); |
|||
} |
|||
} |
|||
} |
|||
get dashboardId(): string { |
|||
return this.dashboardIdValue; |
|||
} |
|||
|
|||
statesValue: { [id: string]: DashboardState }; |
|||
set states(val: { [id: string]: DashboardState }) { |
|||
if (this.statesValue !== val) { |
|||
this.statesValue = val; |
|||
if (this.inited) { |
|||
this.onStatesChanged(); |
|||
} |
|||
} |
|||
} |
|||
get states(): { [id: string]: DashboardState } { |
|||
return this.statesValue; |
|||
} |
|||
|
|||
currentState: string; |
|||
|
|||
private rxSubscriptions = new Array<Subscription>(); |
|||
|
|||
private inited = false; |
|||
|
|||
constructor(protected router: Router, |
|||
protected route: ActivatedRoute, |
|||
protected statesControllerService: StatesControllerService) { |
|||
} |
|||
|
|||
ngOnInit(): void { |
|||
this.rxSubscriptions.push(this.route.queryParamMap.subscribe((paramMap) => { |
|||
const newState = paramMap.get('state'); |
|||
if (this.currentState !== newState) { |
|||
this.currentState = newState; |
|||
if (this.inited) { |
|||
this.onStateChanged(); |
|||
} |
|||
} |
|||
})); |
|||
this.init(); |
|||
this.inited = true; |
|||
} |
|||
|
|||
ngOnDestroy(): void { |
|||
this.rxSubscriptions.forEach((subscription) => { |
|||
subscription.unsubscribe(); |
|||
}); |
|||
this.rxSubscriptions.length = 0; |
|||
} |
|||
|
|||
protected updateStateParam(newState: string) { |
|||
this.currentState = newState; |
|||
const queryParams: Params = { state: this.currentState }; |
|||
this.router.navigate( |
|||
[], |
|||
{ |
|||
relativeTo: this.route, |
|||
queryParams, |
|||
queryParamsHandling: 'merge', |
|||
}); |
|||
} |
|||
|
|||
public openRightLayout(): void { |
|||
this.dashboardCtrl.openRightLayout(); |
|||
} |
|||
|
|||
public preserveState() { |
|||
this.statesControllerService.preserveStateControllerState(this.stateControllerId(), this.stateObject); |
|||
} |
|||
|
|||
public cleanupPreservedStates() { |
|||
this.statesControllerService.cleanupPreservedStates(); |
|||
} |
|||
|
|||
protected abstract init(); |
|||
|
|||
protected abstract onMobileChanged(); |
|||
|
|||
protected abstract onStateIdChanged(); |
|||
|
|||
protected abstract onStatesChanged(); |
|||
|
|||
protected abstract onStateChanged(); |
|||
|
|||
protected abstract stateControllerId(): string; |
|||
|
|||
public abstract getEntityId(entityParamName: string): EntityId; |
|||
|
|||
public abstract getStateId(): string; |
|||
|
|||
public abstract getStateIdAtIndex(index: number): string; |
|||
|
|||
public abstract getStateIndex(): number; |
|||
|
|||
public abstract getStateParams(): StateParams; |
|||
|
|||
public abstract getStateParamsByStateId(stateId: string): StateParams; |
|||
|
|||
public abstract navigatePrevState(index: number): void; |
|||
|
|||
public abstract openState(id: string, params?: StateParams, openRightLayout?: boolean): void; |
|||
|
|||
public abstract resetState(): void; |
|||
|
|||
public abstract updateState(id?: string, params?: StateParams, openRightLayout?: boolean): void; |
|||
|
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
///
|
|||
/// Copyright © 2016-2019 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.
|
|||
///
|
|||
|
|||
import { IStateController, StateObject } from '@core/api/widget-api.models'; |
|||
import { IDashboardController } from '@home/pages/dashboard/dashboard-page.models'; |
|||
import { DashboardState } from '@shared/models/dashboard.models'; |
|||
|
|||
export declare type StateControllerState = StateObject[]; |
|||
|
|||
export interface IStateControllerComponent extends IStateController { |
|||
state: string; |
|||
isMobile: boolean; |
|||
dashboardCtrl: IDashboardController; |
|||
states: {[id: string]: DashboardState }; |
|||
dashboardId: string; |
|||
preservedState: any; |
|||
} |
|||
@ -0,0 +1,122 @@ |
|||
///
|
|||
/// Copyright © 2016-2019 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.
|
|||
///
|
|||
|
|||
import { |
|||
ComponentRef, |
|||
Directive, |
|||
ElementRef, |
|||
Input, |
|||
OnChanges, |
|||
OnInit, |
|||
OnDestroy, |
|||
SimpleChanges, |
|||
ViewContainerRef, |
|||
ChangeDetectorRef |
|||
} from '@angular/core'; |
|||
import { DashboardPageComponent } from '@home/pages/dashboard/dashboard-page.component'; |
|||
import { DashboardState } from '@shared/models/dashboard.models'; |
|||
import { IDashboardController } from '@home/pages/dashboard/dashboard-page.models'; |
|||
import { StatesControllerService } from '@home/pages/dashboard/states/states-controller.service'; |
|||
import { IStateController } from '@core/api/widget-api.models'; |
|||
import { IStateControllerComponent } from '@home/pages/dashboard/states/state-controller.models'; |
|||
|
|||
@Directive({ |
|||
selector: 'tb-states-component' |
|||
}) |
|||
export class StatesComponentDirective implements OnInit, OnDestroy, OnChanges { |
|||
|
|||
@Input() |
|||
statesControllerId: string; |
|||
|
|||
@Input() |
|||
dashboardCtrl: IDashboardController; |
|||
|
|||
@Input() |
|||
dashboardId: string; |
|||
|
|||
@Input() |
|||
states: {[id: string]: DashboardState }; |
|||
|
|||
@Input() |
|||
state: string; |
|||
|
|||
@Input() |
|||
isMobile: boolean; |
|||
|
|||
stateControllerComponentRef: ComponentRef<IStateControllerComponent>; |
|||
stateControllerComponent: IStateControllerComponent; |
|||
|
|||
constructor(private viewContainerRef: ViewContainerRef, |
|||
private statesControllerService: StatesControllerService) { |
|||
} |
|||
|
|||
ngOnInit(): void { |
|||
this.init(); |
|||
} |
|||
|
|||
ngOnDestroy(): void { |
|||
this.destroy(); |
|||
} |
|||
|
|||
ngOnChanges(changes: SimpleChanges): void { |
|||
for (const propName of Object.keys(changes)) { |
|||
const change = changes[propName]; |
|||
if (!change.firstChange && change.currentValue !== change.previousValue) { |
|||
if (propName === 'statesControllerId') { |
|||
this.reInit(); |
|||
} else if (propName === 'states') { |
|||
this.stateControllerComponent.states = this.states; |
|||
} else if (propName === 'dashboardId') { |
|||
this.stateControllerComponent.dashboardId = this.dashboardId; |
|||
} else if (propName === 'isMobile') { |
|||
this.stateControllerComponent.isMobile = this.isMobile; |
|||
} else if (propName === 'state') { |
|||
this.stateControllerComponent.state = this.state; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
private reInit() { |
|||
this.destroy(); |
|||
this.init(); |
|||
} |
|||
|
|||
private init() { |
|||
this.viewContainerRef.clear(); |
|||
let stateControllerData = this.statesControllerService.getStateController(this.statesControllerId); |
|||
if (!stateControllerData) { |
|||
stateControllerData = this.statesControllerService.getStateController('default'); |
|||
} |
|||
const preservedState = this.statesControllerService.withdrawStateControllerState(this.statesControllerId); |
|||
const stateControllerFactory = stateControllerData.factory; |
|||
this.stateControllerComponentRef = this.viewContainerRef.createComponent(stateControllerFactory); |
|||
this.stateControllerComponent = this.stateControllerComponentRef.instance; |
|||
this.dashboardCtrl.dashboardCtx.stateController = this.stateControllerComponent; |
|||
this.stateControllerComponent.preservedState = preservedState; |
|||
this.stateControllerComponent.dashboardCtrl = this.dashboardCtrl; |
|||
this.stateControllerComponent.state = this.state; |
|||
this.stateControllerComponent.isMobile = this.isMobile; |
|||
this.stateControllerComponent.states = this.states; |
|||
this.stateControllerComponent.dashboardId = this.dashboardId; |
|||
} |
|||
|
|||
private destroy() { |
|||
if (this.stateControllerComponentRef) { |
|||
this.stateControllerComponentRef.destroy(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,56 @@ |
|||
///
|
|||
/// Copyright © 2016-2019 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.
|
|||
///
|
|||
|
|||
import { NgModule } from '@angular/core'; |
|||
import { CommonModule } from '@angular/common'; |
|||
import { SharedModule } from '@shared/shared.module'; |
|||
import { HomeComponentsModule } from '@modules/home/components/home-components.module'; |
|||
import { StatesControllerService } from './states-controller.service'; |
|||
import { EntityStateControllerComponent } from './entity-state-controller.component'; |
|||
import { StatesComponentDirective } from './states-component.directive'; |
|||
import { HomeDialogsModule } from '@app/modules/home/dialogs/home-dialogs.module'; |
|||
import { DefaultStateControllerComponent } from '@home/pages/dashboard/states/default-state-controller.component'; |
|||
|
|||
@NgModule({ |
|||
entryComponents: [ |
|||
DefaultStateControllerComponent, |
|||
EntityStateControllerComponent |
|||
], |
|||
declarations: [ |
|||
StatesComponentDirective, |
|||
DefaultStateControllerComponent, |
|||
EntityStateControllerComponent |
|||
], |
|||
imports: [ |
|||
CommonModule, |
|||
SharedModule, |
|||
HomeComponentsModule, |
|||
HomeDialogsModule |
|||
], |
|||
exports: [ |
|||
StatesComponentDirective |
|||
], |
|||
providers: [ |
|||
StatesControllerService |
|||
] |
|||
}) |
|||
export class StatesControllerModule { |
|||
|
|||
constructor(private statesControllerService: StatesControllerService) { |
|||
this.statesControllerService.registerStatesController('default', DefaultStateControllerComponent); |
|||
this.statesControllerService.registerStatesController('entity', EntityStateControllerComponent); |
|||
} |
|||
} |
|||
@ -0,0 +1,64 @@ |
|||
///
|
|||
/// Copyright © 2016-2019 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.
|
|||
///
|
|||
|
|||
import { ComponentFactory, ComponentFactoryResolver, Injectable, Type } from '@angular/core'; |
|||
import { deepClone } from '@core/utils'; |
|||
import { IStateControllerComponent } from '@home/pages/dashboard/states/state-controller.models'; |
|||
|
|||
export interface StateControllerData { |
|||
factory: ComponentFactory<IStateControllerComponent>; |
|||
state?: any; |
|||
} |
|||
|
|||
@Injectable() |
|||
export class StatesControllerService { |
|||
|
|||
statesControllers: {[stateControllerId: string]: StateControllerData} = {}; |
|||
|
|||
constructor(private componentFactoryResolver: ComponentFactoryResolver) { |
|||
} |
|||
|
|||
public registerStatesController(stateControllerId: string, stateControllerComponent: Type<IStateControllerComponent>): void { |
|||
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(stateControllerComponent); |
|||
this.statesControllers[stateControllerId] = { |
|||
factory: componentFactory |
|||
}; |
|||
} |
|||
|
|||
public getStateControllers(): {[stateControllerId: string]: StateControllerData} { |
|||
return this.statesControllers; |
|||
} |
|||
|
|||
public getStateController(stateControllerId: string): StateControllerData { |
|||
return this.statesControllers[stateControllerId]; |
|||
} |
|||
|
|||
public preserveStateControllerState(stateControllerId: string, state: any) { |
|||
this.statesControllers[stateControllerId].state = deepClone(state); |
|||
} |
|||
|
|||
public withdrawStateControllerState(stateControllerId: string): any { |
|||
const state = this.statesControllers[stateControllerId].state; |
|||
this.statesControllers[stateControllerId].state = null; |
|||
return state; |
|||
} |
|||
|
|||
public cleanupPreservedStates() { |
|||
for (const stateControllerId of Object.keys(this.statesControllers)) { |
|||
this.statesControllers[stateControllerId].state = null; |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue