blob: 162a3b5655d658e4a4cf89dafab966ec55536c24 [file] [log] [blame]
Matteo Scandolo8cf33a32017-11-14 15:52:29 -08001/*
2 * Copyright 2017-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Matteo Scandolo9ec14ff2019-03-13 15:51:56 -070017 export interface IServiceGraphConstraint {
18 constraints: string; // this is stringified JSON
19 priority: number;
20 }
Matteo Scandolo8cf33a32017-11-14 15:52:29 -080021
22import * as _ from 'lodash';
23import {IXosResourceService} from '../../datasources/rest/model.rest';
24import {IXosSgNode} from '../interfaces';
Matteo Scandolo35fdf242017-11-30 12:29:45 -080025import {IXosConfirm} from '../../core/confirm/confirm.service';
Matteo Scandolo8cf33a32017-11-14 15:52:29 -080026
27export interface IXosNodePositioner {
28 positionNodes(svg: {width: number, height: number}, nodes: any[]): ng.IPromise<IXosSgNode[]>;
29}
30
31export class XosNodePositioner implements IXosNodePositioner {
32 static $inject = [
33 '$log',
34 '$q',
Matteo Scandolo35fdf242017-11-30 12:29:45 -080035 'ModelRest',
36 'XosConfirm'
Matteo Scandolo8cf33a32017-11-14 15:52:29 -080037 ];
38
39 constructor (
40 private $log: ng.ILogService,
41 private $q: ng.IQService,
42 private ModelRest: IXosResourceService,
Matteo Scandolo35fdf242017-11-30 12:29:45 -080043 private XosConfirm: IXosConfirm
Matteo Scandolo8cf33a32017-11-14 15:52:29 -080044 ) {
45 this.$log.info('[XosNodePositioner] Setup');
46 }
47
Matteo Scandolo35fdf242017-11-30 12:29:45 -080048 public positionNodes(svg: {width: number, height: number}, nodes: IXosSgNode[]): ng.IPromise<IXosSgNode[]> {
Matteo Scandolo8cf33a32017-11-14 15:52:29 -080049
Matteo Scandolo8cf33a32017-11-14 15:52:29 -080050 const d = this.$q.defer();
51
52 this.getConstraints()
53 .then(constraints => {
54 const hStep = this.getHorizontalStep(svg.width, constraints);
Matteo Scandolo35fdf242017-11-30 12:29:45 -080055 const positionConstraints = _.reduce(constraints, (all: any, horizontalConstraint: string | string[], i: number) => {
Matteo Scandolo8cf33a32017-11-14 15:52:29 -080056 // NOTE it's a single element, leave it in the middle
Matteo Scandolo35fdf242017-11-30 12:29:45 -080057 if (angular.isString(horizontalConstraint)) {
58 all[horizontalConstraint] = {
59 x: (i + 1) * hStep,
60 y: svg.height / 2,
61 fixed: true
62 };
Matteo Scandolo8cf33a32017-11-14 15:52:29 -080063 }
64 else {
Matteo Scandolo35fdf242017-11-30 12:29:45 -080065 const verticalConstraints = horizontalConstraint;
Matteo Scandolo8cf33a32017-11-14 15:52:29 -080066 const vStep = this.getVerticalStep(svg.height, verticalConstraints);
Matteo Scandolo35fdf242017-11-30 12:29:45 -080067 _.forEach(verticalConstraints, (verticalConstraint: string, v: number) => {
68 if (angular.isString(verticalConstraint)) {
69 all[verticalConstraint] = {
70 x: (i + 1) * hStep,
71 y: (v + 1) * vStep,
72 fixed: true
73 };
Matteo Scandolo8cf33a32017-11-14 15:52:29 -080074 }
75 });
76 }
77 return all;
78 }, {});
79
Matteo Scandolo865b11c2018-02-14 16:57:44 -080080 // find the nodes that don't have a position defined and put them at the bottom
81 const allServiceNodes = _.reduce(nodes, (all: string[], n: IXosSgNode) => {
Matteo Scandolo35fdf242017-11-30 12:29:45 -080082 if (n.type === 'service') {
83 all.push(n.data.name);
84 }
85 return all;
86 }, []);
87 const positionedNodes = Object.keys(positionConstraints);
Matteo Scandolo865b11c2018-02-14 16:57:44 -080088 const unpositionedNodes = _.difference(allServiceNodes, positionedNodes);
Matteo Scandolo35fdf242017-11-30 12:29:45 -080089
90 _.forEach(unpositionedNodes, (node: string, i: number) => {
91 const hStep = this.getHorizontalStep(svg.width, unpositionedNodes);
92 positionConstraints[node] = {
93 x: (i + 1) * hStep,
94 y: svg.height - 50,
95 fixed: true
96 };
97 });
98
Matteo Scandolo8cf33a32017-11-14 15:52:29 -080099 d.resolve(_.map(nodes, n => {
100 return angular.merge(n, positionConstraints[n.data.name]);
101 }));
102 })
103 .catch(e => {
104 this.$log.error(`[XosNodePositioner] Error retrieving constraints`, e);
105 });
106
107 return d.promise;
108 }
109
110 private getConstraints(): ng.IPromise<any[]> {
111 const d = this.$q.defer();
112 this.ModelRest.getResource('/core/servicegraphconstraints').query().$promise
Matteo Scandolo9ec14ff2019-03-13 15:51:56 -0700113 .then((res) => {
114 d.resolve(this.readConstraints(<IServiceGraphConstraint[]>res));
Matteo Scandolo8cf33a32017-11-14 15:52:29 -0800115 })
116 .catch(e => {
Matteo Scandolo35fdf242017-11-30 12:29:45 -0800117 this.XosConfirm.open({
118 header: 'Error in graph constraints config',
119 text: `
120 There was an error in the settings you provided as graph constraints.
121 Please check the declaration of the <code>"Graph Constraints"</code> model. <br/>
122 The error was: <br/><br/>
123 <code>${e}</code>
124 <br/><br/>
125 Please fix it to see the graph.`,
126 actions: []
127 });
Matteo Scandolo8cf33a32017-11-14 15:52:29 -0800128 d.reject(e);
129 });
130 return d.promise;
131 }
132
Matteo Scandolo9ec14ff2019-03-13 15:51:56 -0700133 private readConstraints(res: IServiceGraphConstraint[]): any[] {
134 if (res.length === 0) {
135 return [];
136 }
137 else {
138 res = _.sortBy(res, (c) => c.priority).reverse();
139 return JSON.parse(res[0].constraints);
140 }
141 }
142
Matteo Scandolo8cf33a32017-11-14 15:52:29 -0800143 private getHorizontalStep(svgWidth: number, constraints: any[]) {
144 return svgWidth / (constraints.length + 1);
145 }
146
147 private getVerticalStep(svgHeight: number, verticalConstraints: string[]) {
148 // NOTE verticalConstraints represent the vertical part (the nested array)
149 return svgHeight / (verticalConstraints.length + 1);
150 }
151}