[CORD-1250] Rendering new ServiceInstance Models
Change-Id: Ic8fdb4775b119816b4b7aa085e6af699eaa13a67
diff --git a/src/app/core/services/helpers/config.helpers.ts b/src/app/core/services/helpers/config.helpers.ts
index c495ba5..b49b27c 100644
--- a/src/app/core/services/helpers/config.helpers.ts
+++ b/src/app/core/services/helpers/config.helpers.ts
@@ -73,7 +73,7 @@
pluralize.addPluralRule(/library$/i, 'librarys');
pluralize.addPluralRule(/imagedeployments/i, 'imagedeploymentses');
pluralize.addPluralRule(/controllerimages/i, 'controllerimageses');
- pluralize.addPluralRule(/servicedependency/i, 'servicedependencys');
+ pluralize.addPluralRule(/servicedependency/i, 'servicedependencies');
}
public pluralize(string: string, quantity?: number, count?: boolean): string {
diff --git a/src/app/service-graph/components/coarse/coarse.component.ts b/src/app/service-graph/components/coarse/coarse.component.ts
index ac687d0..501c543 100644
--- a/src/app/service-graph/components/coarse/coarse.component.ts
+++ b/src/app/service-graph/components/coarse/coarse.component.ts
@@ -2,7 +2,7 @@
import * as d3 from 'd3';
import * as $ from 'jquery';
import * as _ from 'lodash';
-import {IXosServiceGraphStore} from '../../services/graph.store';
+import {IXosServiceGraphStore} from '../../services/service-graph.store';
import {IXosServiceGraph, IXosServiceGraphNode, IXosServiceGraphLink} from '../../interfaces';
import {XosServiceGraphConfig as config} from '../../graph.config';
import {IXosDebouncer} from '../../../core/services/helpers/debounce.helper';
@@ -177,6 +177,7 @@
const entering = node.enter()
.append('g')
.attr({
+ id: n => n.id,
class: n => `node ${this.XosGraphHelpers.parseElemClasses(n.d3Class)}`,
transform: `translate(${svgDim.width / 2}, ${svgDim.height / 2})`
})
@@ -232,6 +233,7 @@
entering.append('line')
.attr({
+ id: n => n.id,
class: l => `link ${this.XosGraphHelpers.parseElemClasses(l.d3Class)}`,
'marker-start': 'url(#arrow)'
});
diff --git a/src/app/service-graph/components/fine-grained/fine-grained.component.scss b/src/app/service-graph/components/fine-grained/fine-grained.component.scss
index c7fcfbc..37605f9 100644
--- a/src/app/service-graph/components/fine-grained/fine-grained.component.scss
+++ b/src/app/service-graph/components/fine-grained/fine-grained.component.scss
@@ -41,7 +41,7 @@
stroke: blue;
}
- &.tenant > rect{
+ &.tenant, &.serviceinstance > rect{
stroke: green;
}
@@ -60,6 +60,15 @@
.link-group {
line {
stroke: $color-accent;
+
+ &.ext-service-instance {
+ stroke: green;
+ }
+
+ &.ext-owner {
+ stroke: green;
+ stroke-dasharray: 5;
+ }
}
}
.arrow-marker {
diff --git a/src/app/service-graph/components/fine-grained/fine-grained.component.ts b/src/app/service-graph/components/fine-grained/fine-grained.component.ts
index 3fc47a5..6d57aad 100644
--- a/src/app/service-graph/components/fine-grained/fine-grained.component.ts
+++ b/src/app/service-graph/components/fine-grained/fine-grained.component.ts
@@ -1,4 +1,3 @@
-import {IXosServiceGraphStore} from '../../services/graph.store';
import './fine-grained.component.scss';
import * as d3 from 'd3';
import * as $ from 'jquery';
@@ -11,11 +10,12 @@
import {IXosSidePanelService} from '../../../core/side-panel/side-panel.service';
import {IXosGraphHelpers} from '../../services/d3-helpers/graph.helpers';
import {IXosServiceGraphExtender, IXosServiceGraphReducer} from '../../services/graph.extender';
+import {IXosServiceInstanceGraphStore} from '../../services/service-instance.graph.store';
class XosFineGrainedTenancyGraphCtrl {
static $inject = [
'$log',
- 'XosServiceGraphStore',
+ 'XosServiceInstanceGraphStore',
'XosDebouncer',
'XosModelDiscoverer',
'XosSidePanel',
@@ -39,7 +39,7 @@
constructor(
private $log: ng.ILogService,
- private XosServiceGraphStore: IXosServiceGraphStore,
+ private XosServiceInstanceGraphStore: IXosServiceInstanceGraphStore,
private XosDebouncer: IXosDebouncer,
private XosModelDiscoverer: IXosModelDiscovererService,
private XosSidePanel: IXosSidePanelService,
@@ -56,10 +56,10 @@
this.renderGraph();
});
- this.GraphSubscription = this.XosServiceGraphStore.get()
+ this.GraphSubscription = this.XosServiceInstanceGraphStore.get()
.subscribe(
(graph) => {
- this.$log.debug(`[XosFineGrainedTenancyGraphCtrl] Fine-Grained Event and render`, graph);
+ this.$log.debug(`[XosServiceInstanceGraphStore] Fine-Grained Event and render`, graph);
if (!graph || !graph.nodes || !graph.links) {
return;
@@ -159,9 +159,6 @@
});
};
const getLinkStrenght = (l: IXosServiceGraphLink) => {
- if (l.id.indexOf('service') > -1) {
- return 0.1;
- }
return 1;
};
const svgDim = this.getSvgDimensions();
@@ -311,6 +308,7 @@
const entering = node.enter()
.append('g')
.attr({
+ id: n => n.id,
class: n => `node ${n.type} ${this.XosGraphHelpers.parseElemClasses(n.d3Class)}`,
transform: (n, i) => `translate(${hStep * i}, ${vStep * i})`
})
@@ -343,10 +341,10 @@
});
this.renderServiceNodes(entering.filter('.service'));
- this.renderTenantNodes(entering.filter('.tenant'));
+ this.renderTenantNodes(entering.filter('.serviceinstance'));
this.renderNetworkNodes(entering.filter('.network'));
this.renderSubscriberNodes(entering.filter('.subscriber'));
- this.renderSubscriberNodes(entering.filter('.tenantroot'));
+ // this.renderSubscriberNodes(entering.filter('.tenantroot'));
}
private renderLinks(links: IXosServiceGraphLink[]) {
@@ -358,6 +356,7 @@
entering.append('line')
.attr({
+ id: n => n.id,
class: n => `link ${this.XosGraphHelpers.parseElemClasses(n.d3Class)}`,
'marker-start': 'url(#arrow)'
});
diff --git a/src/app/service-graph/index.ts b/src/app/service-graph/index.ts
index 00cf9e8..0786592 100644
--- a/src/app/service-graph/index.ts
+++ b/src/app/service-graph/index.ts
@@ -1,15 +1,17 @@
import {xosDataSources} from '../datasources/index';
-import {XosServiceGraphStore} from './services/graph.store';
+import {XosServiceGraphStore} from './services/service-graph.store';
import {xosCore} from '../core/index';
import {XosCoarseTenancyGraph} from './components/coarse/coarse.component';
import {XosFineGrainedTenancyGraph} from './components/fine-grained/fine-grained.component';
import {XosServiceGraphExtender, IXosServiceGraphExtender} from './services/graph.extender';
import {XosGraphHelpers} from './services/d3-helpers/graph.helpers';
+import {XosServiceInstanceGraphStore} from './services/service-instance.graph.store';
export const xosServiceGraph = 'xosServiceGraph';
angular
.module(xosServiceGraph, [xosDataSources, xosCore])
.service('XosServiceGraphStore', XosServiceGraphStore)
+ .service('XosServiceInstanceGraphStore', XosServiceInstanceGraphStore)
.service('XosServiceGraphExtender', XosServiceGraphExtender)
.service('XosGraphHelpers', XosGraphHelpers)
.component('xosCoarseTenancyGraph', XosCoarseTenancyGraph)
diff --git a/src/app/service-graph/interfaces.ts b/src/app/service-graph/interfaces.ts
index 4120bdb..a7e41f1 100644
--- a/src/app/service-graph/interfaces.ts
+++ b/src/app/service-graph/interfaces.ts
@@ -41,15 +41,23 @@
export interface IXosCoarseGraphData {
services: IXosServiceModel[];
- servicedependencys: any[];
+ servicedependencies: any[];
}
+// TODO outdated, remove
export interface IXosFineGrainedGraphData extends IXosCoarseGraphData {
tenants: IXosTenantModel[];
subscribers: any[];
networks: any[];
}
+export interface IXosServiceInstanceGraphData {
+ serviceGraph: IXosServiceGraph;
+ serviceInstances: any[];
+ serviceInstanceLinks: any[];
+ networks: any[];
+}
+
export interface IXosServiceGraphNodeBadge {
type: 'info'|'success'|'warning'|'danger';
text: string;
diff --git a/src/app/service-graph/services/graph.store.ts b/src/app/service-graph/services/graph.store.ts
deleted file mode 100644
index 7c6e552..0000000
--- a/src/app/service-graph/services/graph.store.ts
+++ /dev/null
@@ -1,324 +0,0 @@
-import * as _ from 'lodash';
-import {Observable, BehaviorSubject, Subscription} from 'rxjs';
-import {IXosModelStoreService} from '../../datasources/stores/model.store';
-import {
- IXosServiceGraph, IXosServiceModel, IXosTenantModel, IXosCoarseGraphData,
- IXosServiceGraphNode, IXosServiceGraphLink, IXosFineGrainedGraphData
-} from '../interfaces';
-import {IXosDebouncer} from '../../core/services/helpers/debounce.helper';
-export interface IXosServiceGraphStore {
- get(): Observable<IXosServiceGraph>;
- getCoarse(): Observable<IXosServiceGraph>;
-}
-
-export class XosServiceGraphStore implements IXosServiceGraphStore {
- static $inject = [
- '$log',
- 'XosModelStore',
- 'XosDebouncer'
- ];
-
- // graph data store
- private graphData: BehaviorSubject<IXosFineGrainedGraphData> = new BehaviorSubject({
- services: [],
- tenants: [],
- networks: [],
- subscribers: [],
- servicedependencys: []
- });
-
- private emptyGraph: IXosServiceGraph = {
- nodes: [],
- links: []
- };
-
- // representation of the graph as D3 requires
- private d3CoarseGraph = new BehaviorSubject(this.emptyGraph);
- private d3FineGrainedGraph = new BehaviorSubject(this.emptyGraph);
-
- // storing locally reference to the data model
- private services;
- private tenants;
- private subscribers;
- private networks;
- private servicedependencys;
-
- // debounced functions
- private handleData;
-
- // datastore
- private ServiceSubscription: Subscription;
- private TenantSubscription: Subscription;
- private SubscriberSubscription: Subscription;
- private NetworkSubscription: Subscription;
- private ServiceDependencySubscription: Subscription;
-
- constructor (
- private $log: ng.ILogService,
- private XosModelStore: IXosModelStoreService,
- private XosDebouncer: IXosDebouncer
- ) {
-
- this.$log.info(`[XosServiceGraphStore] Setup`);
-
- // we want to have a quiet period of 500ms from the last event before doing anything
- this.handleData = this.XosDebouncer.debounce(this._handleData, 500, this, false);
-
- // observe models and populate graphData
- this.ServiceSubscription = this.XosModelStore.query('Service', '/core/services')
- .subscribe(
- (res) => {
- this.combineData(res, 'services');
- },
- (err) => {
- this.$log.error(`[XosServiceGraphStore] Service Observable: `, err);
- }
- );
-
- this.ServiceDependencySubscription = this.XosModelStore.query('ServiceDependency', '/core/servicedependencys')
- .subscribe(
- (res) => {
- this.combineData(res, 'servicedependencys');
- },
- (err) => {
- this.$log.error(`[XosServiceGraphStore] Service Observable: `, err);
- }
- );
-
- this.TenantSubscription = this.XosModelStore.query('Tenant', '/core/tenants')
- .subscribe(
- (res) => {
- this.combineData(res, 'tenants');
- },
- (err) => {
- this.$log.error(`[XosServiceGraphStore] Tenant Observable: `, err);
- }
- );
-
- this.SubscriberSubscription = this.XosModelStore.query('Tenantroot', '/core/tenantroots')
- .subscribe(
- (res) => {
- this.combineData(res, 'subscribers');
- },
- (err) => {
- this.$log.error(`[XosServiceGraphStore] Subscriber Observable: `, err);
- }
- );
-
- this.NetworkSubscription = this.XosModelStore.query('Network', '/core/networks')
- .subscribe(
- (res) => {
- this.combineData(res, 'networks');
- },
- (err) => {
- this.$log.error(`[XosServiceGraphStore] graphData Observable: `, err);
- }
- );
-
- // observe graphData and build Coarse and FineGrained graphs
- this.graphData
- .subscribe(
- (res: IXosFineGrainedGraphData) => {
- this.$log.debug(`[XosServiceGraphStore] New graph data received`, res);
- this.graphDataToCoarseGraph(res);
- this.graphDataToFineGrainedGraph(res);
- },
- (err) => {
- this.$log.error(`[XosServiceGraphStore] graphData Observable: `, err);
- }
- );
- }
-
- public get() {
- return this.d3FineGrainedGraph.asObservable();
- }
-
- public getCoarse() {
- return this.d3CoarseGraph.asObservable();
- }
-
- private combineData(data: any, type: 'services'|'tenants'|'subscribers'|'networks'|'servicedependencys') {
- switch (type) {
- case 'services':
- this.services = data;
- break;
- case 'tenants':
- this.tenants = data;
- break;
- case 'subscribers':
- this.subscribers = data;
- break;
- case 'networks':
- this.networks = data;
- break;
- case 'servicedependencys':
- this.servicedependencys = data;
- break;
- }
- this.handleData(this.services, this.tenants);
- }
-
- private _handleData(services: IXosServiceModel[], tenants: IXosTenantModel[]) {
- this.graphData.next({
- services: this.services,
- tenants: this.tenants,
- subscribers: this.subscribers,
- networks: this.networks,
- servicedependencys: this.servicedependencys
- });
- }
-
- private getNodeIndexById(id: number | string, nodes: IXosServiceModel[]) {
- return _.findIndex(nodes, {id: id});
- }
-
- private d3Id(type: string, id: number) {
- return `${type.toLowerCase()}~${id}`;
- }
-
- private getTargetId(tenant: IXosTenantModel) {
-
- let targetId;
- if (tenant.subscriber_service_id) {
- targetId = this.d3Id('service', tenant.subscriber_service_id);
- }
- else if (tenant.subscriber_tenant_id) {
- targetId = this.d3Id('tenant', tenant.subscriber_tenant_id);
- }
- else if (tenant.subscriber_network_id) {
- targetId = this.d3Id('network', tenant.subscriber_network_id);
- }
- else if (tenant.subscriber_root_id) {
- // FIXME understand what's the correct model for the subscriber
- targetId = this.d3Id('tenantroot', tenant.subscriber_root_id);
- }
- return targetId;
- }
-
- private getSourceId(tenant: IXosTenantModel) {
- return this.d3Id('service', tenant.provider_service_id);
- }
-
- private getNodeType(n: any) {
- return n.class_names.split(',')[0].toLowerCase();
- }
-
- private getNodeLabel(n: any) {
- if (this.getNodeType(n) === 'tenant') {
- return n.id;
- }
- return n.humanReadableName ? n.humanReadableName : n.name;
- }
-
- private removeUnwantedFineGrainedData(data: IXosFineGrainedGraphData): IXosFineGrainedGraphData {
- data.tenants = _.filter(data.tenants, t => t.kind !== 'coarse');
- data.networks = _.filter(data.networks, n => {
- const subscriber = _.findIndex(data.tenants, {subscriber_network_id: n.id});
- return subscriber > -1;
- });
- return data;
- }
-
- private graphDataToCoarseGraph(data: IXosCoarseGraphData) {
-
- try {
- const links: IXosServiceGraphLink[] = _.chain(data.servicedependencys)
- .map((t: IXosTenantModel) => {
- return {
- id: t.id,
- source: this.getNodeIndexById(t.provider_service_id, data.services),
- target: this.getNodeIndexById(t.subscriber_service_id, data.services),
- model: t
- };
- })
- .value();
-
- const nodes: IXosServiceGraphNode[] = _.map(data.services, (s: IXosServiceModel) => {
- return {
- id: s.id,
- label: s.name,
- model: s
- };
- });
-
- let graph: IXosServiceGraph = {
- nodes,
- links
- };
-
- this.d3CoarseGraph.next(graph);
- } catch (e) {
- this.d3CoarseGraph.error(e);
- }
- }
-
- private graphDataToFineGrainedGraph(data: IXosFineGrainedGraphData) {
- try {
- data = this.removeUnwantedFineGrainedData(data);
-
- let nodes = _.reduce(Object.keys(data), (list: any[], k: string) => {
- return list.concat(data[k]);
- }, []);
-
- nodes = _.chain(nodes)
- .map(n => {
- n.d3Id = this.d3Id(this.getNodeType(n), n.id);
- return n;
- })
- .map(n => {
- let node: IXosServiceGraphNode = {
- id: n.d3Id,
- label: this.getNodeLabel(n),
- model: n,
- type: this.getNodeType(n)
- };
- return node;
- })
- .value();
-
- const links = _.reduce(data.tenants, (links: IXosServiceGraphLink[], tenant: IXosTenantModel) => {
- const sourceId = this.getSourceId(tenant);
- const targetId = this.getTargetId(tenant);
- if (!angular.isDefined(targetId) || !angular.isDefined(sourceId)) {
- // if the tenant is not pointing to anything, don't draw links
- return links;
- }
-
- const tenantToProvider = {
- id: `${sourceId}_${tenant.d3Id}`,
- source: this.getNodeIndexById(sourceId, nodes),
- target: this.getNodeIndexById(tenant.d3Id, nodes),
- model: tenant
- };
-
- const tenantToSubscriber = {
- id: `${tenant.d3Id}_${targetId}`,
- source: this.getNodeIndexById(tenant.d3Id, nodes),
- target: this.getNodeIndexById(targetId, nodes),
- model: tenant
- };
-
- if (angular.isDefined(tenantToProvider.source) && angular.isDefined(tenantToProvider.target)) {
- links.push(tenantToProvider);
- }
- if (angular.isDefined(tenantToSubscriber.source) && angular.isDefined(tenantToSubscriber.target)) {
- links.push(tenantToSubscriber);
- }
- return links;
- }, []);
-
- if (nodes.length === 0 && links.length === 0) {
- return;
- }
-
- let graph: IXosServiceGraph = {
- nodes,
- links
- };
-
- this.d3FineGrainedGraph.next(graph);
- } catch (e) {
- this.d3FineGrainedGraph.error(e);
- }
- }
-}
diff --git a/src/app/service-graph/services/graph.store.spec.ts b/src/app/service-graph/services/service-graph.store.spec.ts
similarity index 97%
rename from src/app/service-graph/services/graph.store.spec.ts
rename to src/app/service-graph/services/service-graph.store.spec.ts
index c083f09..7ddc393 100644
--- a/src/app/service-graph/services/graph.store.spec.ts
+++ b/src/app/service-graph/services/service-graph.store.spec.ts
@@ -1,7 +1,7 @@
import * as angular from 'angular';
import 'angular-mocks';
import 'angular-ui-router';
-import {IXosServiceGraphStore, XosServiceGraphStore} from './graph.store';
+import {IXosServiceGraphStore, XosServiceGraphStore} from './service-graph.store';
import {Subject} from 'rxjs';
import {XosDebouncer} from '../../core/services/helpers/debounce.helper';
import {IXosServiceGraph} from '../interfaces';
diff --git a/src/app/service-graph/services/service-graph.store.ts b/src/app/service-graph/services/service-graph.store.ts
new file mode 100644
index 0000000..d784958
--- /dev/null
+++ b/src/app/service-graph/services/service-graph.store.ts
@@ -0,0 +1,209 @@
+import * as _ from 'lodash';
+import {Observable, BehaviorSubject, Subscription} from 'rxjs';
+import {IXosModelStoreService} from '../../datasources/stores/model.store';
+import {
+ IXosServiceGraph, IXosServiceModel, IXosTenantModel, IXosCoarseGraphData,
+ IXosServiceGraphNode, IXosServiceGraphLink, IXosFineGrainedGraphData
+} from '../interfaces';
+import {IXosDebouncer} from '../../core/services/helpers/debounce.helper';
+export interface IXosServiceGraphStore {
+ // TODO remove, moved in a new service
+ get(): Observable<IXosServiceGraph>;
+ // TODO rename in get()
+ getCoarse(): Observable<IXosServiceGraph>;
+}
+
+export class XosServiceGraphStore implements IXosServiceGraphStore {
+ static $inject = [
+ '$log',
+ 'XosModelStore',
+ 'XosDebouncer'
+ ];
+
+ // graph data store
+ private graphData: BehaviorSubject<IXosFineGrainedGraphData> = new BehaviorSubject({
+ services: [],
+ tenants: [],
+ networks: [],
+ subscribers: [],
+ servicedependencies: []
+ });
+
+ private emptyGraph: IXosServiceGraph = {
+ nodes: [],
+ links: []
+ };
+
+ // representation of the graph as D3 requires
+ private d3CoarseGraph = new BehaviorSubject(this.emptyGraph);
+ private d3FineGrainedGraph = new BehaviorSubject(this.emptyGraph);
+
+ // storing locally reference to the data model
+ private services;
+ private tenants;
+ private subscribers;
+ private networks;
+ private servicedependencys;
+
+ // debounced functions
+ private handleData;
+
+ // datastore
+ private ServiceSubscription: Subscription;
+ private TenantSubscription: Subscription;
+ private SubscriberSubscription: Subscription;
+ private NetworkSubscription: Subscription;
+ private ServiceDependencySubscription: Subscription;
+
+ constructor (
+ private $log: ng.ILogService,
+ private XosModelStore: IXosModelStoreService,
+ private XosDebouncer: IXosDebouncer
+ ) {
+
+ this.$log.info(`[XosServiceGraphStore] Setup`);
+
+ // we want to have a quiet period of 500ms from the last event before doing anything
+ this.handleData = this.XosDebouncer.debounce(this._handleData, 500, this, false);
+
+ // observe models and populate graphData
+ this.ServiceSubscription = this.XosModelStore.query('Service', '/core/services')
+ .subscribe(
+ (res) => {
+ this.combineData(res, 'services');
+ },
+ (err) => {
+ this.$log.error(`[XosServiceGraphStore] Service Observable: `, err);
+ }
+ );
+
+ this.ServiceDependencySubscription = this.XosModelStore.query('ServiceDependency', '/core/servicedependencys')
+ .subscribe(
+ (res) => {
+ this.combineData(res, 'servicedependencies');
+ },
+ (err) => {
+ this.$log.error(`[XosServiceGraphStore] Service Observable: `, err);
+ }
+ );
+
+ this.TenantSubscription = this.XosModelStore.query('Tenant', '/core/tenants')
+ .subscribe(
+ (res) => {
+ this.combineData(res, 'tenants');
+ },
+ (err) => {
+ this.$log.error(`[XosServiceGraphStore] Tenant Observable: `, err);
+ }
+ );
+
+ this.SubscriberSubscription = this.XosModelStore.query('Tenantroot', '/core/tenantroots')
+ .subscribe(
+ (res) => {
+ this.combineData(res, 'subscribers');
+ },
+ (err) => {
+ this.$log.error(`[XosServiceGraphStore] Subscriber Observable: `, err);
+ }
+ );
+
+ this.NetworkSubscription = this.XosModelStore.query('Network', '/core/networks')
+ .subscribe(
+ (res) => {
+ this.combineData(res, 'networks');
+ },
+ (err) => {
+ this.$log.error(`[XosServiceGraphStore] graphData Observable: `, err);
+ }
+ );
+
+ // observe graphData and build Coarse and FineGrained graphs
+ this.graphData
+ .subscribe(
+ (res: IXosFineGrainedGraphData) => {
+ this.$log.debug(`[XosServiceGraphStore] New graph data received`, res);
+ this.graphDataToCoarseGraph(res);
+ // this.graphDataToFineGrainedGraph(res);
+ },
+ (err) => {
+ this.$log.error(`[XosServiceGraphStore] graphData Observable: `, err);
+ }
+ );
+ }
+
+ public get() {
+ return this.d3FineGrainedGraph.asObservable();
+ }
+
+ public getCoarse() {
+ return this.d3CoarseGraph.asObservable();
+ }
+
+ private combineData(data: any, type: 'services'|'tenants'|'subscribers'|'networks'|'servicedependencies') {
+ switch (type) {
+ case 'services':
+ this.services = data;
+ break;
+ case 'tenants':
+ this.tenants = data;
+ break;
+ case 'subscribers':
+ this.subscribers = data;
+ break;
+ case 'networks':
+ this.networks = data;
+ break;
+ case 'servicedependencies':
+ this.servicedependencys = data;
+ break;
+ }
+ this.handleData(this.services, this.tenants);
+ }
+
+ private _handleData(services: IXosServiceModel[], tenants: IXosTenantModel[]) {
+ this.graphData.next({
+ services: this.services,
+ tenants: this.tenants,
+ subscribers: this.subscribers,
+ networks: this.networks,
+ servicedependencies: this.servicedependencys
+ });
+ }
+
+ private getNodeIndexById(id: number | string, nodes: IXosServiceModel[]) {
+ return _.findIndex(nodes, {id: id});
+ }
+
+ private graphDataToCoarseGraph(data: IXosCoarseGraphData) {
+
+ try {
+ const links: IXosServiceGraphLink[] = _.chain(data.servicedependencies)
+ .map((t: IXosTenantModel) => {
+ return {
+ id: t.id,
+ source: this.getNodeIndexById(t.provider_service_id, data.services),
+ target: this.getNodeIndexById(t.subscriber_service_id, data.services),
+ model: t
+ };
+ })
+ .value();
+
+ const nodes: IXosServiceGraphNode[] = _.map(data.services, (s: IXosServiceModel) => {
+ return {
+ id: s.id,
+ label: s.name,
+ model: s
+ };
+ });
+
+ let graph: IXosServiceGraph = {
+ nodes,
+ links
+ };
+
+ this.d3CoarseGraph.next(graph);
+ } catch (e) {
+ this.d3CoarseGraph.error(e);
+ }
+ }
+}
diff --git a/src/app/service-graph/services/service-instance.graph.store.ts b/src/app/service-graph/services/service-instance.graph.store.ts
new file mode 100644
index 0000000..a6ab41e
--- /dev/null
+++ b/src/app/service-graph/services/service-instance.graph.store.ts
@@ -0,0 +1,263 @@
+import * as _ from 'lodash';
+import {Observable, BehaviorSubject, Subscription} from 'rxjs';
+import {
+ IXosServiceGraph, IXosServiceInstanceGraphData, IXosServiceGraphNode
+} from '../interfaces';
+import {IXosDebouncer} from '../../core/services/helpers/debounce.helper';
+import {IXosModelStoreService} from '../../datasources/stores/model.store';
+import {IXosServiceGraphStore} from './service-graph.store';
+
+export interface IXosServiceInstanceGraphStore {
+ get(): Observable<IXosServiceGraph>;
+}
+
+export class XosServiceInstanceGraphStore implements IXosServiceInstanceGraphStore {
+ static $inject = [
+ '$log',
+ 'XosServiceGraphStore',
+ 'XosModelStore',
+ 'XosDebouncer'
+ ];
+
+ private CoarseGraphSubscription: Subscription;
+ private ServiceInstanceSubscription: Subscription;
+ private ServiceInstanceLinkSubscription: Subscription;
+ private NetworkSubscription: Subscription;
+
+ // debounced functions
+ private handleData;
+
+
+ // FIXME this is declared also in ServiceGraphStore
+ private emptyGraph: IXosServiceGraph = {
+ nodes: [],
+ links: []
+ };
+
+ // graph data store
+ private graphData: BehaviorSubject<IXosServiceInstanceGraphData> = new BehaviorSubject({
+ serviceGraph: this.emptyGraph,
+ serviceInstances: [],
+ serviceInstanceLinks: [],
+ networks: []
+ });
+
+ private d3ServiceInstanceGraph = new BehaviorSubject(this.emptyGraph);
+
+ private serviceGraph: IXosServiceGraph = this.emptyGraph;
+ private serviceInstances: any[] = [];
+ private serviceInstanceLinks: any[] = [];
+ private networks: any[] = [];
+
+ constructor (
+ private $log: ng.ILogService,
+ private XosServiceGraphStore: IXosServiceGraphStore,
+ private XosModelStore: IXosModelStoreService,
+ private XosDebouncer: IXosDebouncer
+ ) {
+ this.$log.info(`[XosServiceInstanceGraphStore] Setup`);
+
+ // we want to have a quiet period of 500ms from the last event before doing anything
+ this.handleData = this.XosDebouncer.debounce(this._handleData, 500, this, false);
+
+ this.CoarseGraphSubscription = this.XosServiceGraphStore.getCoarse()
+ .subscribe(
+ (graph: IXosServiceGraph) => {
+ this.combineData(graph, 'serviceGraph');
+ }
+ );
+
+ this.ServiceInstanceSubscription = this.XosModelStore.query('ServiceInstance', '/core/serviceinstances')
+ .subscribe(
+ (res) => {
+ this.combineData(res, 'serviceInstance');
+ },
+ (err) => {
+ this.$log.error(`[XosServiceInstanceGraphStore] Service Observable: `, err);
+ }
+ );
+
+ this.ServiceInstanceLinkSubscription = this.XosModelStore.query('ServiceInstanceLink', '/core/serviceinstancelinks')
+ .subscribe(
+ (res) => {
+ this.combineData(res, 'serviceInstanceLink');
+ },
+ (err) => {
+ this.$log.error(`[XosServiceInstanceGraphStore] Service Observable: `, err);
+ }
+ );
+
+ this.NetworkSubscription = this.XosModelStore.query('Network', '/core/networks')
+ .subscribe(
+ (res) => {
+ this.combineData(res, 'networks');
+ },
+ (err) => {
+ this.$log.error(`[XosServiceGraphStore] graphData Observable: `, err);
+ }
+ );
+
+ // observe graphData and build ServiceInstance graph
+ this.graphData
+ .subscribe(
+ (res: IXosServiceInstanceGraphData) => {
+ this.$log.debug(`[XosServiceInstanceGraphStore] New graph data received`, res);
+
+ this.graphDataToD3(res);
+ },
+ (err) => {
+ this.$log.error(`[XosServiceInstanceGraphStore] graphData Observable: `, err);
+ }
+ );
+ }
+
+ public get(): Observable<IXosServiceGraph> {
+ return this.d3ServiceInstanceGraph;
+ }
+
+ // called by all the observables, combine the data in a globla graph observable
+ private combineData(data: any, type: 'serviceGraph' | 'serviceInstance' | 'serviceInstanceLink' | 'serviceInterface' | 'networks') {
+ switch (type) {
+ case 'serviceGraph':
+ this.serviceGraph = angular.copy(data);
+ break;
+ case 'serviceInstance':
+ this.serviceInstances = data;
+ break;
+ case 'serviceInstanceLink':
+ this.serviceInstanceLinks = data;
+ break;
+ case 'networks':
+ this.networks = data;
+ break;
+ }
+ this.handleData();
+ }
+
+ private _handleData() {
+ this.graphData.next({
+ serviceGraph: this.serviceGraph,
+ serviceInstances: this.serviceInstances,
+ serviceInstanceLinks: this.serviceInstanceLinks,
+ networks: this.networks
+ });
+ }
+
+ private getNodeType(n: any) {
+ return n.class_names.split(',')[0].toLowerCase();
+ }
+
+ private getNodeLabel(n: any) {
+ if (this.getNodeType(n) === 'serviceinstance') {
+ return n.name ? n.name : n.id;
+ }
+ return n.humanReadableName ? n.humanReadableName : n.name;
+ }
+
+ private d3Id(type: string, id: number) {
+ return `${type.toLowerCase()}~${id}`;
+ }
+
+ private toD3Node(n: any): IXosServiceGraphNode {
+ return {
+ id: this.d3Id(this.getNodeType(n), n.id),
+ label: this.getNodeLabel(n),
+ model: n,
+ type: this.getNodeType(n)
+ };
+ }
+
+ private getServiceInstanceIndexById(l: any, nodes: any[], where: 'source' | 'target'): string {
+ if (where === 'source') {
+ return _.find(nodes, {id: `serviceinstance~${l.provider_service_instance_id}`});
+ }
+ else {
+ if (l.subscriber_service_id) {
+ return _.find(nodes, {id: `service~${l.subscriber_service_id}`});
+ }
+ else if (l.subscriber_network_id) {
+ return _.find(nodes, {id: `network~${l.subscriber_network_id}`});
+ }
+ else if (l.subscriber_service_instance_id) {
+ return _.find(nodes, {id: `serviceinstance~${l.subscriber_service_instance_id}`});
+ }
+ }
+ }
+
+ private getOwnerById(id: number, nodes: any[]): any {
+ return _.find(nodes, {id: `service~${id}`});
+ }
+
+ private graphDataToD3(data: IXosServiceInstanceGraphData) {
+ try {
+ // get all the nodes
+ let nodes = _.chain(data.serviceGraph.nodes)
+ .map(n => {
+ // HACK we are receiving node as d3 models
+ return n.model;
+ })
+ .map(n => {
+ return this.toD3Node(n);
+ })
+ .value();
+
+ data.serviceInstances = _.chain(data.serviceInstances)
+ .map(n => {
+ return this.toD3Node(n);
+ })
+ .value();
+ nodes = nodes.concat(data.serviceInstances);
+
+ data.networks = _.chain(data.networks)
+ .filter(n => {
+ const subscriber = _.findIndex(data.serviceInstanceLinks, {subscriber_network_id: n.id});
+ return subscriber > -1;
+ })
+ .map(n => {
+ return this.toD3Node(n);
+ })
+ .value();
+ nodes = nodes.concat(data.networks);
+
+ let links = data.serviceGraph.links;
+
+ // create the links starting from the coarse ones
+ links = _.reduce(data.serviceInstanceLinks, (links, l) => {
+ let link = {
+ id: `service_instance_link~${l.id}`,
+ source: this.getServiceInstanceIndexById(l, nodes, 'source'),
+ target: this.getServiceInstanceIndexById(l, nodes, 'target'),
+ model: l,
+ d3Class: 'service-instance'
+ };
+ links.push(link);
+ return links;
+ }, data.serviceGraph.links);
+
+ const linksToService = _.reduce(data.serviceInstances, (links, n) => {
+ if (angular.isDefined(n.model.owner_id)) {
+ let link = {
+ id: `owner~${n.id}`,
+ source: n,
+ target: this.getOwnerById(n.model.owner_id, nodes),
+ model: n,
+ d3Class: 'owner'
+ };
+ links.push(link);
+ }
+ return links;
+ }, []);
+
+ links = links.concat(linksToService);
+
+ let graph: IXosServiceGraph = {
+ nodes,
+ links
+ };
+
+ this.d3ServiceInstanceGraph.next(graph);
+ } catch (e) {
+ this.d3ServiceInstanceGraph.error(e);
+ }
+ }
+}