GPIO widgets
This commit is contained in:
parent
7261c75c61
commit
2807c497f0
File diff suppressed because one or more lines are too long
19
ui-ngx/package-lock.json
generated
19
ui-ngx/package-lock.json
generated
@ -3640,6 +3640,12 @@
|
|||||||
"integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=",
|
"integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/raphael": {
|
||||||
|
"version": "2.1.30",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/raphael/-/raphael-2.1.30.tgz",
|
||||||
|
"integrity": "sha1-dsvqSlVrol6xxtf6XnGsSOcvgc8=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/react": {
|
"@types/react": {
|
||||||
"version": "16.9.16",
|
"version": "16.9.16",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.16.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.16.tgz",
|
||||||
@ -6620,6 +6626,11 @@
|
|||||||
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
|
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"eve-raphael": {
|
||||||
|
"version": "0.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/eve-raphael/-/eve-raphael-0.5.0.tgz",
|
||||||
|
"integrity": "sha1-F8dUt5K+7z+maE15z1pHxjxM2jA="
|
||||||
|
},
|
||||||
"eventemitter3": {
|
"eventemitter3": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz",
|
||||||
@ -10955,6 +10966,14 @@
|
|||||||
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
|
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"raphael": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/raphael/-/raphael-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-w2yIenZAQnp257XUWGni4bLMVxpUpcIl7qgxEgDIXtmSypYtlNxfXWpOBxs7LBTps5sDwhRnrToJrMUrivqNTQ==",
|
||||||
|
"requires": {
|
||||||
|
"eve-raphael": "0.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"raw-body": {
|
"raw-body": {
|
||||||
"version": "2.4.0",
|
"version": "2.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
|
||||||
|
|||||||
@ -66,6 +66,7 @@
|
|||||||
"ngx-translate-messageformat-compiler": "^4.5.0",
|
"ngx-translate-messageformat-compiler": "^4.5.0",
|
||||||
"objectpath": "^1.2.2",
|
"objectpath": "^1.2.2",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
|
"raphael": "^2.3.0",
|
||||||
"rc-select": "^9.2.1",
|
"rc-select": "^9.2.1",
|
||||||
"react": "^16.12.0",
|
"react": "^16.12.0",
|
||||||
"react-ace": "^8.0.0",
|
"react-ace": "^8.0.0",
|
||||||
@ -97,6 +98,7 @@
|
|||||||
"@types/js-beautify": "^1.8.1",
|
"@types/js-beautify": "^1.8.1",
|
||||||
"@types/jstree": "^3.3.39",
|
"@types/jstree": "^3.3.39",
|
||||||
"@types/node": "~12.12.17",
|
"@types/node": "~12.12.17",
|
||||||
|
"@types/raphael": "^2.1.30",
|
||||||
"@types/react": "^16.9.16",
|
"@types/react": "^16.9.16",
|
||||||
"@types/react-dom": "^16.9.4",
|
"@types/react-dom": "^16.9.4",
|
||||||
"@types/tinycolor2": "^1.4.2",
|
"@types/tinycolor2": "^1.4.2",
|
||||||
|
|||||||
@ -552,8 +552,9 @@ export class WidgetSubscription implements IWidgetSubscription {
|
|||||||
}, 500);
|
}, 500);
|
||||||
} else {
|
} else {
|
||||||
this.executingSubjects.push(rpcSubject);
|
this.executingSubjects.push(rpcSubject);
|
||||||
const targetSendFunction = oneWayElseTwoWay ? this.ctx.deviceService.sendOneWayRpcCommand : this.ctx.deviceService.sendTwoWayRpcCommand;
|
(oneWayElseTwoWay ? this.ctx.deviceService.sendOneWayRpcCommand(this.targetDeviceId, requestBody) :
|
||||||
targetSendFunction(this.targetDeviceId, requestBody).subscribe((responseBody) => {
|
this.ctx.deviceService.sendTwoWayRpcCommand(this.targetDeviceId, requestBody))
|
||||||
|
.subscribe((responseBody) => {
|
||||||
this.rpcRejection = null;
|
this.rpcRejection = null;
|
||||||
this.rpcErrorText = null;
|
this.rpcErrorText = null;
|
||||||
const index = this.executingSubjects.indexOf(rpcSubject);
|
const index = this.executingSubjects.indexOf(rpcSubject);
|
||||||
|
|||||||
@ -47,7 +47,8 @@ export class GlobalHttpInterceptor implements HttpInterceptor {
|
|||||||
private AUTH_HEADER_NAME = 'X-Authorization';
|
private AUTH_HEADER_NAME = 'X-Authorization';
|
||||||
|
|
||||||
private internalUrlPrefixes = [
|
private internalUrlPrefixes = [
|
||||||
'/api/auth/token'
|
'/api/auth/token',
|
||||||
|
'/api/plugins/rpc'
|
||||||
];
|
];
|
||||||
|
|
||||||
private activeRequests = 0;
|
private activeRequests = 0;
|
||||||
@ -125,8 +126,8 @@ export class GlobalHttpInterceptor implements HttpInterceptor {
|
|||||||
const ignoreErrors = config.ignoreErrors;
|
const ignoreErrors = config.ignoreErrors;
|
||||||
const resendRequest = config.resendRequest;
|
const resendRequest = config.resendRequest;
|
||||||
const errorCode = errorResponse.error ? errorResponse.error.errorCode : null;
|
const errorCode = errorResponse.error ? errorResponse.error.errorCode : null;
|
||||||
if (errorResponse.error.refreshTokenPending || errorResponse.status === 401) {
|
if (errorResponse.error && errorResponse.error.refreshTokenPending || errorResponse.status === 401) {
|
||||||
if (errorResponse.error.refreshTokenPending || errorCode && errorCode === Constants.serverErrorCode.jwtTokenExpired) {
|
if (errorResponse.error && errorResponse.error.refreshTokenPending || errorCode && errorCode === Constants.serverErrorCode.jwtTokenExpired) {
|
||||||
return this.refreshTokenAndRetry(req, next);
|
return this.refreshTokenAndRetry(req, next);
|
||||||
} else if (errorCode !== Constants.serverErrorCode.credentialsExpired) {
|
} else if (errorCode !== Constants.serverErrorCode.credentialsExpired) {
|
||||||
unhandled = true;
|
unhandled = true;
|
||||||
|
|||||||
@ -201,7 +201,7 @@ export class WidgetComponentService {
|
|||||||
}
|
}
|
||||||
if (widgetControllerDescriptor) {
|
if (widgetControllerDescriptor) {
|
||||||
const widgetNamespace = `widget-type-${(isSystem ? 'sys-' : '')}${bundleAlias}-${widgetInfo.alias}`;
|
const widgetNamespace = `widget-type-${(isSystem ? 'sys-' : '')}${bundleAlias}-${widgetInfo.alias}`;
|
||||||
this.loadWidgetResources(widgetInfo, widgetNamespace, [WidgetComponentsModule]).subscribe(
|
this.loadWidgetResources(widgetInfo, widgetNamespace, [SharedModule, WidgetComponentsModule]).subscribe(
|
||||||
() => {
|
() => {
|
||||||
if (widgetControllerDescriptor.settingsSchema) {
|
if (widgetControllerDescriptor.settingsSchema) {
|
||||||
widgetInfo.typeSettingsSchema = widgetControllerDescriptor.settingsSchema;
|
widgetInfo.typeSettingsSchema = widgetControllerDescriptor.settingsSchema;
|
||||||
|
|||||||
@ -27,18 +27,19 @@ import {
|
|||||||
NgZone,
|
NgZone,
|
||||||
OnChanges,
|
OnChanges,
|
||||||
OnDestroy,
|
OnDestroy,
|
||||||
OnInit, ReflectiveInjector,
|
OnInit,
|
||||||
SimpleChanges, Type,
|
SimpleChanges,
|
||||||
|
Type,
|
||||||
ViewChild,
|
ViewChild,
|
||||||
ViewContainerRef,
|
ViewContainerRef,
|
||||||
ViewEncapsulation
|
ViewEncapsulation
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { DashboardWidget, IDashboardComponent } from '@home/models/dashboard-component.models';
|
import { DashboardWidget } from '@home/models/dashboard-component.models';
|
||||||
import {
|
import {
|
||||||
Datasource,
|
Datasource,
|
||||||
|
defaultLegendConfig,
|
||||||
LegendConfig,
|
LegendConfig,
|
||||||
LegendData,
|
LegendData,
|
||||||
LegendDirection,
|
|
||||||
LegendPosition,
|
LegendPosition,
|
||||||
Widget,
|
Widget,
|
||||||
WidgetActionDescriptor,
|
WidgetActionDescriptor,
|
||||||
@ -46,8 +47,7 @@ import {
|
|||||||
WidgetActionType,
|
WidgetActionType,
|
||||||
WidgetResource,
|
WidgetResource,
|
||||||
widgetType,
|
widgetType,
|
||||||
WidgetTypeParameters,
|
WidgetTypeParameters
|
||||||
defaultLegendConfig
|
|
||||||
} from '@shared/models/widget.models';
|
} from '@shared/models/widget.models';
|
||||||
import { PageComponent } from '@shared/components/page.component';
|
import { PageComponent } from '@shared/components/page.component';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
@ -101,6 +101,7 @@ ServicesMap.set('assetService', AssetService);
|
|||||||
ServicesMap.set('dialogs', DialogService);
|
ServicesMap.set('dialogs', DialogService);
|
||||||
ServicesMap.set('customDialog', CustomDialogService);
|
ServicesMap.set('customDialog', CustomDialogService);
|
||||||
ServicesMap.set('date', DatePipe);
|
ServicesMap.set('date', DatePipe);
|
||||||
|
ServicesMap.set('utils', UtilsService);
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-widget',
|
selector: 'tb-widget',
|
||||||
@ -252,6 +253,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI
|
|||||||
|
|
||||||
this.widgetContext = this.dashboardWidget.widgetContext;
|
this.widgetContext = this.dashboardWidget.widgetContext;
|
||||||
this.widgetContext.changeDetector = this.cd;
|
this.widgetContext.changeDetector = this.cd;
|
||||||
|
this.widgetContext.ngZone = this.ngZone;
|
||||||
this.widgetContext.servicesMap = ServicesMap;
|
this.widgetContext.servicesMap = ServicesMap;
|
||||||
this.widgetContext.isEdit = this.isEdit;
|
this.widgetContext.isEdit = this.isEdit;
|
||||||
this.widgetContext.isMobile = this.isMobile;
|
this.widgetContext.isMobile = this.isMobile;
|
||||||
@ -533,7 +535,6 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI
|
|||||||
|
|
||||||
private reInitImpl() {
|
private reInitImpl() {
|
||||||
this.onDestroy();
|
this.onDestroy();
|
||||||
this.configureDynamicWidgetComponent();
|
|
||||||
if (!this.typeParameters.useCustomDatasources) {
|
if (!this.typeParameters.useCustomDatasources) {
|
||||||
this.createDefaultSubscription().subscribe(
|
this.createDefaultSubscription().subscribe(
|
||||||
() => {
|
() => {
|
||||||
@ -541,6 +542,8 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI
|
|||||||
this.onDestroy();
|
this.onDestroy();
|
||||||
} else {
|
} else {
|
||||||
this.subscriptionInited = true;
|
this.subscriptionInited = true;
|
||||||
|
this.configureDynamicWidgetComponent();
|
||||||
|
this.cd.detectChanges();
|
||||||
this.onInit();
|
this.onInit();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -555,6 +558,8 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
this.subscriptionInited = true;
|
this.subscriptionInited = true;
|
||||||
|
this.configureDynamicWidgetComponent();
|
||||||
|
this.cd.detectChanges();
|
||||||
this.onInit();
|
this.onInit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -826,6 +831,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI
|
|||||||
if (this.dynamicWidgetComponent) {
|
if (this.dynamicWidgetComponent) {
|
||||||
this.dynamicWidgetComponent.rpcEnabled = subscription.rpcEnabled;
|
this.dynamicWidgetComponent.rpcEnabled = subscription.rpcEnabled;
|
||||||
this.dynamicWidgetComponent.executingRpcRequest = subscription.executingRpcRequest;
|
this.dynamicWidgetComponent.executingRpcRequest = subscription.executingRpcRequest;
|
||||||
|
this.cd.detectChanges();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRpcSuccess: (subscription) => {
|
onRpcSuccess: (subscription) => {
|
||||||
@ -833,6 +839,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI
|
|||||||
this.dynamicWidgetComponent.executingRpcRequest = subscription.executingRpcRequest;
|
this.dynamicWidgetComponent.executingRpcRequest = subscription.executingRpcRequest;
|
||||||
this.dynamicWidgetComponent.rpcErrorText = subscription.rpcErrorText;
|
this.dynamicWidgetComponent.rpcErrorText = subscription.rpcErrorText;
|
||||||
this.dynamicWidgetComponent.rpcRejection = subscription.rpcRejection;
|
this.dynamicWidgetComponent.rpcRejection = subscription.rpcRejection;
|
||||||
|
this.cd.detectChanges();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRpcFailed: (subscription) => {
|
onRpcFailed: (subscription) => {
|
||||||
@ -840,12 +847,14 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI
|
|||||||
this.dynamicWidgetComponent.executingRpcRequest = subscription.executingRpcRequest;
|
this.dynamicWidgetComponent.executingRpcRequest = subscription.executingRpcRequest;
|
||||||
this.dynamicWidgetComponent.rpcErrorText = subscription.rpcErrorText;
|
this.dynamicWidgetComponent.rpcErrorText = subscription.rpcErrorText;
|
||||||
this.dynamicWidgetComponent.rpcRejection = subscription.rpcRejection;
|
this.dynamicWidgetComponent.rpcRejection = subscription.rpcRejection;
|
||||||
|
this.cd.detectChanges();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRpcErrorCleared: (subscription) => {
|
onRpcErrorCleared: (subscription) => {
|
||||||
if (this.dynamicWidgetComponent) {
|
if (this.dynamicWidgetComponent) {
|
||||||
this.dynamicWidgetComponent.rpcErrorText = null;
|
this.dynamicWidgetComponent.rpcErrorText = null;
|
||||||
this.dynamicWidgetComponent.rpcRejection = null;
|
this.dynamicWidgetComponent.rpcRejection = null;
|
||||||
|
this.cd.detectChanges();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -198,6 +198,8 @@ export class WidgetContext {
|
|||||||
servicesMap?: Map<string, Type<any>>;
|
servicesMap?: Map<string, Type<any>>;
|
||||||
|
|
||||||
$injector?: Injector;
|
$injector?: Injector;
|
||||||
|
|
||||||
|
ngZone?: NgZone;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IDynamicWidgetComponent {
|
export interface IDynamicWidgetComponent {
|
||||||
|
|||||||
@ -14,22 +14,11 @@
|
|||||||
/// limitations under the License.
|
/// limitations under the License.
|
||||||
///
|
///
|
||||||
|
|
||||||
import {
|
import { Component, NgZone, OnDestroy, OnInit } from '@angular/core';
|
||||||
Component,
|
import { StateObject, StateParams } from '@core/api/widget-api.models';
|
||||||
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 { 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 { DashboardState } from '@shared/models/dashboard.models';
|
||||||
import { IStateControllerComponent, StateControllerState } from './state-controller.models';
|
import { StateControllerState } from './state-controller.models';
|
||||||
import { StateControllerComponent } from './state-controller.component';
|
import { StateControllerComponent } from './state-controller.component';
|
||||||
import { StatesControllerService } from '@home/pages/dashboard/states/states-controller.service';
|
import { StatesControllerService } from '@home/pages/dashboard/states/states-controller.service';
|
||||||
import { EntityId } from '@app/shared/models/id/entity-id';
|
import { EntityId } from '@app/shared/models/id/entity-id';
|
||||||
@ -37,8 +26,6 @@ import { UtilsService } from '@core/services/utils.service';
|
|||||||
import { base64toObj, objToBase64 } from '@app/core/utils';
|
import { base64toObj, objToBase64 } from '@app/core/utils';
|
||||||
import { DashboardUtilsService } from '@core/services/dashboard-utils.service';
|
import { DashboardUtilsService } from '@core/services/dashboard-utils.service';
|
||||||
import { EntityService } from '@core/http/entity.service';
|
import { EntityService } from '@core/http/entity.service';
|
||||||
import { EntityType } from '@shared/models/entity-type.models';
|
|
||||||
import { map } from 'rxjs/operators';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-default-state-controller',
|
selector: 'tb-default-state-controller',
|
||||||
@ -49,11 +36,12 @@ export class DefaultStateControllerComponent extends StateControllerComponent im
|
|||||||
|
|
||||||
constructor(protected router: Router,
|
constructor(protected router: Router,
|
||||||
protected route: ActivatedRoute,
|
protected route: ActivatedRoute,
|
||||||
|
protected ngZone: NgZone,
|
||||||
protected statesControllerService: StatesControllerService,
|
protected statesControllerService: StatesControllerService,
|
||||||
private utils: UtilsService,
|
private utils: UtilsService,
|
||||||
private entityService: EntityService,
|
private entityService: EntityService,
|
||||||
private dashboardUtils: DashboardUtilsService) {
|
private dashboardUtils: DashboardUtilsService) {
|
||||||
super(router, route, statesControllerService);
|
super(router, route, ngZone, statesControllerService);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
|||||||
@ -14,22 +14,11 @@
|
|||||||
/// limitations under the License.
|
/// limitations under the License.
|
||||||
///
|
///
|
||||||
|
|
||||||
import {
|
import { Component, NgZone, OnDestroy, OnInit } from '@angular/core';
|
||||||
Component,
|
import { StateObject, StateParams } from '@core/api/widget-api.models';
|
||||||
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 { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { Observable, Subscription, of } from 'rxjs';
|
import { Observable, of } from 'rxjs';
|
||||||
import { IDashboardController } from '@home/pages/dashboard/dashboard-page.models';
|
import { StateControllerState } from './state-controller.models';
|
||||||
import { DashboardState } from '@shared/models/dashboard.models';
|
|
||||||
import { IStateControllerComponent, StateControllerState } from './state-controller.models';
|
|
||||||
import { StateControllerComponent } from './state-controller.component';
|
import { StateControllerComponent } from './state-controller.component';
|
||||||
import { StatesControllerService } from '@home/pages/dashboard/states/states-controller.service';
|
import { StatesControllerService } from '@home/pages/dashboard/states/states-controller.service';
|
||||||
import { EntityId } from '@app/shared/models/id/entity-id';
|
import { EntityId } from '@app/shared/models/id/entity-id';
|
||||||
@ -51,11 +40,12 @@ export class EntityStateControllerComponent extends StateControllerComponent imp
|
|||||||
|
|
||||||
constructor(protected router: Router,
|
constructor(protected router: Router,
|
||||||
protected route: ActivatedRoute,
|
protected route: ActivatedRoute,
|
||||||
|
protected ngZone: NgZone,
|
||||||
protected statesControllerService: StatesControllerService,
|
protected statesControllerService: StatesControllerService,
|
||||||
private utils: UtilsService,
|
private utils: UtilsService,
|
||||||
private entityService: EntityService,
|
private entityService: EntityService,
|
||||||
private dashboardUtils: DashboardUtilsService) {
|
private dashboardUtils: DashboardUtilsService) {
|
||||||
super(router, route, statesControllerService);
|
super(router, route, ngZone, statesControllerService);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
|||||||
@ -18,7 +18,7 @@ import { IStateControllerComponent, StateControllerState } from '@home/pages/das
|
|||||||
import { IDashboardController } from '../dashboard-page.models';
|
import { IDashboardController } from '../dashboard-page.models';
|
||||||
import { DashboardState } from '@app/shared/models/dashboard.models';
|
import { DashboardState } from '@app/shared/models/dashboard.models';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { OnDestroy, OnInit } from '@angular/core';
|
import { NgZone, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { ActivatedRoute, Router, Params } from '@angular/router';
|
import { ActivatedRoute, Router, Params } from '@angular/router';
|
||||||
import { StatesControllerService } from '@home/pages/dashboard/states/states-controller.service';
|
import { StatesControllerService } from '@home/pages/dashboard/states/states-controller.service';
|
||||||
import { EntityId } from '@app/shared/models/id/entity-id';
|
import { EntityId } from '@app/shared/models/id/entity-id';
|
||||||
@ -91,6 +91,7 @@ export abstract class StateControllerComponent implements IStateControllerCompon
|
|||||||
|
|
||||||
constructor(protected router: Router,
|
constructor(protected router: Router,
|
||||||
protected route: ActivatedRoute,
|
protected route: ActivatedRoute,
|
||||||
|
protected ngZone: NgZone,
|
||||||
protected statesControllerService: StatesControllerService) {
|
protected statesControllerService: StatesControllerService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,12 +122,14 @@ export abstract class StateControllerComponent implements IStateControllerCompon
|
|||||||
protected updateStateParam(newState: string) {
|
protected updateStateParam(newState: string) {
|
||||||
this.currentState = newState;
|
this.currentState = newState;
|
||||||
const queryParams: Params = { state: this.currentState };
|
const queryParams: Params = { state: this.currentState };
|
||||||
this.router.navigate(
|
this.ngZone.run(() => {
|
||||||
[],
|
this.router.navigate(
|
||||||
{
|
[],
|
||||||
relativeTo: this.route,
|
{
|
||||||
queryParams,
|
relativeTo: this.route,
|
||||||
queryParamsHandling: 'merge',
|
queryParams,
|
||||||
|
queryParamsHandling: 'merge',
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -157,6 +157,7 @@ class ThingsboardArray extends React.Component<JsonFormFieldProps, ThingsboardAr
|
|||||||
addButton = <Button variant='contained'
|
addButton = <Button variant='contained'
|
||||||
color='primary'
|
color='primary'
|
||||||
startIcon={<AddIcon/>}
|
startIcon={<AddIcon/>}
|
||||||
|
style={{marginBottom: '8px'}}
|
||||||
onClick={this.onAppend}>{this.props.form.add || 'New'}</Button>;
|
onClick={this.onAppend}>{this.props.form.add || 'New'}</Button>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -314,7 +314,7 @@ function defaultFormDefinition(name: string, schema: any, options: DefaultsFormO
|
|||||||
const rules = defaults[stripNullType(schema.type)];
|
const rules = defaults[stripNullType(schema.type)];
|
||||||
if (rules) {
|
if (rules) {
|
||||||
let def;
|
let def;
|
||||||
rules.forEach((rule) => {
|
for (const rule of rules) {
|
||||||
def = rule(name, schema, options);
|
def = rule(name, schema, options);
|
||||||
if (def) {
|
if (def) {
|
||||||
|
|
||||||
@ -324,7 +324,7 @@ function defaultFormDefinition(name: string, schema: any, options: DefaultsFormO
|
|||||||
}
|
}
|
||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
18
ui-ngx/src/app/shared/components/led-light.component.html
Normal file
18
ui-ngx/src/app/shared/components/led-light.component.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
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 id="canvas_container" [ngStyle]="{width: size + 'px', height: size + 'px'}"></div>
|
||||||
124
ui-ngx/src/app/shared/components/led-light.component.ts
Normal file
124
ui-ngx/src/app/shared/components/led-light.component.ts
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
///
|
||||||
|
/// 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 { AfterViewInit, Component, ElementRef, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
|
||||||
|
import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
||||||
|
import Raphael from 'raphael';
|
||||||
|
import * as tinycolor_ from 'tinycolor2';
|
||||||
|
|
||||||
|
const tinycolor = tinycolor_;
|
||||||
|
|
||||||
|
interface CircleElement extends RaphaelElement {
|
||||||
|
theGlow?: RaphaelSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'tb-led-light',
|
||||||
|
templateUrl: './led-light.component.html',
|
||||||
|
styleUrls: []
|
||||||
|
})
|
||||||
|
export class LedLightComponent implements OnInit, AfterViewInit, OnChanges {
|
||||||
|
|
||||||
|
@Input() size: number;
|
||||||
|
|
||||||
|
@Input() colorOn: string;
|
||||||
|
|
||||||
|
@Input() colorOff: string;
|
||||||
|
|
||||||
|
@Input() offOpacity: string;
|
||||||
|
|
||||||
|
private enabledValue: boolean;
|
||||||
|
get enabled(): boolean {
|
||||||
|
return this.enabledValue;
|
||||||
|
}
|
||||||
|
@Input()
|
||||||
|
set enabled(value: boolean) {
|
||||||
|
this.enabledValue = coerceBooleanProperty(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private canvasSize: number;
|
||||||
|
private radius: number;
|
||||||
|
private glowSize: number;
|
||||||
|
private glowColor: string;
|
||||||
|
|
||||||
|
private paper: RaphaelPaper;
|
||||||
|
private circleElement: CircleElement;
|
||||||
|
|
||||||
|
constructor(private elementRef: ElementRef<HTMLElement>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.offOpacity = this.offOpacity || '0.4';
|
||||||
|
this.glowColor = tinycolor(this.colorOn).lighten().toHexString();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit(): void {
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
|
for (const propName of Object.keys(changes)) {
|
||||||
|
const change = changes[propName];
|
||||||
|
if (!change.firstChange && change.currentValue !== change.previousValue) {
|
||||||
|
if (propName === 'enabled') {
|
||||||
|
this.draw();
|
||||||
|
} else if (propName === 'size') {
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private update() {
|
||||||
|
this.size = this.size || 50;
|
||||||
|
this.canvasSize = this.size;
|
||||||
|
this.radius = this.canvasSize / 4;
|
||||||
|
this.glowSize = this.radius / 5;
|
||||||
|
if (this.paper) {
|
||||||
|
this.paper.remove();
|
||||||
|
}
|
||||||
|
this.paper = Raphael($('#canvas_container', this.elementRef.nativeElement)[0], this.canvasSize, this.canvasSize);
|
||||||
|
const center = this.canvasSize / 2;
|
||||||
|
this.circleElement = this.paper.circle(center, center, this.radius);
|
||||||
|
this.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
private draw() {
|
||||||
|
if (this.enabled) {
|
||||||
|
this.circleElement.attr('fill', this.colorOn);
|
||||||
|
this.circleElement.attr('stroke', this.colorOn);
|
||||||
|
this.circleElement.attr('opacity', '1');
|
||||||
|
if (this.circleElement.theGlow) {
|
||||||
|
this.circleElement.theGlow.remove();
|
||||||
|
}
|
||||||
|
this.circleElement.theGlow = this.circleElement.glow(
|
||||||
|
{
|
||||||
|
color: this.glowColor,
|
||||||
|
width: this.radius + this.glowSize,
|
||||||
|
opacity: 0.8,
|
||||||
|
fill: true
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (this.circleElement.theGlow) {
|
||||||
|
this.circleElement.theGlow.remove();
|
||||||
|
}
|
||||||
|
this.circleElement.attr('fill', this.colorOff);
|
||||||
|
this.circleElement.attr('stroke', this.colorOff);
|
||||||
|
this.circleElement.attr('opacity', this.offOpacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -121,6 +121,7 @@ import { KeyValMapComponent } from './components/kv-map.component';
|
|||||||
import { TbCheatSheetComponent } from '@shared/components/cheatsheet.component';
|
import { TbCheatSheetComponent } from '@shared/components/cheatsheet.component';
|
||||||
import { TbHotkeysDirective } from '@shared/components/hotkeys.directive';
|
import { TbHotkeysDirective } from '@shared/components/hotkeys.directive';
|
||||||
import { NavTreeComponent } from '@shared/components/nav-tree.component';
|
import { NavTreeComponent } from '@shared/components/nav-tree.component';
|
||||||
|
import { LedLightComponent } from '@shared/components/led-light.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
providers: [
|
providers: [
|
||||||
@ -200,6 +201,7 @@ import { NavTreeComponent } from '@shared/components/nav-tree.component';
|
|||||||
MessageTypeAutocompleteComponent,
|
MessageTypeAutocompleteComponent,
|
||||||
KeyValMapComponent,
|
KeyValMapComponent,
|
||||||
NavTreeComponent,
|
NavTreeComponent,
|
||||||
|
LedLightComponent,
|
||||||
NospacePipe,
|
NospacePipe,
|
||||||
MillisecondsToTimeStringPipe,
|
MillisecondsToTimeStringPipe,
|
||||||
EnumToArrayPipe,
|
EnumToArrayPipe,
|
||||||
@ -349,6 +351,7 @@ import { NavTreeComponent } from '@shared/components/nav-tree.component';
|
|||||||
MessageTypeAutocompleteComponent,
|
MessageTypeAutocompleteComponent,
|
||||||
KeyValMapComponent,
|
KeyValMapComponent,
|
||||||
NavTreeComponent,
|
NavTreeComponent,
|
||||||
|
LedLightComponent,
|
||||||
NospacePipe,
|
NospacePipe,
|
||||||
MillisecondsToTimeStringPipe,
|
MillisecondsToTimeStringPipe,
|
||||||
EnumToArrayPipe,
|
EnumToArrayPipe,
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
"extends": "../tsconfig.json",
|
"extends": "../tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "../out-tsc/app",
|
"outDir": "../out-tsc/app",
|
||||||
"types": ["node", "jquery", "flot", "tooltipster", "tinycolor2", "js-beautify", "react", "react-dom", "jstree"]
|
"types": ["node", "jquery", "flot", "tooltipster", "tinycolor2", "js-beautify", "react", "react-dom", "jstree", "raphael"]
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"test.ts",
|
"test.ts",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user