SFC topology
[groupbasedpolicy.git] / groupbasedpolicy-ui / module / src / main / resources / gbp / common / gbp.controller.js
1 define(['app/gbp/common/gbp.service', 'app/gbp/resolved-policy/resolved-policy.service'], function () {
2     'use strict';
3
4     angular.module('app.gbp').controller('RootGbpCtrl', RootGbpCtrl);
5
6     RootGbpCtrl.$inject = ['$state', '$rootScope', '$scope', '$filter', '$mdDialog', 'RootGbpService',
7         'TenantListService', 'EpgListService', 'ResolvedPolicyService', 'NextTopologyService', 'EndpointsListService'];
8
9     function RootGbpCtrl($state, $rootScope, $scope, $filter, $mdDialog, RootGbpService,
10         TenantListService, EpgListService, ResolvedPolicyService, NextTopologyService, EndpointsListService) {
11         /* properties */
12         $scope.apiType = 'operational';
13         $scope.activeObject = null;
14         $scope.endpoints = EndpointsListService.createList();
15         $scope.rootTenant = null;
16         $scope.rootTenants = TenantListService.createList();
17         $scope.resolvedPolicy = {};
18         $scope.selectedNode = {};
19         $scope.sidePanelObject = {};
20         $scope.sidePanelPage = false;
21         $scope.sidePanelPageEndpoint = false;
22         $scope.stateUrl = null;
23         $scope.topologyData = {nodes: [], links: []};
24         $scope.viewPath = 'src/app/gbp/';
25
26         var resolvedPolicies = ResolvedPolicyService.createObject();
27         resolvedPolicies.get(fillTopologyData);
28
29         /* methods */
30         $scope.fillTopologyData = fillTopologyData;
31         $scope.broadcastFromRoot = broadcastFromRoot;
32         $scope.closeSidePanel = closeSidePanel;
33         $scope.openSfcDialog = openSfcDialog;
34         $scope.openSidePanel = openSidePanel;
35         $scope.setRootTenant = setRootTenant;
36         $scope.toggleExpanded = toggleExpanded;
37         $scope.openSidePanelContract = openSidePanelContract;
38         $scope.openSidePanelChild = openSidePanelChild;
39         $scope.deselectEpg = deselectEpg;
40         $scope.deselectContract = deselectContract;
41         $scope.openSidePanelTpl = openSidePanelTpl;
42         $scope.getObjectsCount = getObjectsCount;
43         $scope.expandAll = expandAll;
44         $scope.collapseAll = collapseAll;
45         $scope.highlightNode = highlightNode;
46         $scope.highlightLink = highlightLink;
47         $scope.fadeAll = fadeAll;
48         $scope.rootOpenEndpointDialog = rootOpenEndpointDialog;
49         $scope.rootDeleteEndpointDialog = rootDeleteEndpointDialog;
50         $scope.getEndpointsList = getEndpointsList;
51
52         RootGbpService.setMainClass();
53         init();
54
55         /* implementations */
56
57         /**
58          *
59          * @param eventName
60          * @param val
61          */
62         function broadcastFromRoot(eventName, val) {
63             $scope.$broadcast(eventName, val);
64         }
65
66         /**
67          *
68          */
69         function closeSidePanel() {
70             if($scope.sidePanelPage) {
71                 $scope.sidePanelPage = false;
72                 $scope.fadeAll();
73             }
74         }
75
76         /**
77          *
78          * @param arr
79          */
80         function collapseAll(arr) {
81             arr.forEach(function(element) {
82                 element.expanded = false;
83             });
84         }
85
86         /**
87          *
88          * @param source
89          * @param target
90          * @param contract
91          * @param tenant
92          * @returns {{id: string, source: *, target: *, tenant: *}}
93          */
94         function createLink( source, target, contract, tenant) {
95             return {
96                 'id': generateLinkId(contract, source, target),
97                 'source': source,
98                 'target': target,
99                 'tenant': tenant,
100             };
101         }
102
103         /**
104          *
105          * @param nodeName
106          * @param tenantId
107          * @returns {{id: *, tenantId: *, node-id: *, label: *}}
108          */
109         function createNode(nodeName, tenantId) {
110             return {
111                 'id': nodeName,
112                 'tenantId' : tenantId,
113                 'node-id': nodeName,
114                 'label': nodeName,
115             };
116         }
117
118         /**
119          *
120          */
121         function deselectContract() {
122             $scope.fadeAll();
123             $scope.sidePanelPage = 'resolved-policy/contract-sidepanel';
124
125             var obj = Object.keys($scope.resolvedPolicy).map(function(k) {
126                 var obj = $scope.resolvedPolicy[k];
127                 obj.linkId = k;
128
129                 return obj;
130             });
131
132             $scope.sidePanelObject = obj;
133             $scope.selectedNode = null;
134             $scope.activeObject = 'contract';
135         }
136
137         /**
138          *
139          */
140         function deselectEpg() {
141             $scope.fadeAll();
142             var elements;
143
144             $scope.sidePanelPage = 'resolved-policy/epg-sidepanel';
145             elements = EpgListService.createList();
146             elements.get($scope.apiType, $scope.rootTenant);
147             $scope.sidePanelObject = elements;
148             $scope.selectedNode = null;
149             $scope.activeObject = 'epg';
150         }
151
152         /**
153          *
154          * @param arr
155          */
156         function expandAll(arr) {
157             arr.forEach(function(element) {
158                 element.expanded = true;
159             });
160         }
161
162         /**
163          *
164          */
165         function fadeAll() {
166             $rootScope.nxTopology && NextTopologyService.fadeInAllLayers($rootScope.nxTopology);
167         }
168
169         /**
170          *
171          * @param data
172          */
173         function fillResolvedPolicy(data) {
174             if(data['policy-rule-group-with-endpoint-constraints']) {
175                 processPolicyRuleGroupWithEpConstraints(
176                     data['policy-rule-group-with-endpoint-constraints'],
177                     data['provider-epg-id'],
178                     data['consumer-epg-id']);
179             }
180
181         }
182
183         /**
184          *
185          */
186         function fillTopologyData() {
187             if($scope.rootTenant) {
188                 var topoData = {nodes: [], links: [],},
189                     filteredResolvedPolicies = $filter('filter')(resolvedPolicies.data, {
190                         'consumer-tenant-id': $scope.rootTenant,
191                         'provider-tenant-id': $scope.rootTenant
192                     });
193
194
195                 filteredResolvedPolicies && filteredResolvedPolicies.forEach(function(rp) {
196                     if(rp['consumer-tenant-id'] === $scope.rootTenant) {
197                         topoData.nodes.push(createNode(rp['consumer-epg-id'], rp['consumer-tenant-id']));
198                     }
199                     topoData.nodes.push(createNode(rp['provider-epg-id'], rp['provider-tenant-id']));
200
201                     fillResolvedPolicy(rp);
202                     topoData.links = getContracts(rp);
203                 });
204
205                 $scope.topologyData = topoData;
206                 $scope.topologyLoaded = true;
207             }
208         }
209
210         /**
211          *
212          * @param contractId
213          * @param providerEpgId
214          * @param consumerEpgId
215          * @returns {string}
216          */
217         function generateLinkId(contractId, providerEpgId, consumerEpgId) {
218             return contractId + '_' + providerEpgId + '_' + consumerEpgId;
219         }
220
221         /**
222          *
223          * @param data
224          * @returns {Array}
225          */
226         function getContracts(data) {
227             var retVal = [];
228
229             if( data['policy-rule-group-with-endpoint-constraints'] &&
230                 data['policy-rule-group-with-endpoint-constraints'][0]['policy-rule-group']) {
231                 data['policy-rule-group-with-endpoint-constraints'][0]['policy-rule-group'].forEach(function(prg) {
232                     retVal.push(
233                         createLink(
234                             data['provider-epg-id'],
235                             data['consumer-epg-id'],
236                             prg['contract-id'],
237                             prg['tenant-id']
238                         )
239                     )
240                 });
241             }
242
243             return retVal;
244         }
245
246         /**
247          *
248          * @param obj
249          * @returns {*}
250          */
251         function getObjectsCount(obj) {
252             if(obj)
253                 return Object.keys(obj).length;
254             else
255                 return 0;
256         }
257
258         /**
259          *
260          * @param node
261          */
262         function highlightNode(node) {
263             NextTopologyService.highlightNode($rootScope.nxTopology, node);
264         }
265
266         /**
267          *
268          * @param link
269          */
270         function highlightLink(link) {
271             NextTopologyService.highlightLink($rootScope.nxTopology, link);
272         }
273
274         /**
275          *
276          */
277         function init() {
278             $scope.rootTenants.clearData();
279             $scope.rootTenants.get('config');
280         }
281
282         /**
283          *
284          * @param chainName
285          */
286         function openSfcDialog(chainName) {
287             $mdDialog.show({
288                 clickOutsideToClose: true,
289                 controller: 'SfcTopologyController',
290                 preserveScope: true,
291                 templateUrl: $scope.viewPath + 'sfc/dialog-sfc-topology.tpl.html',
292                 parent: angular.element(document.body),
293                 scope: $scope,
294                 locals: {
295                     chainName: chainName,
296                 },
297             });
298         }
299
300
301         /**
302          * Sets '$scope.sidePanelPage' to true. This variable is watched in index.tpl.html template
303          * and opens/closes side panel
304          */
305         function openSidePanel(page, object, cbk) {
306             if(object.constructor.name == 'Epg') {
307                 $scope.endpoints.clearData();
308                 $scope.endpoints.getByEpg(object.data.id);
309                 $scope.activeObject = 'epg';
310             }
311             else
312                 $scope.activeObject = 'contract';
313
314             var samePage = page === $scope.sidePanelPage;
315
316             $scope.selectedNode = object;
317
318             $scope.sidePanelCbk = cbk;
319             $scope.sidePanelPage = page;
320             $scope.sidePanelObject = object;
321
322             if ( samePage &&  $scope.sidePanelCbk) {
323                 $scope.sidePanelCbk();
324             }
325         }
326
327         /**
328          *
329          * @param idElement
330          */
331         function openSidePanelContract(idElement) {
332             var obj = $filter('filter')(Object.keys($scope.resolvedPolicy).map(function(k) {
333                 var obj = $scope.resolvedPolicy[k];
334                 obj.linkId = k;
335
336                 return obj;
337             }), {'contract-id': idElement});
338
339             $scope.sidePanelPage = 'resolved-policy/contract-sidepanel';
340             $scope.sidePanelObject = obj[0];
341             $scope.selectedNode = obj[0];
342             $scope.activeObject = 'contract';
343
344             NextTopologyService.highlightLink($rootScope.nxTopology, obj[0].linkId);
345         }
346
347         /**
348          * .
349          * @param index
350          * @param type
351          */
352         function openSidePanelChild(index, type) {
353             switch(type) {
354             case 'subject':
355                 $scope.sidePanelPage = 'resolved-policy/subject-sidepanel';
356                 $scope.subjectIndex = index;
357                 break;
358             case 'clause':
359                 $scope.sidePanelPage = 'resolved-policy/clause-sidepanel';
360                 $scope.clauseIndex = index;
361                 break;
362             case 'rule':
363                 $scope.sidePanelPage = 'resolved-policy/rule-sidepanel';
364                 $scope.ruleIndex = index;
365                 break;
366             }
367         }
368
369         /**
370          *
371          * @param tpl
372          */
373         function openSidePanelTpl(tpl) {
374             switch(tpl) {
375             case 'contract':
376                 $scope.sidePanelPage = 'resolved-policy/contract-sidepanel';
377                 break;
378             case 'subject':
379                 $scope.sidePanelPage = 'resolved-policy/subject-sidepanel';
380                 break;
381             case 'clause':
382                 $scope.sidePanelPage = 'resolved-policy/clause-sidepanel';
383                 break;
384             case 'rule':
385                 $scope.sidePanelPage = 'resolved-policy/rule-sidepanel';
386                 break;
387             }
388         }
389
390         /**
391          *
392          * @param data
393          * @param providerEpgId
394          * @param consumerEpgId
395          */
396         function processPolicyRuleGroupWithEpConstraints(data, providerEpgId, consumerEpgId) {
397             data.forEach(function(element) {
398                 element['policy-rule-group'].forEach(function(el) {
399                     var linkId = generateLinkId(el['contract-id'], providerEpgId, consumerEpgId);
400
401                     $scope.resolvedPolicy = {};
402
403                     if(!$scope.resolvedPolicy.hasOwnProperty(linkId)) {
404                         $scope.resolvedPolicy[linkId] = {
405                             'contract-id': el['contract-id'],
406                             'subjects': {},
407                         };
408                     }
409
410                     if(!$scope.resolvedPolicy[linkId].subjects.hasOwnProperty(el['subject-name'])) {
411                         $scope.resolvedPolicy[linkId].subjects[el['subject-name']] = {'resolved-rule': []};
412                     }
413
414                     $scope.resolvedPolicy[linkId].subjects[el['subject-name']]['resolved-rule'].push(el['resolved-rule']);
415                 });
416             });
417         }
418
419         /**
420          *
421          */
422         function setRootTenant() {
423             $scope.broadcastFromRoot('ROOT_TENANT_CHANGED');
424
425             if($scope.stateUrl.startsWith('/resolved-policy')) {
426                 fillTopologyData();
427                 if($scope.sidePanelPage) {
428                     if($scope.activeObject == 'epg')
429                         deselectEpg();
430                     else if($scope.activeObject == 'contract')
431                         deselectContract();
432                 }
433             }
434         }
435
436         /**
437          * fills $scope.stateUrl with loaded url
438          * It's called on $viewContentLoaded event
439          */
440         function setStateUrl() {
441             $scope.stateUrl = $state.current.url;
442             closeSidePanel();
443
444             if($scope.stateUrl.startsWith('/resolved-policy')) {
445                 fillTopologyData();
446             }
447         }
448
449         /**
450          *
451          * @param element
452          */
453         function toggleExpanded(element) {
454             if(typeof element !== 'string') {
455                 if(element.expanded)
456                     element.expanded = false;
457                 else
458                     element.expanded = true;
459             }
460         }
461
462         function rootOpenEndpointDialog(operation, endpointData) {
463             $scope.disableKeyFieldsEditing = operation === 'edit';
464             $mdDialog.show({
465                 clickOutsideToClose: true,
466                 controller: 'AddEndpointController',
467                 preserveScope: true,
468                 templateUrl: $scope.viewPath + 'endpoints/dialog-add-endpoint.tpl.html',
469                 parent: angular.element(document.body),
470                 scope: $scope,
471                 locals: {
472                     endpoint: endpointData,
473                 },
474             });
475         }
476
477         function rootDeleteEndpointDialog(endpointData) {
478             var confirm = $mdDialog.confirm()
479                 .title('Delete endpoint')
480                 .textContent('Do you want to delete endpoint?')
481                 .ok('Delete')
482                 .cancel('Cancel');
483
484             $mdDialog.show(confirm).then(function () {
485                 endpointData.deleteEndpoint(function () {
486                     getEndpointsList();
487                 });
488             }, function () {
489
490             });
491         }
492
493         function getEndpointsList() {
494             $scope.endpoints.clearData();
495             $scope.endpoints.getByEpg($scope.selectedNode.data.id);
496         }
497
498         /* event listeners */
499         /**
500          * Event fired after content loaded, setStateUrl function is called to fill stateUrl method
501          */
502         $scope.$on('$viewContentLoaded', setStateUrl);
503     }
504 });