diff --git a/application/src/main/data/json/system/widget_bundles/edge_widgets.json b/application/src/main/data/json/system/widget_bundles/edge_widgets.json index 6412ff9d99..8b64885d80 100644 --- a/application/src/main/data/json/system/widget_bundles/edge_widgets.json +++ b/application/src/main/data/json/system/widget_bundles/edge_widgets.json @@ -16,7 +16,7 @@ "templateHtml": "\n", "templateCss": "", "controllerScript": "self.onInit = function() {\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n dataKeysOptional: true\n };\n}\n\nself.onDestroy = function() {\n};\n", - "settingsSchema": "{}\n", + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EdgeOverviewSettings\",\n \"properties\": {\n \"enableDefaultTitle\": {\n \"title\": \"Display default title\",\n \"type\": \"boolean\",\n \"default\": true\n }\n },\n \"required\": []\n },\n \"form\": [\n \"enableDefaultTitle\"\n ]\n}", "dataKeySettingsSchema": "{}\n", "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"showTitleIcon\":true,\"titleIcon\":\"router\",\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{},\"title\":\"Edge 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));\"}]}],\"widgetStyle\":{},\"actions\":{}}" } diff --git a/ui-ngx/src/app/core/http/entity.service.ts b/ui-ngx/src/app/core/http/entity.service.ts index 7da7bf61f7..e0afb0a2e4 100644 --- a/ui-ngx/src/app/core/http/entity.service.ts +++ b/ui-ngx/src/app/core/http/entity.service.ts @@ -76,8 +76,10 @@ import { } from '@shared/models/query/query.models'; import { alarmFields } from '@shared/models/alarm.models'; import { EdgeService } from "@core/http/edge.service"; +import { Edge, EdgeEventType } from '@shared/models/edge.models'; import { RuleChainType } from "@shared/models/rule-chain.models"; -import { Edge } from '@shared/models/edge.models'; +import { WidgetService } from "@core/http/widget.service"; +import { DeviceProfileService } from "@core/http/device-profile.service"; @Injectable({ providedIn: 'root' @@ -98,6 +100,8 @@ export class EntityService { private dashboardService: DashboardService, private entityRelationService: EntityRelationService, private attributeService: AttributeService, + private widgetService: WidgetService, + private deviceProfileService: DeviceProfileService, private utils: UtilsService ) { } @@ -1316,4 +1320,40 @@ export class EntityService { } return entitiesObservable; } + + public getEdgeEventContentByEntityType(entity: any): Observable { + let entityObservable: Observable; + const entityId: string = entity.entityId; + const entityType: any = entity.type; + switch (entityType) { + case EdgeEventType.DASHBOARD: + case EdgeEventType.ALARM: + case EdgeEventType.RULE_CHAIN: + case EdgeEventType.EDGE: + case EdgeEventType.USER: + case EdgeEventType.CUSTOMER: + case EdgeEventType.TENANT: + case EdgeEventType.ASSET: + case EdgeEventType.DEVICE: + case EdgeEventType.ENTITY_VIEW: + entityObservable = this.getEntity(entityType, entityId, { ignoreLoading: true, ignoreErrors: true }); + break; + case EdgeEventType.RULE_CHAIN_METADATA: + entityObservable = this.ruleChainService.getRuleChainMetadata(entityId); + break; + case EdgeEventType.WIDGET_TYPE: + entityObservable = this.widgetService.getWidgetTypeById(entityId); + break; + case EdgeEventType.WIDGETS_BUNDLE: + entityObservable = this.widgetService.getWidgetsBundle(entityId); + break; + case EdgeEventType.DEVICE_PROFILE: + entityObservable = this.deviceProfileService.getDeviceProfile(entityId); + break; + case EdgeEventType.RELATION: + entityObservable = of(entity.body); + break; + } + return entityObservable; + } } diff --git a/ui-ngx/src/app/modules/home/components/edge/edge-downlink-table-config.ts b/ui-ngx/src/app/modules/home/components/edge/edge-downlink-table-config.ts index 64bac0313f..8f2f9a776d 100644 --- a/ui-ngx/src/app/modules/home/components/edge/edge-downlink-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/edge/edge-downlink-table-config.ts @@ -21,7 +21,8 @@ import { EntityTableConfig } from '@home/models/entity/entities-table-config.models'; import { - EdgeEvent, edgeEventActionTypeTranslations, + EdgeEvent, + edgeEventActionTypeTranslations, EdgeEventStatus, edgeEventStatusColor, EdgeEventType, @@ -33,7 +34,7 @@ import { DatePipe } from '@angular/common'; import { MatDialog } from '@angular/material/dialog'; import { EntityId } from '@shared/models/id/entity-id'; import { EntityTypeResource } from '@shared/models/entity-type.models'; -import { Observable, of } from 'rxjs'; +import { Observable } from 'rxjs'; import { PageData } from '@shared/models/page/page-data'; import { Direction } from '@shared/models/page/sort-order'; import { DialogService } from '@core/services/dialog.service'; @@ -42,37 +43,29 @@ import { EventContentDialogComponent, EventContentDialogData } from '@home/components/event/event-content-dialog.component'; -import { sortObjectKeys } from '@core/utils'; -import { RuleChainService } from '@core/http/rule-chain.service'; import { AttributeService } from '@core/http/attribute.service'; import { AttributeScope } from '@shared/models/telemetry/telemetry.models'; import { EdgeDownlinkTableHeaderComponent } from '@home/components/edge/edge-downlink-table-header.component'; import { EdgeService } from '@core/http/edge.service'; import { map } from 'rxjs/operators'; -import { AssetService } from '@core/http/asset.service'; -import { DeviceService } from '@core/http/device.service'; -import { EntityViewService } from '@core/http/entity-view.service'; -import { EventTableHeaderComponent } from '@home/components/event/event-table-header.component'; +import { EntityService } from "@core/http/entity.service"; export class EdgeDownlinkTableConfig extends EntityTableConfig { queueStartTs: number; constructor(private edgeService: EdgeService, + private entityService: EntityService, private dialogService: DialogService, private translate: TranslateService, - private deviceService: DeviceService, - private assetService: AssetService, - private entityViewService: EntityViewService, - private ruleChainService: RuleChainService, private attributeService: AttributeService, private datePipe: DatePipe, private dialog: MatDialog, - public entityId: EntityId, - public tenantId: string) { + public entityId: EntityId) { super(); - this.loadDataOnInit = false; + this.tableTitle = ''; + this.loadDataOnInit = false; this.useTimePageLink = true; this.detailsPanelEnabled = false; this.selectionEnabled = false; @@ -81,13 +74,11 @@ export class EdgeDownlinkTableConfig extends EntityTableConfig; this.entitiesFetchFunction = pageLink => this.fetchEvents(pageLink); - this.defaultSortOrder = {property: 'createdTime', direction: Direction.DESC}; this.updateColumns(); @@ -98,6 +89,24 @@ export class EdgeDownlinkTableConfig extends EntityTableConfig this.onUpdate(attributes) + ); + } + + onUpdate(attributes) { + this.queueStartTs = 0; + let edge = attributes.reduce(function (map, attribute) { + map[attribute.key] = attribute; + return map; + }, {}); + if (edge.queueStartTs) { + this.queueStartTs = edge.queueStartTs.lastUpdateTs; + } + } + updateColumns(updateTableColumns: boolean = false): void { this.columns = []; this.columns.push( @@ -132,31 +141,20 @@ export class EdgeDownlinkTableConfig extends EntityTableConfig(EventContentDialogComponent, { - disableClose: true, - panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], - data: { - content, - title, - contentType - } - }); } - isEdgeEventHasData(edgeEventType: EdgeEventType) { + isPending(createdTime): boolean { + return createdTime > this.queueStartTs; + } + + isEdgeEventHasData(edgeEventType: EdgeEventType): boolean { switch (edgeEventType) { - case EdgeEventType.WIDGET_TYPE: - case EdgeEventType.WIDGETS_BUNDLE: case EdgeEventType.ADMIN_SETTINGS: return false; default: @@ -164,90 +162,24 @@ export class EdgeDownlinkTableConfig extends EntityTableConfig { - return JSON.stringify(asset); - }) - ); - case EdgeEventType.DEVICE: - return this.deviceService.getDevice(entity.entityId, null).pipe( - map((device) => { - return JSON.stringify(device); - }) - ); - case EdgeEventType.ENTITY_VIEW: - return this.entityViewService.getEntityView(entity.entityId, null).pipe( - map((entityView) => { - return JSON.stringify(entityView); - }) - ); - case EdgeEventType.RULE_CHAIN_METADATA: - return this.ruleChainService.getRuleChainMetadata(entity.entityId, null).pipe( - map((ruleChainMetaData) => { - return JSON.stringify(ruleChainMetaData.nodes); - }) - ); - default: - return of(JSON.stringify(entity)); - } + prepareEdgeEventContent(entity: any): Observable { + return this.entityService.getEdgeEventContentByEntityType(entity).pipe( + map((result) => JSON.stringify(result)) + ); } - showEdgeEventContent($event: MouseEvent, content: string, title: string, sortKeys = false): void { + showEdgeEventContent($event: MouseEvent, content: string, title: string): void { if ($event) { $event.stopPropagation(); } - var contentType = ContentType.JSON; - if (contentType === ContentType.JSON && sortKeys) { - try { - content = JSON.stringify(sortObjectKeys(JSON.parse(content))); - } catch (e) { - } - } this.dialog.open(EventContentDialogComponent, { disableClose: true, panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], data: { content, title, - contentType + contentType: ContentType.JSON } }); } - - updateEdgeEventStatus(createdTime) { - if (this.queueStartTs && createdTime < this.queueStartTs) { - return this.translate.instant('edge.deployed'); - } else { - return this.translate.instant('edge.pending'); - } - } - - isPending(createdTime) { - return createdTime > this.queueStartTs; - } - - loadEdgeInfo() { - this.attributeService.getEntityAttributes(this.entityId, AttributeScope.SERVER_SCOPE, ['queueStartTs']) - .subscribe( - attributes => this.onUpdate(attributes) - ); - } - - onUpdate(attributes) { - this.queueStartTs = 0; - let edge = attributes.reduce(function (map, attribute) { - map[attribute.key] = attribute; - return map; - }, {}); - if (edge.queueStartTs) { - this.queueStartTs = edge.queueStartTs.lastUpdateTs; - } - } } - diff --git a/ui-ngx/src/app/modules/home/components/edge/edge-downlink-table.component.ts b/ui-ngx/src/app/modules/home/components/edge/edge-downlink-table.component.ts index e6ad61998e..3b5fca1c7a 100644 --- a/ui-ngx/src/app/modules/home/components/edge/edge-downlink-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/edge/edge-downlink-table.component.ts @@ -22,12 +22,9 @@ import { EntityId } from '@shared/models/id/entity-id'; import { EntitiesTableComponent } from '@home/components/entity/entities-table.component'; import { EdgeDownlinkTableConfig } from './edge-downlink-table-config'; import { DialogService } from '@core/services/dialog.service'; -import { RuleChainService } from '@core/http/rule-chain.service'; import { AttributeService } from '@core/http/attribute.service'; import { EdgeService } from '@core/http/edge.service'; -import { DeviceService } from '@core/http/device.service'; -import { AssetService } from '@core/http/asset.service'; -import { EntityViewService } from '@core/http/entity-view.service'; +import { EntityService } from "@core/http/entity.service"; @Component({ selector: 'tb-edge-downlink-table', @@ -36,9 +33,6 @@ import { EntityViewService } from '@core/http/entity-view.service'; }) export class EdgeDownlinkTableComponent implements OnInit { - @Input() - tenantId: string; - activeValue = false; dirtyValue = false; entityIdValue: EntityId; @@ -71,13 +65,10 @@ export class EdgeDownlinkTableComponent implements OnInit { edgeDownlinkTableConfig: EdgeDownlinkTableConfig; constructor(private edgeService: EdgeService, - private deviceService: DeviceService, - private assetService: AssetService, - private entityViewService: EntityViewService, + private entityService: EntityService, private dialogService: DialogService, private translate: TranslateService, private attributeService: AttributeService, - private ruleChainService: RuleChainService, private datePipe: DatePipe, private dialog: MatDialog) { } @@ -86,17 +77,13 @@ export class EdgeDownlinkTableComponent implements OnInit { this.dirtyValue = !this.activeValue; this.edgeDownlinkTableConfig = new EdgeDownlinkTableConfig( this.edgeService, + this.entityService, this.dialogService, this.translate, - this.deviceService, - this.assetService, - this.entityViewService, - this.ruleChainService, this.attributeService, this.datePipe, this.dialog, - this.entityIdValue, - this.tenantId + this.entityIdValue ); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.component.ts index 657cc92efe..0b15def29f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.component.ts @@ -41,6 +41,11 @@ 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'; +import { isDefined } from '@core/utils'; + +interface EdgesOverviewWidgetSettings { + enableDefaultTitle: boolean; +} @Component({ selector: 'tb-edges-overview-widget', @@ -59,12 +64,10 @@ export class EdgesOverviewWidgetComponent extends PageComponent implements OnIni private widgetConfig: WidgetConfig; private subscription: IWidgetSubscription; private datasources: Array; + private settings: EdgesOverviewWidgetSettings; private nodeIdCounter = 0; - private entityNodesMap: {[parentNodeId: string]: {[edgeId: string]: string}} = {}; - private entityGroupsNodesMap: {[edgeNodeId: string]: {[groupType: string]: string}} = {}; - constructor(protected store: Store, private edgeService: EdgeService, private entityService: EntityService, @@ -78,6 +81,8 @@ export class EdgesOverviewWidgetComponent extends PageComponent implements OnIni this.widgetConfig = this.ctx.widgetConfig; this.subscription = this.ctx.defaultSubscription; this.datasources = this.subscription.datasources as Array; + this.settings = this.ctx.settings; + this.initializeConfig(); this.ctx.updateWidgetParams(); } @@ -86,11 +91,11 @@ export class EdgesOverviewWidgetComponent extends PageComponent implements OnIni if (node.id === '#' && datasource) { if (datasource.type === DatasourceType.entity && datasource.entity.id.entityType === EntityType.EDGE) { var selectedEdge: BaseData = datasource.entity; + this.updateTitle(selectedEdge); this.getCustomerTitle(selectedEdge.id.id); - this.ctx.widgetTitle = `${selectedEdge.name} Quick Overview`; - cb(this.loadNodesForEdge(selectedEdge.id.id, selectedEdge)); + cb(this.loadNodesForEdge(selectedEdge)); } else if (datasource.type === DatasourceType.function) { - cb(this.loadNodesForEdge(datasource.entityId, datasource.entity)); + cb(this.loadNodesForEdge(datasource.entity)); } else { this.edgeIsDatasource = false; cb([]); @@ -103,21 +108,19 @@ export class EdgesOverviewWidgetComponent extends PageComponent implements OnIni this.entityService.getAssignedToEdgeEntitiesByType(edgeId, entityType, pageLink).subscribe( (entities) => { if (entities.data.length > 0) { - cb(this.entitiesToNodes(node.id, entities.data)); + cb(this.entitiesToNodes(entities.data)); } else { cb([]); } } - ) + ); } else { cb([]); } } - private loadNodesForEdge(parentNodeId: string, entity: BaseData): EdgeOverviewNode[] { + private loadNodesForEdge(entity: BaseData): 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) { @@ -136,18 +139,12 @@ export class EdgesOverviewWidgetComponent extends PageComponent implements OnIni } as EdgeGroupNodeData }; nodes.push(node); - nodesMap[entityType] = node.id; }); return nodes; } - private createEntityNode(parentNodeId: string, entity: BaseData): EdgeOverviewNode { - let nodesMap = this.entityNodesMap[parentNodeId]; - if (!nodesMap) { - nodesMap = {}; - this.entityNodesMap[parentNodeId] = nodesMap; - } - const node: EdgeOverviewNode = { + private createEntityNode(entity: BaseData): EdgeOverviewNode { + return { id: (++this.nodeIdCounter)+'', icon: false, text: entityNodeText(entity), @@ -159,17 +156,14 @@ export class EdgesOverviewWidgetComponent extends PageComponent implements OnIni entity: entity, internalId: entity.id.id } as EntityNodeData - }; - nodesMap[entity.id.id] = node.id; - return node; + } as EdgeOverviewNode; } - private entitiesToNodes(parentNodeId: string, entities: BaseData[]): EdgeOverviewNode[] { + private entitiesToNodes(entities: BaseData[]): EdgeOverviewNode[] { const nodes: EdgeOverviewNode[] = []; - this.entityNodesMap[parentNodeId] = {}; if (entities) { entities.forEach((entity) => { - const node = this.createEntityNode(parentNodeId, entity); + const node = this.createEntityNode(entity); nodes.push(node); }); } @@ -187,4 +181,17 @@ export class EdgesOverviewWidgetComponent extends PageComponent implements OnIni this.cd.detectChanges(); }); } + + private initializeConfig(): void { + const edgeIsDatasource: boolean = this.datasources[0] && this.datasources[0].type === DatasourceType.entity && this.datasources[0].entity.id.entityType === EntityType.EDGE; + if (edgeIsDatasource) { + const edge = this.datasources[0].entity; + this.updateTitle(edge); + } + } + + private updateTitle(edge: BaseData): void { + const displayDefaultTitle: boolean = isDefined(this.settings.enableDefaultTitle) ? this.settings.enableDefaultTitle : false; + this.ctx.widgetTitle = displayDefaultTitle ? `${edge.name} Quick Overview` : this.widgetConfig.title; + } } diff --git a/ui-ngx/src/app/modules/home/pages/edge/edge-routing.module.ts b/ui-ngx/src/app/modules/home/pages/edge/edge-routing.module.ts index a9d2d586f2..da5aedf53b 100644 --- a/ui-ngx/src/app/modules/home/pages/edge/edge-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/edge/edge-routing.module.ts @@ -34,7 +34,7 @@ import { importRuleChainBreadcumbLabelFunction, ResolvedRuleChainMetaDataResolver, ruleChainBreadcumbLabelFunction, RuleChainImportGuard, - RuleChainResolver, RuleNodeComponentsResolver + RuleChainResolver, RuleNodeComponentsResolver, TooltipsterResolver } from '@home/pages/rulechain/rulechain-routing.module'; const routes: Routes = [ @@ -194,7 +194,8 @@ const routes: Routes = [ resolve: { ruleChain: RuleChainResolver, ruleChainMetaData: ResolvedRuleChainMetaDataResolver, - ruleNodeComponents: RuleNodeComponentsResolver + ruleNodeComponents: RuleNodeComponentsResolver, + tooltipster: TooltipsterResolver } }, { @@ -213,7 +214,8 @@ const routes: Routes = [ ruleChainType: RuleChainType.EDGE }, resolve: { - ruleNodeComponents: RuleNodeComponentsResolver + ruleNodeComponents: RuleNodeComponentsResolver, + tooltipster: TooltipsterResolver } } ] diff --git a/ui-ngx/src/app/modules/home/pages/edge/edge-tabs.component.html b/ui-ngx/src/app/modules/home/pages/edge/edge-tabs.component.html index 3058522130..615ee09ee1 100644 --- a/ui-ngx/src/app/modules/home/pages/edge/edge-tabs.component.html +++ b/ui-ngx/src/app/modules/home/pages/edge/edge-tabs.component.html @@ -43,7 +43,7 @@ - { ) } ); - this.checkIsNewEdge(entity, form); + this.generateRoutingKeyAndSecret(entity, form); return form; } @@ -100,7 +100,7 @@ export class EdgeComponent extends EntityComponent { description: entity.additionalInfo ? entity.additionalInfo.description : '' } }); - this.checkIsNewEdge(entity, this.entityForm); + this.generateRoutingKeyAndSecret(entity, this.entityForm); } updateFormState() { @@ -109,13 +109,6 @@ export class EdgeComponent extends EntityComponent { this.entityForm.get('secret').disable({emitEvent: false}); } - private checkIsNewEdge(entity: EdgeInfo, form: FormGroup) { - if (entity && !entity.id) { - form.get('routingKey').patchValue(guid(), {emitEvent: false}); - form.get('secret').patchValue(generateSecret(20), {emitEvent: false}); - } - } - onEdgeIdCopied($event) { this.store.dispatch(new ActionNotificationShow( { @@ -139,4 +132,11 @@ export class EdgeComponent extends EntityComponent { horizontalPosition: 'right' })); } + + private generateRoutingKeyAndSecret(entity: EdgeInfo, form: FormGroup) { + if (entity && !entity.id) { + form.get('routingKey').patchValue(guid(), {emitEvent: false}); + form.get('secret').patchValue(generateSecret(20), {emitEvent: false}); + } + } } diff --git a/ui-ngx/src/app/shared/models/edge.models.ts b/ui-ngx/src/app/shared/models/edge.models.ts index 22146a5f76..fd7cb57706 100644 --- a/ui-ngx/src/app/shared/models/edge.models.ts +++ b/ui-ngx/src/app/shared/models/edge.models.ts @@ -59,6 +59,7 @@ export enum EdgeEventType { USER = "USER", CUSTOMER = "CUSTOMER", RELATION = "RELATION", + TENANT = "TENANT", WIDGETS_BUNDLE = "WIDGETS_BUNDLE", WIDGET_TYPE = "WIDGET_TYPE", ADMIN_SETTINGS = "ADMIN_SETTINGS" @@ -105,6 +106,7 @@ export const edgeEventTypeTranslations = new Map( [EdgeEventType.USER, 'edge-event.type-user'], [EdgeEventType.CUSTOMER, 'edge-event.type-customer'], [EdgeEventType.RELATION, 'edge-event.type-relation'], + [EdgeEventType.TENANT, 'edge-event.type-tenant'], [EdgeEventType.WIDGETS_BUNDLE, 'edge-event.type-widgets-bundle'], [EdgeEventType.WIDGET_TYPE, 'edge-event.type-widgets-type'], [EdgeEventType.ADMIN_SETTINGS, 'edge-event.type-admin-settings']