Browse Source

Moved edge downlinks to a separate TAB

pull/3811/head
Volodymyr Babak 6 years ago
parent
commit
6e564de948
  1. 7
      ui-ngx/src/app/core/http/edge.service.ts
  2. 5
      ui-ngx/src/app/core/http/event.service.ts
  3. 253
      ui-ngx/src/app/modules/home/components/edge/edge-downlink-table-config.ts
  4. 19
      ui-ngx/src/app/modules/home/components/edge/edge-downlink-table-header.component.html
  5. 41
      ui-ngx/src/app/modules/home/components/edge/edge-downlink-table-header.component.scss
  6. 42
      ui-ngx/src/app/modules/home/components/edge/edge-downlink-table-header.component.ts
  7. 18
      ui-ngx/src/app/modules/home/components/edge/edge-downlink-table.component.html
  8. 22
      ui-ngx/src/app/modules/home/components/edge/edge-downlink-table.component.scss
  9. 103
      ui-ngx/src/app/modules/home/components/edge/edge-downlink-table.component.ts
  10. 164
      ui-ngx/src/app/modules/home/components/event/event-table-config.ts
  11. 6
      ui-ngx/src/app/modules/home/components/event/event-table.component.ts
  12. 3
      ui-ngx/src/app/modules/home/components/home-components.module.ts
  13. 5
      ui-ngx/src/app/modules/home/pages/edge/edge-tabs.component.html
  14. 1
      ui-ngx/src/app/modules/home/pages/edge/edge.component.ts
  15. 3
      ui-ngx/src/app/modules/home/pages/edge/edge.module.ts
  16. 114
      ui-ngx/src/app/shared/models/edge.models.ts
  17. 42
      ui-ngx/src/app/shared/models/event.models.ts
  18. 38
      ui-ngx/src/assets/locale/locale.constant-en_US.json

7
ui-ngx/src/app/core/http/edge.service.ts

@ -21,9 +21,8 @@ import { HttpClient } from '@angular/common/http';
import { PageLink, TimePageLink } from '@shared/models/page/page-link';
import { PageData } from '@shared/models/page/page-data';
import { EntitySubtype } from '@app/shared/models/entity-type.models';
import { Edge, EdgeInfo, EdgeSearchQuery } from "@shared/models/edge.models";
import { Edge, EdgeEvent, EdgeInfo, EdgeSearchQuery } from "@shared/models/edge.models";
import { EntityId } from "@shared/models/id/entity-id";
import { Event } from "@shared/models/event.models";
@Injectable({
providedIn: 'root'
})
@ -92,8 +91,8 @@ export class EdgeService {
}
public getEdgeEvents(entityId: EntityId, pageLink: TimePageLink,
config?: RequestConfig): Observable<PageData<Event>> {
return this.http.get<PageData<Event>>(`/api/edge/${entityId.id}/events` + `${pageLink.toQuery()}`,
config?: RequestConfig): Observable<PageData<EdgeEvent>> {
return this.http.get<PageData<EdgeEvent>>(`/api/edge/${entityId.id}/events` + `${pageLink.toQuery()}`,
defaultHttpOptionsFromConfig(config));
}
}

5
ui-ngx/src/app/core/http/event.service.ts

@ -39,9 +39,4 @@ export class EventService {
defaultHttpOptionsFromConfig(config));
}
public getEdgeEvents(entityId: EntityId, pageLink: TimePageLink,
config?: RequestConfig): Observable<PageData<Event>> {
return this.http.get<PageData<Event>>(`/api/edge/${entityId.id}/events` + `${pageLink.toQuery()}`,
defaultHttpOptionsFromConfig(config));
}
}

253
ui-ngx/src/app/modules/home/components/edge/edge-downlink-table-config.ts

@ -0,0 +1,253 @@
///
/// 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 {
DateEntityTableColumn,
EntityActionTableColumn,
EntityTableColumn,
EntityTableConfig
} from '@home/models/entity/entities-table-config.models';
import {
EdgeEvent, edgeEventActionTypeTranslations,
EdgeEventStatus,
edgeEventStatusColor,
EdgeEventType,
edgeEventTypeTranslations
} from '@shared/models/edge.models';
import { TimePageLink } from '@shared/models/page/page-link';
import { TranslateService } from '@ngx-translate/core';
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 { PageData } from '@shared/models/page/page-data';
import { Direction } from '@shared/models/page/sort-order';
import { DialogService } from '@core/services/dialog.service';
import { ContentType } from '@shared/models/constants';
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 { actionTypeTranslations } from "@shared/models/audit-log.models";
export class EdgeDownlinkTableConfig extends EntityTableConfig<EdgeEvent, TimePageLink> {
queueStartTs: number;
constructor(private edgeService: EdgeService,
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) {
super();
this.loadDataOnInit = false;
this.tableTitle = '';
this.useTimePageLink = true;
this.detailsPanelEnabled = false;
this.selectionEnabled = false;
this.searchEnabled = false;
this.addEnabled = false;
this.entitiesDeleteEnabled = false;
this.headerComponent = EdgeDownlinkTableHeaderComponent;
this.entityTranslations = {
noEntities: 'edge.no-downlinks-prompt'
};
this.entityResources = {} as EntityTypeResource<EdgeEvent>;
this.entitiesFetchFunction = pageLink => this.fetchEvents(pageLink);
this.defaultSortOrder = {property: 'createdTime', direction: Direction.DESC};
this.updateColumns();
}
fetchEvents(pageLink: TimePageLink): Observable<PageData<EdgeEvent>> {
this.loadEdgeInfo();
return this.edgeService.getEdgeEvents(this.entityId, pageLink);
}
updateColumns(updateTableColumns: boolean = false): void {
this.columns = [];
this.columns.push(
new DateEntityTableColumn<EdgeEvent>('createdTime', 'event.event-time', this.datePipe, '120px'),
new EntityTableColumn<EdgeEvent>('type', 'event.type', '25%',
entity => this.translate.instant(edgeEventTypeTranslations.get(entity.type)), entity => ({}), false),
new EntityTableColumn<EdgeEvent>('action', 'edge.event-action', '25%',
entity => this.translate.instant(edgeEventActionTypeTranslations.get(entity.action)), entity => ({}), false),
new EntityTableColumn<EdgeEvent>('entityId', 'edge.entity-id', '40%',
(entity) => entity.entityId, entity => ({}), false),
new EntityTableColumn<EdgeEvent>('status', 'event.status', '10%',
(entity) => this.updateEdgeEventStatus(entity.createdTime),
entity => ({
color: this.isPending(entity.createdTime) ? edgeEventStatusColor.get(EdgeEventStatus.PENDING) : edgeEventStatusColor.get(EdgeEventStatus.DEPLOYED)
}), false),
new EntityActionTableColumn<EdgeEvent>('data', 'event.data',
{
name: this.translate.instant('action.view'),
icon: 'more_horiz',
isEnabled: (entity) => this.isEdgeEventHasData(entity.type),
onAction: ($event, entity) =>
{
this.prepareEdgeEventContent(entity).subscribe((content) => {
this.showEdgeEventContent($event, content,'event.data');
});
}
},
'40px'),
);
if (updateTableColumns) {
this.table.columnsUpdated(true);
}
}
showContent($event: MouseEvent, content: string, title: string, contentType: ContentType = null, sortKeys = false): void {
if ($event) {
$event.stopPropagation();
}
if (contentType === ContentType.JSON && sortKeys) {
try {
content = JSON.stringify(sortObjectKeys(JSON.parse(content)));
} catch (e) {
}
}
this.dialog.open<EventContentDialogComponent, EventContentDialogData>(EventContentDialogComponent, {
disableClose: true,
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
data: {
content,
title,
contentType
}
});
}
isEdgeEventHasData(edgeEventType: EdgeEventType) {
switch (edgeEventType) {
case EdgeEventType.WIDGET_TYPE:
case EdgeEventType.WIDGETS_BUNDLE:
case EdgeEventType.ADMIN_SETTINGS:
return false;
default:
return true;
}
}
prepareEdgeEventContent(entity) {
// TODO: voba - extend this function with different cases based on action and entity type
switch (entity.type) {
case EdgeEventType.RELATION:
return of(JSON.stringify(entity.body));
case EdgeEventType.ASSET:
return this.assetService.getAsset(entity.entityId, null).pipe(
map((asset) => {
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));
}
}
showEdgeEventContent($event: MouseEvent, content: string, title: string, sortKeys = false): 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, EventContentDialogData>(EventContentDialogComponent, {
disableClose: true,
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
data: {
content,
title,
contentType
}
});
}
updateEdgeEventStatus(createdTime) {
if (this.queueStartTs && createdTime < this.queueStartTs) {
return this.translate.instant('edge.success');
} else {
return this.translate.instant('edge.failed');
}
}
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;
}
}
}

19
ui-ngx/src/app/modules/home/components/edge/edge-downlink-table-header.component.html

@ -0,0 +1,19 @@
<!--
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.
-->
<mat-form-field class="mat-block">
</mat-form-field>

41
ui-ngx/src/app/modules/home/components/edge/edge-downlink-table-header.component.scss

@ -0,0 +1,41 @@
/**
* 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 '../../../../../scss/constants';
:host {
padding-right: 8px;
}
:host ::ng-deep {
mat-form-field {
.mat-form-field-wrapper {
padding-bottom: 0;
}
.mat-form-field-underline {
bottom: 0;
}
@media #{$mat-xs} {
width: 100%;
.mat-form-field-infix {
width: auto !important;
}
}
}
}

42
ui-ngx/src/app/modules/home/components/edge/edge-downlink-table-header.component.ts

@ -0,0 +1,42 @@
///
/// 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 { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { EntityTableHeaderComponent } from '../../components/entity/entity-table-header.component';
import { EdgeEvent } from "@shared/models/edge.models";
import { EdgeDownlinkTableConfig } from "@home/components/edge/edge-downlink-table-config";
@Component({
selector: 'tb-edge-downlink-table-header',
templateUrl: './edge-downlink-table-header.component.html',
styleUrls: ['./edge-downlink-table-header.component.scss']
})
export class EdgeDownlinkTableHeaderComponent extends EntityTableHeaderComponent<EdgeEvent> {
get eventTableConfig(): EdgeDownlinkTableConfig {
return this.entitiesTableConfig as EdgeDownlinkTableConfig;
}
constructor(protected store: Store<AppState>) {
super(store);
}
eventTypeChanged() {
this.eventTableConfig.table.resetSortAndFilter(true, true);
}
}

18
ui-ngx/src/app/modules/home/components/edge/edge-downlink-table.component.html

@ -0,0 +1,18 @@
<!--
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.
-->
<tb-entities-table [entitiesTableConfig]="edgeDownlinkTableConfig"></tb-entities-table>

22
ui-ngx/src/app/modules/home/components/edge/edge-downlink-table.component.scss

@ -0,0 +1,22 @@
/**
* 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 ::ng-deep {
tb-entities-table {
.mat-drawer-container {
background-color: white;
}
}
}

103
ui-ngx/src/app/modules/home/components/edge/edge-downlink-table.component.ts

@ -0,0 +1,103 @@
///
/// 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 { Component, Input, OnInit, ViewChild } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { DatePipe } from '@angular/common';
import { MatDialog } from '@angular/material/dialog';
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";
@Component({
selector: 'tb-edge-downlink-table',
templateUrl: './edge-downlink-table.component.html',
styleUrls: ['./edge-downlink-table.component.scss']
})
export class EdgeDownlinkTableComponent implements OnInit {
@Input()
tenantId: string;
activeValue = false;
dirtyValue = false;
entityIdValue: EntityId;
@Input()
set active(active: boolean) {
if (this.activeValue !== active) {
this.activeValue = active;
if (this.activeValue && this.dirtyValue) {
this.dirtyValue = false;
this.entitiesTable.updateData();
}
}
}
@Input()
set entityId(entityId: EntityId) {
this.entityIdValue = entityId;
if (this.edgeDownlinkTableConfig && this.edgeDownlinkTableConfig.entityId !== entityId) {
this.edgeDownlinkTableConfig.entityId = entityId;
this.entitiesTable.resetSortAndFilter(this.activeValue);
if (!this.activeValue) {
this.dirtyValue = true;
}
}
}
@ViewChild(EntitiesTableComponent, {static: true}) entitiesTable: EntitiesTableComponent;
edgeDownlinkTableConfig: EdgeDownlinkTableConfig;
constructor(private edgeService: EdgeService,
private deviceService: DeviceService,
private assetService: AssetService,
private entityViewService: EntityViewService,
private dialogService: DialogService,
private translate: TranslateService,
private attributeService: AttributeService,
private ruleChainService: RuleChainService,
private datePipe: DatePipe,
private dialog: MatDialog) {
}
ngOnInit() {
this.dirtyValue = !this.activeValue;
this.edgeDownlinkTableConfig = new EdgeDownlinkTableConfig(
this.edgeService,
this.dialogService,
this.translate,
this.deviceService,
this.assetService,
this.entityViewService,
this.ruleChainService,
this.attributeService,
this.datePipe,
this.dialog,
this.entityIdValue,
this.tenantId
);
}
}

164
ui-ngx/src/app/modules/home/components/event/event-table-config.ts

@ -20,35 +20,25 @@ import {
EntityTableColumn,
EntityTableConfig
} from '@home/models/entity/entities-table-config.models';
import {
DebugEventType,
Event,
EventType,
EdgeEventType,
EdgeEventStatus,
edgeEventStatusColor
} from '@shared/models/event.models';
import {TimePageLink} from '@shared/models/page/page-link';
import {TranslateService} from '@ngx-translate/core';
import {DatePipe} from '@angular/common';
import {MatDialog} from '@angular/material/dialog';
import {EntityId} from '@shared/models/id/entity-id';
import {EventService} from '@app/core/http/event.service';
import {EventTableHeaderComponent} from '@home/components/event/event-table-header.component';
import {EntityType, EntityTypeResource} from '@shared/models/entity-type.models';
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';
import {ContentType} from '@shared/models/constants';
import { DebugEventType, Event, EventType } from '@shared/models/event.models';
import { TimePageLink } from '@shared/models/page/page-link';
import { TranslateService } from '@ngx-translate/core';
import { DatePipe } from '@angular/common';
import { MatDialog } from '@angular/material/dialog';
import { EntityId } from '@shared/models/id/entity-id';
import { EventService } from '@app/core/http/event.service';
import { EventTableHeaderComponent } from '@home/components/event/event-table-header.component';
import { EntityTypeResource } from '@shared/models/entity-type.models';
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';
import { ContentType } from '@shared/models/constants';
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 { sortObjectKeys } from '@core/utils';
export class EventTableConfig extends EntityTableConfig<Event, TimePageLink> {
@ -66,13 +56,10 @@ export class EventTableConfig extends EntityTableConfig<Event, TimePageLink> {
}
eventTypes: Array<EventType | DebugEventType>;
queueStartTs: number;
constructor(private eventService: EventService,
private dialogService: DialogService,
private translate: TranslateService,
private ruleChainService: RuleChainService,
private attributeService: AttributeService,
private datePipe: DatePipe,
private dialog: MatDialog,
public entityId: EntityId,
@ -94,10 +81,6 @@ export class EventTableConfig extends EntityTableConfig<Event, TimePageLink> {
this.eventTypes = Object.keys(EventType).map(type => EventType[type]);
if (this.entityId.entityType !== EntityType.EDGE) {
this.eventTypes.pop();
}
if (disabledEventTypes && disabledEventTypes.length) {
this.eventTypes = this.eventTypes.filter(type => disabledEventTypes.indexOf(type) === -1);
}
@ -121,25 +104,15 @@ export class EventTableConfig extends EntityTableConfig<Event, TimePageLink> {
}
fetchEvents(pageLink: TimePageLink): Observable<PageData<Event>> {
if (this.eventTypeValue === EventType.EDGE_EVENT) {
this.loadEdgeInfo();
return this.eventService.getEdgeEvents(this.entityId, pageLink);
} else {
return this.eventService.getEvents(this.entityId, this.eventType, this.tenantId, pageLink);
}
return this.eventService.getEvents(this.entityId, this.eventType, this.tenantId, pageLink);
}
updateColumns(updateTableColumns: boolean = false): void {
this.columns = [];
this.columns.push(
new DateEntityTableColumn<Event>('createdTime', 'event.event-time', this.datePipe, '120px'),
);
if (this.eventType !== EventType.EDGE_EVENT) {
this.columns.push(
new EntityTableColumn<Event>('server', 'event.server', '100px',
(entity) => entity.body.server, entity => ({}), false)
);
}
new EntityTableColumn<Event>('server', 'event.server', '100px',
(entity) => entity.body.server, entity => ({}), false));
switch (this.eventType) {
case EventType.ERROR:
this.columns.push(
@ -186,30 +159,6 @@ export class EventTableConfig extends EntityTableConfig<Event, TimePageLink> {
() => ({}), () => undefined, true)
);
break;
case EventType.EDGE_EVENT:
this.columns.push(
new EntityTableColumn<Event>('type', 'event.type', '100%',
(entity) => entity.type, entity => ({}), false),
new EntityTableColumn<Event>('action', 'edge.event-action', '100%',
(entity) => entity.action, entity => ({}), false),
new EntityTableColumn<Event>('entityId', 'edge.entity-id', '100%',
(entity) => entity.id.id, entity => ({}), false), //TODO: replace this to entity.entityId because of conflict wiht entityId model
new EntityTableColumn<Event>('status', 'event.status', '100%',
(entity) => this.updateEdgeEventStatus(entity.createdTime),
entity => ({
color: this.isPending(entity.createdTime) ? edgeEventStatusColor.get(EdgeEventStatus.PENDING) : edgeEventStatusColor.get(EdgeEventStatus.DEPLOYED)
}), false),
new EntityActionTableColumn<Event>('data', 'event.data',
{
name: this.translate.instant('action.view'),
icon: 'more_horiz',
isEnabled: (entity) => this.checkEdgeEventType(entity),
onAction: ($event, entity) => this.showEdgeEventContent($event, this.manageEdgeEventContent(entity),
'event.data')
},
'40px'),
);
break;
case DebugEventType.DEBUG_RULE_NODE:
case DebugEventType.DEBUG_RULE_CHAIN:
this.columns[0].width = '100px';
@ -300,82 +249,5 @@ export class EventTableConfig extends EntityTableConfig<Event, TimePageLink> {
}
});
}
checkEdgeEventType(entity) {
return !( entity.type === EdgeEventType.WIDGET_TYPE ||
entity.type === EdgeEventType.ADMIN_SETTINGS ||
entity.type === EdgeEventType.WIDGETS_BUNDLE );
}
manageEdgeEventContent(entity) {
var content: string;
switch (entity.type) {
case EdgeEventType.RELATION:
content = entity.body;
break;
// case EdgeEventType.RULE_CHAIN_METADATA:
// this.ruleChainService.getRuleChainMetadata(entity.entityId, null).pipe(
// map(ruleChainMetaData => content = ruleChainMetaData.nodes)
// );
// break;
default:
content = entity;
break;
}
return JSON.stringify(content);
}
showEdgeEventContent($event: MouseEvent, content: string, title: string, sortKeys = false): 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, EventContentDialogData>(EventContentDialogComponent, {
disableClose: true,
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
data: {
content,
title,
contentType
}
});
}
updateEdgeEventStatus(createdTime) {
if (this.queueStartTs && createdTime < this.queueStartTs) {
return this.translate.instant('edge.success');
} else {
return this.translate.instant('edge.failed');
}
}
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;
}
}
}

6
ui-ngx/src/app/modules/home/components/event/event-table.component.ts

@ -24,8 +24,6 @@ import { EventTableConfig } from './event-table-config';
import { EventService } from '@core/http/event.service';
import { DialogService } from '@core/services/dialog.service';
import { DebugEventType, EventType } from '@shared/models/event.models';
import { RuleChainService } from "@core/http/rule-chain.service";
import { AttributeService } from "@core/http/attribute.service";
@Component({
selector: 'tb-event-table',
@ -81,8 +79,6 @@ export class EventTableComponent implements OnInit {
constructor(private eventService: EventService,
private dialogService: DialogService,
private translate: TranslateService,
private attributeService: AttributeService,
private ruleChainService: RuleChainService,
private datePipe: DatePipe,
private dialog: MatDialog) {
}
@ -93,8 +89,6 @@ export class EventTableComponent implements OnInit {
this.eventService,
this.dialogService,
this.translate,
this.ruleChainService,
this.attributeService,
this.datePipe,
this.dialog,
this.entityIdValue,

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

@ -119,6 +119,7 @@ import { SmsProviderConfigurationComponent } from '@home/components/sms/sms-prov
import { AwsSnsProviderConfigurationComponent } from '@home/components/sms/aws-sns-provider-configuration.component';
import { TwilioSmsProviderConfigurationComponent } from '@home/components/sms/twilio-sms-provider-configuration.component';
import { CopyDeviceCredentialsComponent } from '@home/components/device/copy-device-credentials.component';
import {EdgeDownlinkTableComponent} from "@home/components/edge/edge-downlink-table.component";
@NgModule({
declarations:
@ -132,6 +133,7 @@ import { CopyDeviceCredentialsComponent } from '@home/components/device/copy-dev
EventContentDialogComponent,
EventTableHeaderComponent,
EventTableComponent,
EdgeDownlinkTableComponent,
RelationTableComponent,
RelationDialogComponent,
RelationFiltersComponent,
@ -234,6 +236,7 @@ import { CopyDeviceCredentialsComponent } from '@home/components/device/copy-dev
EntityDetailsPanelComponent,
AuditLogTableComponent,
EventTableComponent,
EdgeDownlinkTableComponent,
RelationTableComponent,
RelationFiltersComponent,
AlarmTableComponent,

5
ui-ngx/src/app/modules/home/pages/edge/edge-tabs.component.html

@ -41,6 +41,11 @@
<tb-event-table [defaultEventType]="eventTypes.ERROR" [active]="eventsTab.isActive" [tenantId]="entity.tenantId.id"
[entityId]="entity.id"></tb-event-table>
</mat-tab>
<mat-tab *ngIf="entity"
label="{{ 'edge.downlinks' | translate }}" #downLinksTab="matTab">
<tb-edge-downlink-table [active]="downLinksTab.isActive" [tenantId]="entity.tenantId.id"
[entityId]="entity.id"></tb-edge-downlink-table>
</mat-tab>
<mat-tab *ngIf="entity"
label="{{ 'relation.relations' | translate }}" #relationsTab="matTab">
<tb-relation-table [active]="relationsTab.isActive" [entityId]="entity.id"></tb-relation-table>

1
ui-ngx/src/app/modules/home/pages/edge/edge.component.ts

@ -44,6 +44,7 @@ export class EdgeComponent extends EntityComponent<EdgeInfo> {
@Inject('entity') protected entityValue: EdgeInfo,
@Inject('entitiesTableConfig') protected entitiesTableConfigValue: EntityTableConfig<EdgeInfo>,
public fb: FormBuilder,
// TODO: voba - discuss with Vlad how properly add window to subclass
@Inject(WINDOW) protected window: Window) {
super(store, fb, entityValue, entitiesTableConfigValue, window);
}

3
ui-ngx/src/app/modules/home/pages/edge/edge.module.ts

@ -36,6 +36,9 @@ import { EdgeTabsComponent } from "@home/pages/edge/edge-tabs.component";
HomeDialogsModule,
HomeComponentsModule,
EdgeRoutingModule
],
exports: [
EdgeComponent
]
})

114
ui-ngx/src/app/shared/models/edge.models.ts

@ -20,6 +20,8 @@ import { CustomerId } from '@shared/models/id/customer-id';
import { EdgeId } from '@shared/models/id/edge-id';
import { EntitySearchQuery } from '@shared/models/relation.models';
import { RuleChainId } from "@shared/models/id/rule-chain-id";
import { BaseEventBody } from "@shared/models/event.models";
import { EventId } from "@shared/models/id/event-id";
export interface Edge extends BaseData<EdgeId> {
tenantId?: TenantId;
@ -43,3 +45,115 @@ export interface EdgeInfo extends Edge {
export interface EdgeSearchQuery extends EntitySearchQuery {
edgeTypes: Array<string>;
}
export enum EdgeEventType {
DASHBOARD = "DASHBOARD",
ASSET = "ASSET",
DEVICE = "DEVICE",
DEVICE_PROFILE = "DEVICE_PROFILE",
ENTITY_VIEW = "ENTITY_VIEW",
ALARM = "ALARM",
RULE_CHAIN = "RULE_CHAIN",
RULE_CHAIN_METADATA = "RULE_CHAIN_METADATA",
EDGE = "EDGE",
USER = "USER",
CUSTOMER = "CUSTOMER",
RELATION = "RELATION",
WIDGETS_BUNDLE = "WIDGETS_BUNDLE",
WIDGET_TYPE = "WIDGET_TYPE",
ADMIN_SETTINGS = "ADMIN_SETTINGS"
}
export enum EdgeEventActionType {
ADDED = "ADDED",
DELETED = "DELETED",
UPDATED = "UPDATED",
POST_ATTRIBUTES = "POST_ATTRIBUTES",
ATTRIBUTES_UPDATED = "ATTRIBUTES_UPDATED",
ATTRIBUTES_DELETED = "ATTRIBUTES_DELETED",
TIMESERIES_UPDATED = "TIMESERIES_UPDATED",
CREDENTIALS_UPDATED = "CREDENTIALS_UPDATED",
ASSIGNED_TO_CUSTOMER = "ASSIGNED_TO_CUSTOMER",
UNASSIGNED_FROM_CUSTOMER = "UNASSIGNED_FROM_CUSTOMER",
RELATION_ADD_OR_UPDATE = "RELATION_ADD_OR_UPDATE",
RELATION_DELETED = "RELATION_DELETED",
RPC_CALL = "RPC_CALL",
ALARM_ACK = "ALARM_ACK",
ALARM_CLEAR = "ALARM_CLEAR",
ASSIGNED_TO_EDGE = "ASSIGNED_TO_EDGE",
UNASSIGNED_FROM_EDGE = "UNASSIGNED_FROM_EDGE",
CREDENTIALS_REQUEST = "CREDENTIALS_REQUEST",
ENTITY_MERGE_REQUEST = "ENTITY_MERGE_REQUEST"
}
export enum EdgeEventStatus {
DEPLOYED = "DEPLOYED",
PENDING = "PENDING"
}
export const edgeEventTypeTranslations = new Map<EdgeEventType, string>(
[
[EdgeEventType.DASHBOARD, 'edge.edge-event-type-dashboard'],
[EdgeEventType.ASSET, 'edge.edge-event-type-asset'],
[EdgeEventType.DEVICE, 'edge.edge-event-type-device'],
[EdgeEventType.DEVICE_PROFILE, 'edge.edge-event-type-device-profile'],
[EdgeEventType.ENTITY_VIEW, 'edge.edge-event-type-entity-view'],
[EdgeEventType.ALARM, 'edge.edge-event-type-alarm'],
[EdgeEventType.RULE_CHAIN, 'edge.edge-event-type-rule-chain'],
[EdgeEventType.RULE_CHAIN_METADATA, 'edge.edge-event-type-rule-chain-metadata'],
[EdgeEventType.EDGE, 'edge.edge-event-type-edge'],
[EdgeEventType.USER, 'edge.edge-event-type-user'],
[EdgeEventType.CUSTOMER, 'edge.edge-event-type-customer'],
[EdgeEventType.RELATION, 'edge.edge-event-type-relation'],
[EdgeEventType.WIDGETS_BUNDLE, 'edge.edge-event-type-widgets-bundle'],
[EdgeEventType.WIDGET_TYPE, 'edge.edge-event-type-widgets-type'],
[EdgeEventType.ADMIN_SETTINGS, 'edge.edge-event-type-admin-settings']
]
);
export const edgeEventActionTypeTranslations = new Map<EdgeEventActionType, string>(
[
[EdgeEventActionType.ADDED, 'edge.edge-event-action-type-added'],
[EdgeEventActionType.DELETED, 'edge.edge-event-action-type-deleted'],
[EdgeEventActionType.UPDATED, 'edge.edge-event-action-type-updated'],
[EdgeEventActionType.POST_ATTRIBUTES, 'edge.edge-event-action-type-post-attributes'],
[EdgeEventActionType.ATTRIBUTES_UPDATED, 'edge.edge-event-action-type-attributes-updated'],
[EdgeEventActionType.ATTRIBUTES_DELETED, 'edge.edge-event-action-type-attributes-deleted'],
[EdgeEventActionType.TIMESERIES_UPDATED, 'edge.edge-event-action-type-timeseries-updated'],
[EdgeEventActionType.CREDENTIALS_UPDATED, 'edge.edge-event-action-type-credentials-updated'],
[EdgeEventActionType.ASSIGNED_TO_CUSTOMER, 'edge.edge-event-action-type-assigned-to-customer'],
[EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER, 'edge.edge-event-action-type-unassigned-from-customer'],
[EdgeEventActionType.RELATION_ADD_OR_UPDATE, 'edge.edge-event-action-type-relation-add-or-update'],
[EdgeEventActionType.RELATION_DELETED, 'edge.edge-event-action-type-relation-deleted'],
[EdgeEventActionType.RPC_CALL, 'edge.edge-event-action-type-rpc-call'],
[EdgeEventActionType.ALARM_ACK, 'edge.edge-event-action-type-alarm-ack'],
[EdgeEventActionType.ALARM_CLEAR, 'edge.edge-event-action-type-alarm-clear'],
[EdgeEventActionType.ASSIGNED_TO_EDGE, 'edge.edge-event-action-type-assigned-to-edge'],
[EdgeEventActionType.UNASSIGNED_FROM_EDGE, 'edge.edge-event-action-type-unassigned-from-edge'],
[EdgeEventActionType.CREDENTIALS_REQUEST, 'edge.edge-event-action-type-credentials-request'],
[EdgeEventActionType.ENTITY_MERGE_REQUEST, 'edge.edge-event-action-type-entity-merge-request']
]
);
export const edgeEventStatusColor = new Map<EdgeEventStatus, string>(
[
[EdgeEventStatus.DEPLOYED, '#000000'],
[EdgeEventStatus.PENDING, '#9e9e9e']
]
);
export interface EdgeEventBody extends BaseEventBody {
type: string;
action: string;
entityId: string;
}
export interface EdgeEvent extends BaseData<EventId> {
tenantId: TenantId;
entityId: string;
edgeId: EdgeId;
action: EdgeEventActionType;
type: EdgeEventType;
uid: string;
body: string;
}

42
ui-ngx/src/app/shared/models/event.models.ts

@ -23,8 +23,7 @@ import { ContentType } from '@shared/models/constants';
export enum EventType {
ERROR = 'ERROR',
LC_EVENT = 'LC_EVENT',
STATS = 'STATS',
EDGE_EVENT = 'EDGE_EVENT'
STATS = 'STATS'
}
export enum DebugEventType {
@ -32,41 +31,11 @@ export enum DebugEventType {
DEBUG_RULE_CHAIN = 'DEBUG_RULE_CHAIN'
}
export enum EdgeEventType {
DASHBOARD = "DASHBOARD",
ASSET = "ASSET",
DEVICE = "DEVICE",
ENTITY_VIEW = "ENTITY_VIEW",
ALARM = "ALARM",
RULE_CHAIN = "RULE_CHAIN",
RULE_CHAIN_METADATA = "RULE_CHAIN_METADATA",
EDGE = "EDGE",
USER = "USER",
CUSTOMER = "CUSTOMER",
RELATION = "RELATION",
WIDGETS_BUNDLE = "WIDGETS_BUNDLE",
WIDGET_TYPE = "WIDGET_TYPE",
ADMIN_SETTINGS = "ADMIN_SETTINGS"
}
export enum EdgeEventStatus {
DEPLOYED = "DEPLOYED",
PENDING = "PENDING"
}
export const edgeEventStatusColor = new Map<EdgeEventStatus, string> (
[
[EdgeEventStatus.DEPLOYED, '#000000'],
[EdgeEventStatus.PENDING, '#9e9e9e']
]
);
export const eventTypeTranslations = new Map<EventType | DebugEventType, string>(
[
[EventType.ERROR, 'event.type-error'],
[EventType.LC_EVENT, 'event.type-lc-event'],
[EventType.STATS, 'event.type-stats'],
[EventType.EDGE_EVENT, 'event.type-edge-event'],
[DebugEventType.DEBUG_RULE_NODE, 'event.type-debug-rule-node'],
[DebugEventType.DEBUG_RULE_CHAIN, 'event.type-debug-rule-chain'],
]
@ -92,12 +61,6 @@ export interface StatsEventBody extends BaseEventBody {
errorsOccurred: number;
}
export interface EdgeEventBody extends BaseEventBody {
type: string;
action: string;
entityId: string;
}
export interface DebugRuleNodeEventBody extends BaseEventBody {
type: string;
entityId: string;
@ -111,7 +74,7 @@ export interface DebugRuleNodeEventBody extends BaseEventBody {
error: string;
}
export type EventBody = ErrorEventBody & LcEventEventBody & StatsEventBody & DebugRuleNodeEventBody & EdgeEventBody;
export type EventBody = ErrorEventBody & LcEventEventBody & StatsEventBody & DebugRuleNodeEventBody;
export interface Event extends BaseData<EventId> {
tenantId: TenantId;
@ -119,5 +82,4 @@ export interface Event extends BaseData<EventId> {
type: string;
uid: string;
body: EventBody;
action: string; //TODO: refactor edgeEvents - move parameters to the entity.body
}

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

@ -1203,7 +1203,43 @@
"dashboard": "Edge dashboard",
"enter-edge-type": "Enter edge type",
"deployed": "Deployed",
"pending": "Pending"
"pending": "Pending",
"downlinks": "Downlinks",
"no-downlinks-prompt": "No downlinks found",
"edge-event-type-dashboard": "Dashboard",
"edge-event-type-asset": "Asset",
"edge-event-type-device": "Device",
"edge-event-type-device-profile": "Device Profile",
"edge-event-type-entity-view": "Entity View",
"edge-event-type-alarm": "Alar",
"edge-event-type-rule-chain": "Rule Chain",
"edge-event-type-rule-chain-metadata": "Rule Chain Metadata",
"edge-event-type-edge": "Edge",
"edge-event-type-user": "User",
"edge-event-type-customer": "Customer",
"edge-event-type-relation": "Relation",
"edge-event-type-widgets-bundle": "Widgets Bundle",
"edge-event-type-widgets-type": "Widgets Type",
"edge-event-type-admin-settings": "Admin Settings",
"edge-event-action-type-added": "Added",
"edge-event-action-type-deleted": "Deleted",
"edge-event-action-type-updated": "Updated",
"edge-event-action-type-post-attributes": "Post Attributes",
"edge-event-action-type-attributes-updated": "Attributes Updated",
"edge-event-action-type-attributes-deleted": "Attributes Deleted",
"edge-event-action-type-timeseries-updated": "Timeseries Updated",
"edge-event-action-type-credentials-updated": "Credentials Updated",
"edge-event-action-type-assigned-to-customer": "Assigned to Customer",
"edge-event-action-type-unassigned-from-customer": "Unassigned from Customer",
"edge-event-action-type-relation-add-or-update": "Relation Add or Update",
"edge-event-action-type-relation-deleted": "Relation Deleted",
"edge-event-action-type-rpc-call": "RPC Call",
"edge-event-action-type-alarm-ack": "Alarm Ack",
"edge-event-action-type-alarm-clear": "Alarm Clear",
"edge-event-action-type-assigned-to-edge": "Assigned to Edge",
"edge-event-action-type-unassigned-from-edge": "Unassigned from Edge",
"edge-event-action-type-credentials-request": "Credentials Request",
"edge-event-action-type-entity-merge-request": "Entity Merge Request"
},
"error": {
"unable-to-connect": "Unable to connect to the server! Please check your internet connection.",

Loading…
Cancel
Save