UI: Refactor entities hierarchy widget to use new WS data query API.
This commit is contained in:
parent
2eb7949d57
commit
92c4d00fbb
File diff suppressed because one or more lines are too long
4
ui-ngx/package-lock.json
generated
4
ui-ngx/package-lock.json
generated
@ -8997,10 +8997,10 @@
|
|||||||
"integrity": "sha512-4O3GWAYJaauMCILm07weko2rHA8a4kjn7+8Lg4s1d7SxwS/3IpkVD/GljbRrIJ1c1W/XGJ3GbuK7RyYZEJChhw=="
|
"integrity": "sha512-4O3GWAYJaauMCILm07weko2rHA8a4kjn7+8Lg4s1d7SxwS/3IpkVD/GljbRrIJ1c1W/XGJ3GbuK7RyYZEJChhw=="
|
||||||
},
|
},
|
||||||
"ngx-flowchart": {
|
"ngx-flowchart": {
|
||||||
"version": "git://github.com/thingsboard/ngx-flowchart.git#a4157b0eef2eb3646ef920447c7b06b39d54f87f",
|
"version": "git://github.com/thingsboard/ngx-flowchart.git#7a02f4748b5e7821a883c903107af5f20415d026",
|
||||||
"from": "git://github.com/thingsboard/ngx-flowchart.git#master",
|
"from": "git://github.com/thingsboard/ngx-flowchart.git#master",
|
||||||
"requires": {
|
"requires": {
|
||||||
"tslib": "^1.10.0"
|
"tslib": "^1.13.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": {
|
"tslib": {
|
||||||
|
|||||||
@ -20,7 +20,7 @@ import { Datasource, DatasourceType } from '@app/shared/models/widget.models';
|
|||||||
import { deepClone, isEqual } from '@core/utils';
|
import { deepClone, isEqual } from '@core/utils';
|
||||||
import { EntityService } from '@core/http/entity.service';
|
import { EntityService } from '@core/http/entity.service';
|
||||||
import { UtilsService } from '@core/services/utils.service';
|
import { UtilsService } from '@core/services/utils.service';
|
||||||
import { EntityAliases } from '@shared/models/alias.models';
|
import { AliasFilterType, EntityAliases, SingleEntityFilter } from '@shared/models/alias.models';
|
||||||
import { EntityInfo } from '@shared/models/entity.models';
|
import { EntityInfo } from '@shared/models/entity.models';
|
||||||
import { map, mergeMap } from 'rxjs/operators';
|
import { map, mergeMap } from 'rxjs/operators';
|
||||||
import {
|
import {
|
||||||
@ -282,6 +282,15 @@ export class AliasController implements IAliasController {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
} else if (newDatasource.entityId && !newDatasource.entityFilter) {
|
||||||
|
newDatasource.entityFilter = {
|
||||||
|
singleEntity: {
|
||||||
|
id: newDatasource.entityId,
|
||||||
|
entityType: newDatasource.entityType,
|
||||||
|
},
|
||||||
|
type: AliasFilterType.singleEntity
|
||||||
|
} as SingleEntityFilter;
|
||||||
|
return of(newDatasource);
|
||||||
} else {
|
} else {
|
||||||
newDatasource.aliasName = newDatasource.entityName;
|
newDatasource.aliasName = newDatasource.entityName;
|
||||||
newDatasource.name = newDatasource.entityName;
|
newDatasource.name = newDatasource.entityName;
|
||||||
|
|||||||
@ -23,19 +23,18 @@ import { DatasourceData, DatasourceType, WidgetConfig, widgetType } from '@share
|
|||||||
import { IWidgetSubscription, WidgetSubscriptionOptions } from '@core/api/widget-api.models';
|
import { IWidgetSubscription, WidgetSubscriptionOptions } from '@core/api/widget-api.models';
|
||||||
import { UtilsService } from '@core/services/utils.service';
|
import { UtilsService } from '@core/services/utils.service';
|
||||||
import cssjs from '@core/css/css';
|
import cssjs from '@core/css/css';
|
||||||
import { forkJoin, fromEvent, Observable, of } from 'rxjs';
|
import { fromEvent } from 'rxjs';
|
||||||
import { catchError, debounceTime, distinctUntilChanged, map, mergeMap, tap } from 'rxjs/operators';
|
import { debounceTime, distinctUntilChanged, tap } from 'rxjs/operators';
|
||||||
import { constructTableCssString } from '@home/components/widget/lib/table-widget.models';
|
import { constructTableCssString } from '@home/components/widget/lib/table-widget.models';
|
||||||
import { Overlay } from '@angular/cdk/overlay';
|
import { Overlay } from '@angular/cdk/overlay';
|
||||||
import {
|
import {
|
||||||
LoadNodesCallback,
|
LoadNodesCallback,
|
||||||
NavTreeEditCallbacks,
|
NavTreeEditCallbacks,
|
||||||
|
NodesCallback,
|
||||||
NodeSearchCallback,
|
NodeSearchCallback,
|
||||||
NodeSelectedCallback,
|
NodeSelectedCallback,
|
||||||
NodesInsertedCallback
|
NodesInsertedCallback
|
||||||
} from '@shared/components/nav-tree.component';
|
} from '@shared/components/nav-tree.component';
|
||||||
import { BaseData } from '@shared/models/base-data';
|
|
||||||
import { EntityId } from '@shared/models/id/entity-id';
|
|
||||||
import { EntityType } from '@shared/models/entity-type.models';
|
import { EntityType } from '@shared/models/entity-type.models';
|
||||||
import { deepClone, hashCode } from '@core/utils';
|
import { deepClone, hashCode } from '@core/utils';
|
||||||
import {
|
import {
|
||||||
@ -58,10 +57,9 @@ import {
|
|||||||
NodesSortFunction,
|
NodesSortFunction,
|
||||||
NodeTextFunction
|
NodeTextFunction
|
||||||
} from '@home/components/widget/lib/entities-hierarchy-widget.models';
|
} from '@home/components/widget/lib/entities-hierarchy-widget.models';
|
||||||
import { EntityService } from '@core/http/entity.service';
|
import { EntityRelationsQuery } from '@shared/models/relation.models';
|
||||||
import { EntityRelationsQuery, EntitySearchDirection } from '@shared/models/relation.models';
|
import { AliasFilterType, RelationsQueryFilter } from '@shared/models/alias.models';
|
||||||
import { EntityRelationService } from '@core/http/entity-relation.service';
|
import { EntityFilter } from '@shared/models/query/query.models';
|
||||||
import { ActionNotificationShow } from '@core/notification/notification.actions';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-entities-hierarchy-widget',
|
selector: 'tb-entities-hierarchy-widget',
|
||||||
@ -86,6 +84,7 @@ export class EntitiesHierarchyWidgetComponent extends PageComponent implements O
|
|||||||
private widgetConfig: WidgetConfig;
|
private widgetConfig: WidgetConfig;
|
||||||
private subscription: IWidgetSubscription;
|
private subscription: IWidgetSubscription;
|
||||||
private datasources: Array<HierarchyNodeDatasource>;
|
private datasources: Array<HierarchyNodeDatasource>;
|
||||||
|
private data: Array<Array<DatasourceData>>;
|
||||||
|
|
||||||
private nodesMap: {[nodeId: string]: HierarchyNavTreeNode} = {};
|
private nodesMap: {[nodeId: string]: HierarchyNavTreeNode} = {};
|
||||||
private pendingUpdateNodeTasks: {[nodeId: string]: () => void} = {};
|
private pendingUpdateNodeTasks: {[nodeId: string]: () => void} = {};
|
||||||
@ -108,14 +107,11 @@ export class EntitiesHierarchyWidgetComponent extends PageComponent implements O
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
constructor(protected store: Store<AppState>,
|
constructor(protected store: Store<AppState>,
|
||||||
private elementRef: ElementRef,
|
private elementRef: ElementRef,
|
||||||
private overlay: Overlay,
|
private overlay: Overlay,
|
||||||
private viewContainerRef: ViewContainerRef,
|
private viewContainerRef: ViewContainerRef,
|
||||||
private utils: UtilsService,
|
private utils: UtilsService) {
|
||||||
private entityService: EntityService,
|
|
||||||
private entityRelationService: EntityRelationService) {
|
|
||||||
super(store);
|
super(store);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,6 +121,7 @@ export class EntitiesHierarchyWidgetComponent extends PageComponent implements O
|
|||||||
this.widgetConfig = this.ctx.widgetConfig;
|
this.widgetConfig = this.ctx.widgetConfig;
|
||||||
this.subscription = this.ctx.defaultSubscription;
|
this.subscription = this.ctx.defaultSubscription;
|
||||||
this.datasources = this.subscription.datasources as Array<HierarchyNodeDatasource>;
|
this.datasources = this.subscription.datasources as Array<HierarchyNodeDatasource>;
|
||||||
|
this.data = this.subscription.dataPages[0].data;
|
||||||
this.initializeConfig();
|
this.initializeConfig();
|
||||||
this.ctx.updateWidgetParams();
|
this.ctx.updateWidgetParams();
|
||||||
}
|
}
|
||||||
@ -254,33 +251,15 @@ export class EntitiesHierarchyWidgetComponent extends PageComponent implements O
|
|||||||
|
|
||||||
public loadNodes: LoadNodesCallback = (node, cb) => {
|
public loadNodes: LoadNodesCallback = (node, cb) => {
|
||||||
if (node.id === '#') {
|
if (node.id === '#') {
|
||||||
const tasks: Observable<HierarchyNavTreeNode>[] = [];
|
const childNodes: HierarchyNavTreeNode[] = [];
|
||||||
this.datasources.forEach((datasource) => {
|
this.datasources.forEach((childDatasource, index) => {
|
||||||
tasks.push(this.datasourceToNode(datasource));
|
childNodes.push(this.datasourceToNode(childDatasource as HierarchyNodeDatasource, this.data[index]));
|
||||||
});
|
|
||||||
forkJoin(tasks).subscribe((nodes) => {
|
|
||||||
cb(this.prepareNodes(nodes));
|
|
||||||
this.updateNodeData(this.subscription.data);
|
|
||||||
});
|
});
|
||||||
|
cb(this.prepareNodes(childNodes));
|
||||||
} else {
|
} else {
|
||||||
if (node.data && node.data.nodeCtx.entity && node.data.nodeCtx.entity.id && node.data.nodeCtx.entity.id.entityType !== 'function') {
|
if (node.data && node.data.nodeCtx.entity && node.data.nodeCtx.entity.id && node.data.nodeCtx.entity.id.entityType !== 'function') {
|
||||||
const relationQuery = this.prepareNodeRelationQuery(node.data.nodeCtx);
|
this.loadChildren(node, node.data.datasource, cb);
|
||||||
this.entityRelationService.findByQuery(relationQuery, {ignoreErrors: true, ignoreLoading: true}).subscribe(
|
/* (error) => { // TODO:
|
||||||
(entityRelations) => {
|
|
||||||
if (entityRelations.length) {
|
|
||||||
const tasks: Observable<HierarchyNavTreeNode>[] = [];
|
|
||||||
entityRelations.forEach((relation) => {
|
|
||||||
const targetId = relationQuery.parameters.direction === EntitySearchDirection.FROM ? relation.to : relation.from;
|
|
||||||
tasks.push(this.entityIdToNode(targetId.entityType as EntityType, targetId.id, node.data.datasource, node.data.nodeCtx));
|
|
||||||
});
|
|
||||||
forkJoin(tasks).subscribe((nodes) => {
|
|
||||||
cb(this.prepareNodes(nodes));
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
cb([]);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
let errorText = 'Failed to get relations!';
|
let errorText = 'Failed to get relations!';
|
||||||
if (error && error.status === 400) {
|
if (error && error.status === 400) {
|
||||||
errorText = 'Invalid relations query returned by \'Node relations query function\'! Please check widget configuration!';
|
errorText = 'Invalid relations query returned by \'Node relations query function\'! Please check widget configuration!';
|
||||||
@ -288,6 +267,7 @@ export class EntitiesHierarchyWidgetComponent extends PageComponent implements O
|
|||||||
this.showError(errorText);
|
this.showError(errorText);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
*/
|
||||||
} else {
|
} else {
|
||||||
cb([]);
|
cb([]);
|
||||||
}
|
}
|
||||||
@ -313,7 +293,7 @@ export class EntitiesHierarchyWidgetComponent extends PageComponent implements O
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public onNodesInserted: NodesInsertedCallback = (nodes, parent) => {
|
public onNodesInserted: NodesInsertedCallback = (nodes) => {
|
||||||
if (nodes) {
|
if (nodes) {
|
||||||
nodes.forEach((nodeId) => {
|
nodes.forEach((nodeId) => {
|
||||||
const task = this.pendingUpdateNodeTasks[nodeId];
|
const task = this.pendingUpdateNodeTasks[nodeId];
|
||||||
@ -355,17 +335,6 @@ export class EntitiesHierarchyWidgetComponent extends PageComponent implements O
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private showError(errorText: string) {
|
|
||||||
this.store.dispatch(new ActionNotificationShow(
|
|
||||||
{
|
|
||||||
message: errorText,
|
|
||||||
type: 'error',
|
|
||||||
target: this.toastTargetId,
|
|
||||||
verticalPosition: 'bottom',
|
|
||||||
horizontalPosition: 'left'
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
private prepareNodes(nodes: HierarchyNavTreeNode[]): HierarchyNavTreeNode[] {
|
private prepareNodes(nodes: HierarchyNavTreeNode[]): HierarchyNavTreeNode[] {
|
||||||
nodes = nodes.filter((node) => node !== null);
|
nodes = nodes.filter((node) => node !== null);
|
||||||
nodes.sort((node1, node2) => this.nodesSortFunction(node1.data.nodeCtx, node2.data.nodeCtx));
|
nodes.sort((node1, node2) => this.nodesSortFunction(node1.data.nodeCtx, node2.data.nodeCtx));
|
||||||
@ -399,10 +368,9 @@ export class EntitiesHierarchyWidgetComponent extends PageComponent implements O
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private datasourceToNode(datasource: HierarchyNodeDatasource, parentNodeCtx?: HierarchyNodeContext): Observable<HierarchyNavTreeNode> {
|
private datasourceToNode(datasource: HierarchyNodeDatasource,
|
||||||
return this.resolveEntity(datasource).pipe(
|
data: DatasourceData[],
|
||||||
map(entity => {
|
parentNodeCtx?: HierarchyNodeContext): HierarchyNavTreeNode {
|
||||||
if (entity !== null) {
|
|
||||||
const node: HierarchyNavTreeNode = {
|
const node: HierarchyNavTreeNode = {
|
||||||
id: (++this.nodeIdCounter) + ''
|
id: (++this.nodeIdCounter) + ''
|
||||||
};
|
};
|
||||||
@ -411,9 +379,24 @@ export class EntitiesHierarchyWidgetComponent extends PageComponent implements O
|
|||||||
node.icon = false;
|
node.icon = false;
|
||||||
const nodeCtx: HierarchyNodeContext = {
|
const nodeCtx: HierarchyNodeContext = {
|
||||||
parentNodeCtx,
|
parentNodeCtx,
|
||||||
entity,
|
entity: {
|
||||||
|
id: {
|
||||||
|
id: datasource.entityId,
|
||||||
|
entityType: datasource.entityType
|
||||||
|
},
|
||||||
|
name: datasource.entityName,
|
||||||
|
label: datasource.entityLabel ? datasource.entityLabel : datasource.entityName
|
||||||
|
},
|
||||||
data: {}
|
data: {}
|
||||||
};
|
};
|
||||||
|
datasource.dataKeys.forEach((dataKey, index) => {
|
||||||
|
const keyData = data[index].data;
|
||||||
|
if (keyData && keyData.length && keyData[0].length > 1) {
|
||||||
|
nodeCtx.data[dataKey.label] = keyData[0][1];
|
||||||
|
} else {
|
||||||
|
nodeCtx.data[dataKey.label] = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
nodeCtx.level = parentNodeCtx ? parentNodeCtx.level + 1 : 1;
|
nodeCtx.level = parentNodeCtx ? parentNodeCtx.level + 1 : 1;
|
||||||
node.data = {
|
node.data = {
|
||||||
datasource,
|
datasource,
|
||||||
@ -426,59 +409,47 @@ export class EntitiesHierarchyWidgetComponent extends PageComponent implements O
|
|||||||
node.text = this.prepareNodeText(node);
|
node.text = this.prepareNodeText(node);
|
||||||
node.children = this.nodeHasChildrenFunction(node.data.nodeCtx);
|
node.children = this.nodeHasChildrenFunction(node.data.nodeCtx);
|
||||||
return node;
|
return node;
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private entityIdToNode(entityType: EntityType, entityId: string,
|
private loadChildren(parentNode: HierarchyNavTreeNode, datasource: HierarchyNodeDatasource, childrenNodesLoadCb: NodesCallback) {
|
||||||
parentDatasource: HierarchyNodeDatasource,
|
const nodeCtx = parentNode.data.nodeCtx;
|
||||||
parentNodeCtx: HierarchyNodeContext): Observable<HierarchyNavTreeNode> {
|
nodeCtx.childrenNodesLoaded = false;
|
||||||
const datasource = {
|
const entityFilter = this.prepareNodeRelationsQueryFilter(nodeCtx);
|
||||||
dataKeys: parentDatasource.dataKeys,
|
const childrenDatasource = {
|
||||||
|
dataKeys: datasource.dataKeys,
|
||||||
type: DatasourceType.entity,
|
type: DatasourceType.entity,
|
||||||
entityType,
|
entityFilter
|
||||||
entityId
|
|
||||||
} as HierarchyNodeDatasource;
|
} as HierarchyNodeDatasource;
|
||||||
return this.datasourceToNode(datasource, parentNodeCtx).pipe(
|
|
||||||
mergeMap((node) => {
|
|
||||||
if (node != null) {
|
|
||||||
const subscriptionOptions: WidgetSubscriptionOptions = {
|
const subscriptionOptions: WidgetSubscriptionOptions = {
|
||||||
type: widgetType.latest,
|
type: widgetType.latest,
|
||||||
datasources: [datasource],
|
datasources: [childrenDatasource],
|
||||||
callbacks: {
|
callbacks: {
|
||||||
onDataUpdated: subscription => {
|
onSubscriptionMessage: (subscription, message) => {
|
||||||
this.updateNodeData(subscription.data);
|
this.ctx.showToast(message.severity, message.message, undefined,
|
||||||
}
|
'bottom', 'left', this.toastTargetId);
|
||||||
}
|
|
||||||
};
|
|
||||||
return this.ctx.subscriptionApi.
|
|
||||||
createSubscription(subscriptionOptions, true).pipe(
|
|
||||||
map(() => node));
|
|
||||||
} else {
|
|
||||||
return of(node);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private resolveEntity(datasource: HierarchyNodeDatasource): Observable<BaseData<EntityId>> {
|
|
||||||
if (datasource.type === DatasourceType.function) {
|
|
||||||
const entity = {
|
|
||||||
id: {
|
|
||||||
entityType: 'function'
|
|
||||||
},
|
},
|
||||||
name: datasource.name
|
onInitialPageDataChanged: (subscription) => {
|
||||||
};
|
this.ctx.subscriptionApi.removeSubscription(subscription.id);
|
||||||
return of(entity as BaseData<EntityId>);
|
this.nodeEditCallbacks.refreshNode(parentNode.id);
|
||||||
|
},
|
||||||
|
onDataUpdated: subscription => {
|
||||||
|
if (nodeCtx.childrenNodesLoaded) {
|
||||||
|
this.updateNodeData(subscription.data);
|
||||||
} else {
|
} else {
|
||||||
return this.entityService.getEntity(datasource.entityType, datasource.entityId, {ignoreLoading: true}).pipe(
|
const datasourcesPageData = subscription.datasourcePages[0];
|
||||||
catchError(err => of(null))
|
const dataPageData = subscription.dataPages[0];
|
||||||
);
|
const childNodes: HierarchyNavTreeNode[] = [];
|
||||||
|
datasourcesPageData.data.forEach((childDatasource, index) => {
|
||||||
|
childNodes.push(this.datasourceToNode(childDatasource as HierarchyNodeDatasource, dataPageData.data[index]));
|
||||||
|
});
|
||||||
|
nodeCtx.childrenNodesLoaded = true;
|
||||||
|
childrenNodesLoadCb(this.prepareNodes(childNodes));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.ctx.subscriptionApi.createSubscription(subscriptionOptions, true);
|
||||||
|
}
|
||||||
|
|
||||||
private prepareNodeRelationQuery(nodeCtx: HierarchyNodeContext): EntityRelationsQuery {
|
private prepareNodeRelationQuery(nodeCtx: HierarchyNodeContext): EntityRelationsQuery {
|
||||||
let relationQuery = this.nodeRelationQueryFunction(nodeCtx);
|
let relationQuery = this.nodeRelationQueryFunction(nodeCtx);
|
||||||
@ -487,4 +458,19 @@ export class EntitiesHierarchyWidgetComponent extends PageComponent implements O
|
|||||||
}
|
}
|
||||||
return relationQuery as EntityRelationsQuery;
|
return relationQuery as EntityRelationsQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private prepareNodeRelationsQueryFilter(nodeCtx: HierarchyNodeContext): EntityFilter {
|
||||||
|
const relationQuery = this.prepareNodeRelationQuery(nodeCtx);
|
||||||
|
return {
|
||||||
|
rootEntity: {
|
||||||
|
id: relationQuery.parameters.rootId,
|
||||||
|
entityType: relationQuery.parameters.rootType
|
||||||
|
},
|
||||||
|
direction: relationQuery.parameters.direction,
|
||||||
|
filters: relationQuery.filters,
|
||||||
|
maxLevel: relationQuery.parameters.maxLevel,
|
||||||
|
fetchLastLevelOnly: relationQuery.parameters.fetchLastLevelOnly,
|
||||||
|
type: AliasFilterType.relationsQuery
|
||||||
|
} as RelationsQueryFilter;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
import { BaseData } from '@shared/models/base-data';
|
import { BaseData } from '@shared/models/base-data';
|
||||||
import { EntityId } from '@shared/models/id/entity-id';
|
import { EntityId } from '@shared/models/id/entity-id';
|
||||||
import { NavTreeNode } from '@shared/components/nav-tree.component';
|
import { NavTreeNode, NodesCallback } from '@shared/components/nav-tree.component';
|
||||||
import { Datasource } from '@shared/models/widget.models';
|
import { Datasource } from '@shared/models/widget.models';
|
||||||
import { isDefined, isUndefined } from '@core/utils';
|
import { isDefined, isUndefined } from '@core/utils';
|
||||||
import { EntityRelationsQuery, EntitySearchDirection, RelationTypeGroup } from '@shared/models/relation.models';
|
import { EntityRelationsQuery, EntitySearchDirection, RelationTypeGroup } from '@shared/models/relation.models';
|
||||||
@ -35,6 +35,7 @@ export interface EntitiesHierarchyWidgetSettings {
|
|||||||
export interface HierarchyNodeContext {
|
export interface HierarchyNodeContext {
|
||||||
parentNodeCtx?: HierarchyNodeContext;
|
parentNodeCtx?: HierarchyNodeContext;
|
||||||
entity: BaseData<EntityId>;
|
entity: BaseData<EntityId>;
|
||||||
|
childrenNodesLoaded?: boolean;
|
||||||
level?: number;
|
level?: number;
|
||||||
data: {[key: string]: any};
|
data: {[key: string]: any};
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user