Browse Source

Merge pull request #72 from deaflynx/develop/3.3-edge

Develop/3.3 edge Edges Overview Widget
pull/3811/head
VoBa 6 years ago
committed by GitHub
parent
commit
1b490bf5f4
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 25
      application/src/main/data/json/system/widget_bundles/edge_widgets.json
  2. 1
      application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
  3. 22
      ui-ngx/src/app/core/http/entity.service.ts
  4. 28
      ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.component.html
  5. 128
      ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.component.scss
  6. 190
      ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.component.ts
  7. 108
      ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.models.ts
  8. 3
      ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts
  9. 16
      ui-ngx/src/app/modules/home/pages/widget/widgets-bundles-table-config.resolver.ts
  10. 10
      ui-ngx/src/app/shared/components/widgets-bundle-select.component.ts
  11. 5
      ui-ngx/src/assets/locale/locale.constant-en_US.json

25
application/src/main/data/json/system/widget_bundles/edge_widgets.json

@ -0,0 +1,25 @@
{
"widgetsBundle": {
"alias": "edge_widgets",
"title": "Edge widgets",
"image": null
},
"widgetTypes": [
{
"alias": "edges_overview",
"name": "Edges Quick Overview",
"descriptor": {
"type": "latest",
"sizeX": 7.5,
"sizeY": 5,
"resources": [],
"templateHtml": "<tb-edges-overview-widget \n [ctx]=\"ctx\">\n</tb-edges-overview-widget>",
"templateCss": "",
"controllerScript": "self.onInit = function() {\n};\n\nself.onDestroy = function() {\n};\n",
"settingsSchema": "{}",
"dataKeySettingsSchema": "{}\n",
"defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{},\"title\":\"Edges Quick Overview\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"datasources\":[{\"type\":\"function\",\"name\":\"Simulated\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Sin\",\"color\":\"#2196f3\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.472295003170325,\"funcBody\":\"return Math.round(1000*Math.sin(time/5000));\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Cos\",\"color\":\"#4caf50\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.8926244886945558,\"funcBody\":\"return Math.round(1000*Math.cos(time/5000));\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#f44336\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6401141393938932,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"widgetStyle\":{},\"actions\":{}}"
}
}
]
}

1
application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java

@ -439,6 +439,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
this.deleteSystemWidgetBundle("input_widgets"); this.deleteSystemWidgetBundle("input_widgets");
this.deleteSystemWidgetBundle("date"); this.deleteSystemWidgetBundle("date");
this.deleteSystemWidgetBundle("entity_admin_widgets"); this.deleteSystemWidgetBundle("entity_admin_widgets");
this.deleteSystemWidgetBundle("edge_widgets");
installScripts.loadSystemWidgets(); installScripts.loadSystemWidgets();
} }

22
ui-ngx/src/app/core/http/entity.service.ts

@ -1157,4 +1157,26 @@ export class EntityService {
datasource.dataKeys.push(dataKey); datasource.dataKeys.push(dataKey);
}); });
} }
public getAssignedToEdgeEntitiesByType(edgeId: string, entityType: EntityType, pageLink: PageLink): Observable<PageData<any>> {
let entitiesObservable: Observable<PageData<any>>;
switch (entityType) {
case (EntityType.ASSET):
entitiesObservable = this.assetService.getEdgeAssets(edgeId, pageLink);
break;
case (EntityType.DEVICE):
entitiesObservable = this.deviceService.getEdgeDevices(edgeId, pageLink);
break;
case (EntityType.ENTITY_VIEW):
entitiesObservable = this.entityViewService.getEdgeEntityViews(edgeId, pageLink);
break;
case (EntityType.DASHBOARD):
entitiesObservable = this.dashboardService.getEdgeDashboards(edgeId, pageLink);
break;
case (EntityType.RULE_CHAIN):
entitiesObservable = this.ruleChainService.getEdgeRuleChains(edgeId, pageLink);
break;
}
return entitiesObservable;
}
} }

28
ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.component.html

@ -0,0 +1,28 @@
<!--
Copyright © 2016-2020 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<div class="tb-edges-overview tb-absolute-fill" tb-toast toastTarget="{{ toastTargetId }}">
<div fxFlex fxLayout="column" class="tb-absolute-fill">
<span class="mat-subheader" *ngIf="customerTitle" fxLayout="row">{{ customerTitle }}</span>
<span class="mat-subheader" *ngIf="!edgeIsDatasource" fxLayout="row" translate>edge.widget-datasource-error</span>
<div fxFlex class="tb-entities-nav-tree-panel">
<tb-nav-tree
[loadNodes]="loadNodes"
></tb-nav-tree>
</div>
</div>
</div>

128
ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.component.scss

@ -0,0 +1,128 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
:host-context(.tb-has-timewindow) {
.tb-edges-overview {
mat-toolbar {
height: 60px;
max-height: 60px;
.mat-toolbar-tools {
height: 60px;
max-height: 60px;
}
}
}
}
:host {
.tb-edges-overview {
mat-toolbar.mat-table-toolbar:not([color="primary"]) {
background: transparent;
}
mat-toolbar {
min-height: 39px;
max-height: 39px;
.mat-toolbar-tools {
min-height: 39px;
max-height: 39px;
}
}
.mat-subheader {
padding: 15px;
color: rgba(0,0,0,0.54);
font-size: 14px;
font-weight: 400;
}
.tb-entities-nav-tree-panel {
overflow-x: auto;
overflow-y: auto;
}
}
}
:host ::ng-deep {
.tb-nav-tree-container {
&.jstree-proton {
.jstree-anchor {
div.node-icon {
display: inline-block;
width: 22px;
height: 22px;
margin-right: 2px;
margin-bottom: 2px;
background-color: transparent;
background-repeat: no-repeat;
background-attachment: scroll;
background-position: center center;
background-size: 18px 18px;
}
mat-icon.node-icon {
width: 22px;
min-width: 22px;
height: 22px;
min-height: 22px;
margin-right: 2px;
margin-bottom: 2px;
color: inherit;
vertical-align: middle;
&.material-icons {
font-size: 18px;
line-height: 22px;
text-align: center;
}
}
&.jstree-hovered:not(.jstree-clicked),
&.jstree-disabled {
div.node-icon {
opacity: .5;
}
}
}
}
}
@media (max-width: 768px) {
.tb-nav-tree-container {
&.jstree-proton-responsive {
.jstree-anchor {
div.node-icon {
width: 40px;
height: 40px;
margin: 0;
background-size: 24px 24px;
}
mat-icon.node-icon {
width: 40px;
min-width: 40px;
height: 40px;
min-height: 40px;
margin: 0;
&.material-icons {
font-size: 24px;
line-height: 40px;
}
}
}
}
}
}
}

190
ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.component.ts

@ -0,0 +1,190 @@
///
/// Copyright © 2016-2020 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
import { PageComponent } from '@shared/components/page.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { WidgetContext } from '@home/models/widget-component.models';
import { Datasource, DatasourceType, WidgetConfig } from '@shared/models/widget.models';
import { IWidgetSubscription } from '@core/api/widget-api.models';
import { UtilsService } from '@core/services/utils.service';
import { LoadNodesCallback } from '@shared/components/nav-tree.component';
import { EntityType } from '@shared/models/entity-type.models';
import {
EdgeGroupNodeData,
edgeGroupsNodeText,
edgeGroupsTypes,
entityNodeText,
EdgeOverviewNode,
EntityNodeData,
EntityNodeDatasource
} from '@home/components/widget/lib/edges-overview-widget.models';
import { EdgeService } from "@core/http/edge.service";
import { EntityService } from "@core/http/entity.service";
import { TranslateService } from "@ngx-translate/core";
import { PageLink } from "@shared/models/page/page-link";
import { BaseData, HasId } from "@shared/models/base-data";
import { EntityId } from "@shared/models/id/entity-id";
import { getCurrentAuthUser } from "@core/auth/auth.selectors";
import { Authority } from "@shared/models/authority.enum";
@Component({
selector: 'tb-edges-overview-widget',
templateUrl: './edges-overview-widget.component.html',
styleUrls: ['./edges-overview-widget.component.scss']
})
export class EdgesOverviewWidgetComponent extends PageComponent implements OnInit {
@Input()
ctx: WidgetContext;
public toastTargetId = 'edges-overview-' + this.utils.guid();
public customerTitle: string = null;
public edgeIsDatasource: boolean = true;
private widgetConfig: WidgetConfig;
private subscription: IWidgetSubscription;
private datasources: Array<EntityNodeDatasource>;
private nodeIdCounter = 0;
private entityNodesMap: {[parentNodeId: string]: {[edgeId: string]: string}} = {};
private entityGroupsNodesMap: {[edgeNodeId: string]: {[groupType: string]: string}} = {};
constructor(protected store: Store<AppState>,
private edgeService: EdgeService,
private entityService: EntityService,
private translateService: TranslateService,
private utils: UtilsService,
private cd: ChangeDetectorRef) {
super(store);
}
ngOnInit(): void {
this.widgetConfig = this.ctx.widgetConfig;
this.subscription = this.ctx.defaultSubscription;
this.datasources = this.subscription.datasources as Array<EntityNodeDatasource>;
this.ctx.updateWidgetParams();
}
public loadNodes: LoadNodesCallback = (node, cb) => {
const datasource: Datasource = this.datasources[0];
if (node.id === '#' && datasource) {
if (datasource.type === DatasourceType.entity && datasource.entity.id.entityType === EntityType.EDGE) {
var selectedEdge: BaseData<EntityId> = datasource.entity;
this.getCustomerTitle(selectedEdge.id.id);
this.ctx.widgetTitle = selectedEdge.name;
cb(this.loadNodesForEdge(selectedEdge.id.id, selectedEdge));
} else if (datasource.type === DatasourceType.function) {
cb(this.loadNodesForEdge(datasource.entityId, datasource.entity));
} else {
this.edgeIsDatasource = false;
cb([]);
}
}
else if (node.data && node.data.entity.id.entityType === EntityType.EDGE) {
const edgeId = node.data.entity.id.id;
const entityType = node.data.entityType;
const pageLink = new PageLink(datasource.pageLink.pageSize);
this.entityService.getAssignedToEdgeEntitiesByType(edgeId, entityType, pageLink).subscribe(
(entities) => {
if (entities.data.length > 0) {
cb(this.entitiesToNodes(node.id, entities.data));
} else {
cb([]);
}
}
)
} else {
cb([]);
}
}
private loadNodesForEdge(parentNodeId: string, entity: BaseData<HasId>): EdgeOverviewNode[] {
const nodes: EdgeOverviewNode[] = [];
const nodesMap = {};
this.entityGroupsNodesMap[parentNodeId] = nodesMap;
const authUser = getCurrentAuthUser(this.store);
var allowedGroupTypes: EntityType[] = edgeGroupsTypes;
if (authUser.authority === Authority.CUSTOMER_USER) {
allowedGroupTypes = edgeGroupsTypes.filter(type => type !== EntityType.RULE_CHAIN);
}
allowedGroupTypes.forEach((entityType) => {
const node: EdgeOverviewNode = {
id: (++this.nodeIdCounter)+'',
icon: false,
text: edgeGroupsNodeText(this.translateService, entityType),
children: true,
data: {
entityType,
entity,
internalId: entity.id.id + '_' + entityType
} as EdgeGroupNodeData
};
nodes.push(node);
nodesMap[entityType] = node.id;
});
return nodes;
}
private createEntityNode(parentNodeId: string, entity: BaseData<HasId>): EdgeOverviewNode {
let nodesMap = this.entityNodesMap[parentNodeId];
if (!nodesMap) {
nodesMap = {};
this.entityNodesMap[parentNodeId] = nodesMap;
}
const node: EdgeOverviewNode = {
id: (++this.nodeIdCounter)+'',
icon: false,
text: entityNodeText(entity),
children: false,
state: {
disabled: false
},
data: {
entity: entity,
internalId: entity.id.id
} as EntityNodeData
};
nodesMap[entity.id.id] = node.id;
return node;
}
private entitiesToNodes(parentNodeId: string, entities: BaseData<HasId>[]): EdgeOverviewNode[] {
const nodes: EdgeOverviewNode[] = [];
this.entityNodesMap[parentNodeId] = {};
if (entities) {
entities.forEach((entity) => {
const node = this.createEntityNode(parentNodeId, entity);
nodes.push(node);
});
}
return nodes;
}
private getCustomerTitle(edgeId: string) {
this.edgeService.getEdgeInfo(edgeId).subscribe(
(edge) => {
if (edge.customerTitle) {
this.customerTitle = this.translateService.instant('edge.assigned-to-customer', {customerTitle: edge.customerTitle});
} else {
this.customerTitle = null;
}
this.cd.detectChanges();
});
}
}

108
ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.models.ts

@ -0,0 +1,108 @@
///
/// Copyright © 2016-2020 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { NavTreeNode } from '@shared/components/nav-tree.component';
import { Datasource } from '@shared/models/widget.models';
import { EntityType } from '@shared/models/entity-type.models';
import { TranslateService } from "@ngx-translate/core";
import { BaseData, HasId } from "@shared/models/base-data";
export interface EntityNodeDatasource extends Datasource {
nodeId: string;
}
export function edgeGroupsNodeText(translate: TranslateService, entityType: EntityType): string {
const nodeIcon = materialIconByEntityType(entityType);
const nodeText = textForEdgeGroupsType(translate, entityType);
return nodeIcon + nodeText;
}
export function entityNodeText(entity: any): string {
const nodeIcon = materialIconByEntityType(entity.id.entityType);
const nodeText = entity.name;
return nodeIcon + nodeText;
}
export function materialIconByEntityType(entityType: EntityType): string {
let materialIcon = 'insert_drive_file';
switch (entityType) {
case EntityType.DEVICE:
materialIcon = 'devices_other';
break;
case EntityType.ASSET:
materialIcon = 'domain';
break;
case EntityType.DASHBOARD:
materialIcon = 'dashboards';
break;
case EntityType.ENTITY_VIEW:
materialIcon = 'view_quilt';
break;
case EntityType.RULE_CHAIN:
materialIcon = 'settings_ethernet';
break;
}
return '<mat-icon class="node-icon material-icons" role="img" aria-hidden="false">' + materialIcon + '</mat-icon>';
}
export function textForEdgeGroupsType(translate: TranslateService, entityType: EntityType): string {
let textForEdgeGroupsType: string = '';
switch (entityType) {
case EntityType.DEVICE:
textForEdgeGroupsType = 'device.devices';
break;
case EntityType.ASSET:
textForEdgeGroupsType = 'asset.assets';
break;
case EntityType.DASHBOARD:
textForEdgeGroupsType = 'dashboard.dashboards';
break;
case EntityType.ENTITY_VIEW:
textForEdgeGroupsType = 'entity-view.entity-views';
break;
case EntityType.RULE_CHAIN:
textForEdgeGroupsType = 'rulechain.rulechains';
break;
}
return translate.instant(textForEdgeGroupsType);
}
export const edgeGroupsTypes: EntityType[] = [
EntityType.ASSET,
EntityType.DEVICE,
EntityType.ENTITY_VIEW,
EntityType.DASHBOARD,
EntityType.RULE_CHAIN
]
export interface EdgeOverviewNode extends NavTreeNode {
data?: EdgeOverviewNodeData;
}
export type EdgeOverviewNodeData = EdgeGroupNodeData | EntityNodeData;
export interface EdgeGroupNodeData extends BaseEdgeOverviewNodeData {
entityType: EntityType;
entity: BaseData<HasId>;
}
export interface EntityNodeData extends BaseEdgeOverviewNodeData {
entity: BaseData<HasId>;
}
export interface BaseEdgeOverviewNodeData {
internalId: string;
}

3
ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts

@ -35,6 +35,7 @@ import { TripAnimationComponent } from './trip-animation/trip-animation.componen
import { PhotoCameraInputWidgetComponent } from './lib/photo-camera-input.component'; import { PhotoCameraInputWidgetComponent } from './lib/photo-camera-input.component';
import { GatewayFormComponent } from './lib/gateway/gateway-form.component'; import { GatewayFormComponent } from './lib/gateway/gateway-form.component';
import { ImportExportService } from '@home/components/import-export/import-export.service'; import { ImportExportService } from '@home/components/import-export/import-export.service';
import { EdgesOverviewWidgetComponent } from "@home/components/widget/lib/edges-overview-widget.component";
@NgModule({ @NgModule({
declarations: declarations:
@ -45,6 +46,7 @@ import { ImportExportService } from '@home/components/import-export/import-expor
AlarmsTableWidgetComponent, AlarmsTableWidgetComponent,
TimeseriesTableWidgetComponent, TimeseriesTableWidgetComponent,
EntitiesHierarchyWidgetComponent, EntitiesHierarchyWidgetComponent,
EdgesOverviewWidgetComponent,
DateRangeNavigatorWidgetComponent, DateRangeNavigatorWidgetComponent,
DateRangeNavigatorPanelComponent, DateRangeNavigatorPanelComponent,
MultipleInputWidgetComponent, MultipleInputWidgetComponent,
@ -63,6 +65,7 @@ import { ImportExportService } from '@home/components/import-export/import-expor
AlarmsTableWidgetComponent, AlarmsTableWidgetComponent,
TimeseriesTableWidgetComponent, TimeseriesTableWidgetComponent,
EntitiesHierarchyWidgetComponent, EntitiesHierarchyWidgetComponent,
EdgesOverviewWidgetComponent,
RpcWidgetsModule, RpcWidgetsModule,
DateRangeNavigatorWidgetComponent, DateRangeNavigatorWidgetComponent,
MultipleInputWidgetComponent, MultipleInputWidgetComponent,

16
ui-ngx/src/app/modules/home/pages/widget/widgets-bundles-table-config.resolver.ts

@ -33,11 +33,12 @@ import { WidgetsBundleComponent } from '@modules/home/pages/widget/widgets-bundl
import { NULL_UUID } from '@shared/models/id/has-uuid'; import { NULL_UUID } from '@shared/models/id/has-uuid';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { getCurrentAuthUser } from '@app/core/auth/auth.selectors'; import { getCurrentAuthState, getCurrentAuthUser } from '@app/core/auth/auth.selectors';
import { Authority } from '@shared/models/authority.enum'; import { Authority } from '@shared/models/authority.enum';
import { DialogService } from '@core/services/dialog.service'; import { DialogService } from '@core/services/dialog.service';
import { ImportExportService } from '@home/components/import-export/import-export.service'; import { ImportExportService } from '@home/components/import-export/import-export.service';
import { Direction } from "@shared/models/page/sort-order"; import { Direction } from "@shared/models/page/sort-order";
import { map } from "rxjs/operators";
@Injectable() @Injectable()
export class WidgetsBundlesTableConfigResolver implements Resolve<EntityTableConfig<WidgetsBundle>> { export class WidgetsBundlesTableConfigResolver implements Resolve<EntityTableConfig<WidgetsBundle>> {
@ -106,7 +107,7 @@ export class WidgetsBundlesTableConfigResolver implements Resolve<EntityTableCon
this.config.deleteEntitiesTitle = count => this.translate.instant('widgets-bundle.delete-widgets-bundles-title', {count}); this.config.deleteEntitiesTitle = count => this.translate.instant('widgets-bundle.delete-widgets-bundles-title', {count});
this.config.deleteEntitiesContent = () => this.translate.instant('widgets-bundle.delete-widgets-bundles-text'); this.config.deleteEntitiesContent = () => this.translate.instant('widgets-bundle.delete-widgets-bundles-text');
this.config.entitiesFetchFunction = pageLink => this.widgetsService.getWidgetBundles(pageLink);
this.config.loadEntity = id => this.widgetsService.getWidgetsBundle(id.id); this.config.loadEntity = id => this.widgetsService.getWidgetsBundle(id.id);
this.config.saveEntity = widgetsBundle => this.widgetsService.saveWidgetsBundle(widgetsBundle); this.config.saveEntity = widgetsBundle => this.widgetsService.saveWidgetsBundle(widgetsBundle);
this.config.deleteEntity = id => this.widgetsService.deleteWidgetsBundle(id.id); this.config.deleteEntity = id => this.widgetsService.deleteWidgetsBundle(id.id);
@ -119,6 +120,17 @@ export class WidgetsBundlesTableConfigResolver implements Resolve<EntityTableCon
this.config.deleteEnabled = (widgetsBundle) => this.isWidgetsBundleEditable(widgetsBundle, authUser.authority); this.config.deleteEnabled = (widgetsBundle) => this.isWidgetsBundleEditable(widgetsBundle, authUser.authority);
this.config.entitySelectionEnabled = (widgetsBundle) => this.isWidgetsBundleEditable(widgetsBundle, authUser.authority); this.config.entitySelectionEnabled = (widgetsBundle) => this.isWidgetsBundleEditable(widgetsBundle, authUser.authority);
this.config.detailsReadonly = (widgetsBundle) => !this.isWidgetsBundleEditable(widgetsBundle, authUser.authority); this.config.detailsReadonly = (widgetsBundle) => !this.isWidgetsBundleEditable(widgetsBundle, authUser.authority);
const authState = getCurrentAuthState(this.store);
if (!authState.edgesSupportEnabled) {
this.config.entitiesFetchFunction = pageLink => this.widgetsService.getWidgetBundles(pageLink).pipe(
map((widgetBundles) => {
widgetBundles.data = widgetBundles.data.filter(widgetBundle => widgetBundle.alias !== 'edge_widgets');
return widgetBundles;
})
);
} else {
this.config.entitiesFetchFunction = pageLink => this.widgetsService.getWidgetBundles(pageLink);
}
return this.config; return this.config;
} }

10
ui-ngx/src/app/shared/components/widgets-bundle-select.component.ts

@ -17,7 +17,7 @@
import { Component, forwardRef, Input, OnChanges, OnInit, SimpleChanges, ViewEncapsulation } from '@angular/core'; import { Component, forwardRef, Input, OnChanges, OnInit, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { share, tap } from 'rxjs/operators'; import { map, share, tap } from 'rxjs/operators';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state'; import { AppState } from '@app/core/core.state';
import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { coerceBooleanProperty } from '@angular/cdk/coercion';
@ -25,6 +25,7 @@ import { WidgetsBundle } from '@shared/models/widgets-bundle.model';
import { WidgetService } from '@core/http/widget.service'; import { WidgetService } from '@core/http/widget.service';
import { isDefined } from '@core/utils'; import { isDefined } from '@core/utils';
import { NULL_UUID } from '@shared/models/id/has-uuid'; import { NULL_UUID } from '@shared/models/id/has-uuid';
import { getCurrentAuthState } from "@core/auth/auth.selectors";
@Component({ @Component({
selector: 'tb-widgets-bundle-select', selector: 'tb-widgets-bundle-select',
@ -94,6 +95,13 @@ export class WidgetsBundleSelectComponent implements ControlValueAccessor, OnIni
} }
} }
}), }),
map((widgetsBundles) => {
const authState = getCurrentAuthState(this.store);
if (!authState.edgesSupportEnabled) {
widgetsBundles = widgetsBundles.filter(widgetsBundle => widgetsBundle.alias !== 'edge_widgets');
}
return widgetsBundles;
}),
share() share()
); );
} }

5
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -1233,7 +1233,7 @@
"assign-to-customer-text": "Please select the customer to assign the edge(s)", "assign-to-customer-text": "Please select the customer to assign the edge(s)",
"assign-edge-to-customer": "Assign Edge(s) To Customer", "assign-edge-to-customer": "Assign Edge(s) To Customer",
"assign-edge-to-customer-text": "Please select the edges to assign to the customer", "assign-edge-to-customer-text": "Please select the edges to assign to the customer",
"assigned-to-customer": "Assigned to customer", "assigned-to-customer": "Assigned to: {{customerTitle}}",
"unassign-from-customer": "Unassign from customer", "unassign-from-customer": "Unassign from customer",
"assign-edges-text": "Assign { count, plural, 1 {1 edge} other {# edges} } to customer", "assign-edges-text": "Assign { count, plural, 1 {1 edge} other {# edges} } to customer",
"unassign-edge-title": "Are you sure you want to unassign the edge '{{edgeName}}'?", "unassign-edge-title": "Are you sure you want to unassign the edge '{{edgeName}}'?",
@ -1287,7 +1287,8 @@
"no-downlinks-prompt": "No downlinks found", "no-downlinks-prompt": "No downlinks found",
"sync-process-started-successfully": "Sync process started successfully!", "sync-process-started-successfully": "Sync process started successfully!",
"missing-related-rule-chains-title": "Edge has missing related rule chain(s)", "missing-related-rule-chains-title": "Edge has missing related rule chain(s)",
"missing-related-rule-chains-text": "Assigned to edge rule chain(s) use rule nodes that forward message(s) to rule chain(s) that are not assigned to this edge. <br><br> List of missing rule chain(s): <br> {{missingRuleChains}}" "missing-related-rule-chains-text": "Assigned to edge rule chain(s) use rule nodes that forward message(s) to rule chain(s) that are not assigned to this edge. <br><br> List of missing rule chain(s): <br> {{missingRuleChains}}",
"widget-datasource-error": "This widget supports only EDGE entity datasource"
}, },
"edge-event": { "edge-event": {
"type-dashboard": "Dashboard", "type-dashboard": "Dashboard",

Loading…
Cancel
Save