Moved edge downlinks to a separate TAB

This commit is contained in:
Volodymyr Babak 2020-12-22 19:21:06 +02:00
parent c89849c38d
commit 6e564de948
18 changed files with 684 additions and 202 deletions

View File

@ -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));
}
}

View File

@ -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));
}
}

View File

@ -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;
}
}
}

View File

@ -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>

View File

@ -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;
}
}
}
}

View File

@ -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);
}
}

View File

@ -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>

View File

@ -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;
}
}
}

View File

@ -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
);
}
}

View File

@ -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;
}
}
}

View File

@ -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,

View File

@ -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,

View File

@ -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>

View File

@ -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);
}

View File

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

View File

@ -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;
}

View File

@ -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
}

View File

@ -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.",