Add DCAE MOD design tool project
[dcaegen2/platform.git] / mod / designtool / designtool-web / src / main / webapp / js / nf / canvas / header / components / nf-ng-processor-component.js
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * Modifications to the original nifi code for the ONAP project are made
18  * available under the Apache License, Version 2.0
19  */
20
21 /* global define, module, require, exports */
22
23 (function (root, factory) {
24     if (typeof define === 'function' && define.amd) {
25         define(['jquery',
26                 'Slick',
27                 'nf.Client',
28                 'nf.Birdseye',
29                 'nf.Storage',
30                 'nf.Graph',
31                 'nf.CanvasUtils',
32                 'nf.ErrorHandler',
33                 'nf.FilteredDialogCommon',
34                 'nf.Dialog',
35                 'nf.Common'],
36             function ($, Slick, nfClient, nfBirdseye, nfStorage, nfGraph, nfCanvasUtils, nfErrorHandler, nfFilteredDialogCommon, nfDialog, nfCommon) {
37                 return (nf.ng.ProcessorComponent = factory($, Slick, nfClient, nfBirdseye, nfStorage, nfGraph, nfCanvasUtils, nfErrorHandler, nfFilteredDialogCommon, nfDialog, nfCommon));
38             });
39     } else if (typeof exports === 'object' && typeof module === 'object') {
40         module.exports = (nf.ng.ProcessorComponent =
41             factory(require('jquery'),
42                 require('Slick'),
43                 require('nf.Client'),
44                 require('nf.Birdseye'),
45                 require('nf.Storage'),
46                 require('nf.Graph'),
47                 require('nf.CanvasUtils'),
48                 require('nf.ErrorHandler'),
49                 require('nf.FilteredDialogCommon'),
50                 require('nf.Dialog'),
51                 require('nf.Common')));
52     } else {
53         nf.ng.ProcessorComponent = factory(root.$,
54             root.Slick,
55             root.nf.Client,
56             root.nf.Birdseye,
57             root.nf.Storage,
58             root.nf.Graph,
59             root.nf.CanvasUtils,
60             root.nf.ErrorHandler,
61             root.nf.FilteredDialogCommon,
62             root.nf.Dialog,
63             root.nf.Common);
64     }
65 }(this, function ($, Slick, nfClient, nfBirdseye, nfStorage, nfGraph, nfCanvasUtils, nfErrorHandler, nfFilteredDialogCommon, nfDialog, nfCommon) {
66     'use strict';
67
68     return function (serviceProvider) {
69         'use strict';
70
71
72         var latestResponse;
73
74         var processorTypesData;
75
76
77         /**
78          * Filters the processor type table.
79          */
80         var applyFilter = function () {
81             // get the dataview
82             var processorTypesGrid = $('#processor-types-table').data('gridInstance');
83
84             // ensure the grid has been initialized
85             if (nfCommon.isDefinedAndNotNull(processorTypesGrid)) {
86                 var processorTypesDataForFilter = processorTypesGrid.getData();
87
88                 // update the search criteria
89                 processorTypesDataForFilter.setFilterArgs({
90                     searchString: getFilterText()
91                 });
92                 processorTypesDataForFilter.refresh();
93
94                 // update the buttons to possibly trigger the disabled state
95                 $('#new-processor-dialog').modal('refreshButtons');
96
97                 // update the selection if possible
98                 if (processorTypesDataForFilter.getLength() > 0) {
99                     nfFilteredDialogCommon.choseFirstRow(processorTypesGrid);
100                     // make the first row visible
101                     processorTypesGrid.scrollRowToTop(0);
102                 }
103             }
104         };
105
106         /**
107          * Determines if the item matches the filter.
108          *
109          * @param {object} item     The item to filter.
110          * @param {object} args     The filter criteria.
111          * @returns {boolean}       Whether the item matches the filter.
112          */
113         var matchesRegex = function (item, args) {
114             if (args.searchString === '') {
115                 return true;
116             }
117
118             try {
119                 // perform the row filtering
120                 var filterExp = new RegExp(args.searchString, 'i');
121             } catch (e) {
122                 // invalid regex
123                 return false;
124             }
125
126             // determine if the item matches the filter
127             var matchesLabel = item['label'].search(filterExp) >= 0;
128             var matchesTags = item['tags'].search(filterExp) >= 0;
129             return matchesLabel || matchesTags;
130         };
131
132         /**
133          * Performs the filtering.
134          *
135          * @param {object} item     The item subject to filtering.
136          * @param {object} args     Filter arguments.
137          * @returns {Boolean}       Whether or not to include the item.
138          */
139         var filter = function (item, args) {
140             // determine if the item matches the filter
141             var matchesFilter = matchesRegex(item, args);
142
143             // determine if the row matches the selected tags
144             var matchesTags = true;
145             if (matchesFilter) {
146                 var tagFilters = $('#processor-tag-cloud').tagcloud('getSelectedTags');
147                 var hasSelectedTags = tagFilters.length > 0;
148                 if (hasSelectedTags) {
149                     matchesTags = matchesSelectedTags(tagFilters, item['tags']);
150                 }
151             }
152
153             // determine if the row matches the selected source group
154             var matchesGroup = true;
155             if (matchesFilter && matchesTags) {
156                 var bundleGroup = $('#processor-bundle-group-combo').combo('getSelectedOption');
157                 if (nfCommon.isDefinedAndNotNull(bundleGroup) && bundleGroup.value !== '') {
158                     matchesGroup = (item.bundle.group === bundleGroup.value);
159                 }
160             }
161
162             // determine if this row should be visible
163             var matches = matchesFilter && matchesTags && matchesGroup;
164
165             // if this row is currently selected and its being filtered
166             if (matches === false && $('#selected-processor-type').text() === item['type']) {
167                 // clear the selected row
168                 $('#processor-type-description').attr('title', '').text('');
169                 $('#processor-type-name').attr('title', '').text('');
170                 $('#processor-type-bundle').attr('title', '').text('');
171                 $('#selected-processor-name').text('');
172                 $('#selected-processor-type').text('').removeData('bundle');
173
174                 // clear the active cell the it can be reselected when its included
175                 var processTypesGrid = $('#processor-types-table').data('gridInstance');
176                 processTypesGrid.resetActiveCell();
177             }
178
179             return matches;
180         };
181
182         /**
183          * Determines if the specified tags match all the tags selected by the user.
184          *
185          * @argument {string[]} tagFilters      The tag filters.
186          * @argument {string} tags              The tags to test.
187          */
188         var matchesSelectedTags = function (tagFilters, tags) {
189             var selectedTags = [];
190             $.each(tagFilters, function (_, filter) {
191                 selectedTags.push(filter);
192             });
193
194             // normalize the tags
195             var normalizedTags = tags.toLowerCase();
196
197             var matches = true;
198             $.each(selectedTags, function (i, selectedTag) {
199                 if (normalizedTags.indexOf(selectedTag) === -1) {
200                     matches = false;
201                     return false;
202                 }
203             });
204
205             return matches;
206         };
207
208         /**
209          * Get the text out of the filter field. If the filter field doesn't
210          * have any text it will contain the text 'filter list' so this method
211          * accounts for that.
212          */
213         var getFilterText = function () {
214             return $('#processor-type-filter').val();
215         };
216
217         /**
218          * Resets the filtered processor types.
219          */
220         var resetProcessorDialog = function () {
221
222  //********* REPLICATED A BLOCK OF CODE to get logic of autoloading processor ---STARTING FROM HERE----********************
223
224                                 // initialize the processor type table
225                                 var processorTypesColumns = [
226                                     {
227                                         id: 'type',
228                                         name: 'Type',
229                                         field: 'label',
230                                         formatter: nfCommon.typeFormatter,
231                                         sortable: true,
232                                         resizable: true
233                                     },
234                                     {
235                                         id: 'version',
236                                         name: 'Version',
237                                         field: 'version',
238                                         formatter: nfCommon.typeVersionFormatter,
239                                         sortable: true,
240                                         resizable: true
241                                     },
242                                     {
243                                         id: 'tags',
244                                         name: 'Tags',
245                                         field: 'tags',
246                                         sortable: true,
247                                         resizable: true,
248                                         formatter: nfCommon.genericValueFormatter
249                                     }
250                                 ];
251
252                                 var processorTypesOptions = {
253                                     forceFitColumns: true,
254                                     enableTextSelectionOnCells: true,
255                                     enableCellNavigation: true,
256                                     enableColumnReorder: false,
257                                     autoEdit: false,
258                                     multiSelect: false,
259                                     rowHeight: 24
260                                 };
261
262                                 // initialize the dataview
263                                 processorTypesData = new Slick.Data.DataView({
264                                     inlineFilters: false
265                                 });
266                                 processorTypesData.setItems([]);
267                                 processorTypesData.setFilterArgs({
268                                     searchString: getFilterText()
269                                 });
270                                 processorTypesData.setFilter(filter);
271
272                                 // initialize the sort
273                                 nfCommon.sortType({
274                                     columnId: 'type',
275                                     sortAsc: true
276                                 }, processorTypesData);
277
278                                 // initialize the grid
279                                 var processorTypesGrid = new Slick.Grid('#processor-types-table', processorTypesData, processorTypesColumns, processorTypesOptions);
280                                 processorTypesGrid.setSelectionModel(new Slick.RowSelectionModel());
281                                 processorTypesGrid.registerPlugin(new Slick.AutoTooltips());
282                                 processorTypesGrid.setSortColumn('type', true);
283                                 processorTypesGrid.onSort.subscribe(function (e, args) {
284                                     nfCommon.sortType({
285                                         columnId: args.sortCol.field,
286                                         sortAsc: args.sortAsc
287                                     }, processorTypesData);
288                                 });
289                                 processorTypesGrid.onSelectedRowsChanged.subscribe(function (e, args) {
290                                     if ($.isArray(args.rows) && args.rows.length === 1) {
291                                         var processorTypeIndex = args.rows[0];
292                                         var processorType = processorTypesGrid.getDataItem(processorTypeIndex);
293
294                                         // set the processor type description
295                                         if (nfCommon.isDefinedAndNotNull(processorType)) {
296                                             if (nfCommon.isBlank(processorType.description)) {
297                                                 $('#processor-type-description')
298                                                     .attr('title', '')
299                                                     .html('<span class="unset">No description specified</span>');
300                                             } else {
301                                                 $('#processor-type-description')
302                                                     .width($('#processor-description-container').innerWidth() - 1)
303                                                     .html(processorType.description)
304                                                     .ellipsis();
305                                             }
306
307                                             var bundle = nfCommon.formatBundle(processorType.bundle);
308                                             var type = nfCommon.formatType(processorType);
309
310                                             // populate the dom
311                                             $('#processor-type-name').text(type).attr('title', type);
312                                             $('#processor-type-bundle').text(bundle).attr('title', bundle);
313                                             $('#selected-processor-name').text(processorType.label);
314                                             $('#selected-processor-type').text(processorType.type).data('bundle', processorType.bundle);
315
316                                             // refresh the buttons based on the current selection
317                                             $('#new-processor-dialog').modal('refreshButtons');
318                                         }
319                                     }
320                                 });
321                                 processorTypesGrid.onViewportChanged.subscribe(function (e, args) {
322                                     nfCommon.cleanUpTooltips($('#processor-types-table'), 'div.view-usage-restriction');
323                                 });
324
325                                 // wire up the dataview to the grid
326                                 processorTypesData.onRowCountChanged.subscribe(function (e, args) {
327                                     processorTypesGrid.updateRowCount();
328                                     processorTypesGrid.render();
329
330                                     // update the total number of displayed processors
331                                     $('#displayed-processor-types').text(args.current);
332                                 });
333                                 processorTypesData.onRowsChanged.subscribe(function (e, args) {
334                                     processorTypesGrid.invalidateRows(args.rows);
335                                     processorTypesGrid.render();
336                                 });
337                                 processorTypesData.syncGridSelection(processorTypesGrid, false);
338
339                                 // hold onto an instance of the grid
340                                 $('#processor-types-table').data('gridInstance', processorTypesGrid).on('mouseenter', 'div.slick-cell', function (e) {
341                                     var usageRestriction = $(this).find('div.view-usage-restriction');
342                                     if (usageRestriction.length && !usageRestriction.data('qtip')) {
343                                         var rowId = $(this).find('span.row-id').text();
344
345                                         // get the status item
346                                         var item = processorTypesData.getItemById(rowId);
347
348                                         // show the tooltip
349                                         if (item.restricted === true) {
350                                             var restrictionTip = $('<div></div>');
351
352                                             if (nfCommon.isBlank(item.usageRestriction)) {
353                                                 restrictionTip.append($('<p style="margin-bottom: 3px;"></p>').text('Requires the following permissions:'));
354                                             } else {
355                                                 restrictionTip.append($('<p style="margin-bottom: 3px;"></p>').text(item.usageRestriction + ' Requires the following permissions:'));
356                                             }
357
358                                             var restrictions = [];
359                                             if (nfCommon.isDefinedAndNotNull(item.explicitRestrictions)) {
360                                                 $.each(item.explicitRestrictions, function (_, explicitRestriction) {
361                                                     var requiredPermission = explicitRestriction.requiredPermission;
362                                                     restrictions.push("'" + requiredPermission.label + "' - " + nfCommon.escapeHtml(explicitRestriction.explanation));
363                                                 });
364                                             } else {
365                                                 restrictions.push('Access to restricted components regardless of restrictions.');
366                                             }
367                                             restrictionTip.append(nfCommon.formatUnorderedList(restrictions));
368
369                                             usageRestriction.qtip($.extend({}, nfCommon.config.tooltipConfig, {
370                                                 content: restrictionTip,
371                                                 position: {
372                                                     container: $('#summary'),
373                                                     at: 'bottom right',
374                                                     my: 'top left',
375                                                     adjust: {
376                                                         x: 4,
377                                                         y: 4
378                                                     }
379                                                 }
380                                             }));
381                                         }
382                                     }
383                                 });
384
385                                 var generalRestriction = nfCommon.getPolicyTypeListing('restricted-components');
386
387                                 // load the available processor types, this select is shown in the
388                                 // new processor dialog when a processor is dragged onto the screen
389                                 $.ajax({
390                                     type: 'GET',
391                                     url:'../nifi-api/flow/processor-types',
392         //                            url: serviceProvider.headerCtrl.toolboxCtrl.config.urls.processorTypes,
393                                     dataType: 'json'
394                                 }).done(function (response) {
395                                     console.log(response);
396                                     var tags = [];
397                                     var groups = d3.set();
398                                     var restrictedUsage = d3.map();
399                                     var requiredPermissions = d3.map();
400
401                                     // begin the update
402                                     processorTypesData.beginUpdate();
403
404                                     // go through each processor type
405                                     $.each(response.processorTypes, function (i, documentedType) {
406                                         var type = documentedType.type;
407
408                                         if (documentedType.restricted === true) {
409                                             if (nfCommon.isDefinedAndNotNull(documentedType.explicitRestrictions)) {
410                                                 $.each(documentedType.explicitRestrictions, function (_, explicitRestriction) {
411                                                     var requiredPermission = explicitRestriction.requiredPermission;
412
413                                                     // update required permissions
414                                                     if (!requiredPermissions.has(requiredPermission.id)) {
415                                                         requiredPermissions.set(requiredPermission.id, requiredPermission.label);
416                                                     }
417
418                                                     // update component restrictions
419                                                     if (!restrictedUsage.has(requiredPermission.id)) {
420                                                         restrictedUsage.set(requiredPermission.id, []);
421                                                     }
422
423                                                     restrictedUsage.get(requiredPermission.id).push({
424                                                         type: nfCommon.formatType(documentedType),
425                                                         bundle: nfCommon.formatBundle(documentedType.bundle),
426                                                         explanation: nfCommon.escapeHtml(explicitRestriction.explanation)
427                                                     })
428                                                 });
429                                             } else {
430                                                 // update required permissions
431                                                 if (!requiredPermissions.has(generalRestriction.value)) {
432                                                     requiredPermissions.set(generalRestriction.value, generalRestriction.text);
433                                                 }
434
435                                                 // update component restrictions
436                                                 if (!restrictedUsage.has(generalRestriction.value)) {
437                                                     restrictedUsage.set(generalRestriction.value, []);
438                                                 }
439
440                                                 restrictedUsage.get(generalRestriction.value).push({
441                                                     type: nfCommon.formatType(documentedType),
442                                                     bundle: nfCommon.formatBundle(documentedType.bundle),
443                                                     explanation: nfCommon.escapeHtml(documentedType.usageRestriction)
444                                                 });
445                                             }
446                                         }
447
448                                         // record the group
449                                         groups.add(documentedType.bundle.group);
450
451                                         // create the row for the processor type
452                                         processorTypesData.addItem({
453                                             id: i,
454                                             label: nfCommon.substringAfterLast(type, '.'),
455                                             type: type,
456                                             bundle: documentedType.bundle,
457                                             description: nfCommon.escapeHtml(documentedType.description),
458                                             restricted:  documentedType.restricted,
459                                             usageRestriction: nfCommon.escapeHtml(documentedType.usageRestriction),
460                                             explicitRestrictions: documentedType.explicitRestrictions,
461                                             tags: documentedType.tags.join(', ')
462                                         });
463
464                                         // count the frequency of each tag for this type
465                                         $.each(documentedType.tags, function (i, tag) {
466                                             tags.push(tag.toLowerCase());
467                                         });
468                                     });
469
470                                     // end the update
471                                     processorTypesData.endUpdate();
472
473                                     // resort
474                                     processorTypesData.reSort();
475                                     processorTypesGrid.invalidate();
476
477                                     // set the component restrictions and the corresponding required permissions
478                                     nfCanvasUtils.addComponentRestrictions(restrictedUsage, requiredPermissions);
479
480                                     // set the total number of processors
481                                     $('#total-processor-types, #displayed-processor-types').text(response.processorTypes.length);
482
483                                     // create the tag cloud
484                                     $('#processor-tag-cloud').tagcloud({
485                                         tags: tags,
486                                         select: applyFilter,
487                                         remove: applyFilter
488                                     });
489
490                                     // build the combo options
491                                     var options = [{
492                                         text: 'all groups',
493                                         value: ''
494                                     }];
495                                     groups.each(function (group) {
496                                         options.push({
497                                             text: group,
498                                             value: group
499                                         });
500                                     });
501
502                                     // initialize the bundle group combo
503                                     $('#processor-bundle-group-combo').combo({
504                                         options: options,
505                                         select: applyFilter
506                                     });
507                                 }).fail(nfErrorHandler.handleAjaxError);
508
509 //************* REPLICATED CODE---ENDS HERE------******************
510
511
512
513             // clear the selected tag cloud
514             $('#processor-tag-cloud').tagcloud('clearSelectedTags');
515
516             // reset the group combo
517             $('#processor-bundle-group-combo').combo('setSelectedOption', {
518                 value: ''
519             });
520
521             // clear any filter strings
522             $('#processor-type-filter').val('');
523
524             // reapply the filter
525             applyFilter();
526
527             // clear the selected row
528             $('#processor-type-description').attr('title', '').text('');
529             $('#processor-type-name').attr('title', '').text('');
530             $('#processor-type-bundle').attr('title', '').text('');
531             $('#selected-processor-name').text('');
532             $('#selected-processor-type').text('').removeData('bundle');
533
534             // unselect any current selection
535             var processTypesGrid = $('#processor-types-table').data('gridInstance');
536             processTypesGrid.setSelectedRows([]);
537             processTypesGrid.resetActiveCell();
538         };
539
540         /**
541          * Create the processor and add to the graph.
542          *
543          * @argument {string} name              The processor name.
544          * @argument {string} processorType     The processor type.
545          * @argument {object} bundle            The processor bundle.
546          * @argument {object} pt                The point that the processor was dropped.
547          */
548         var createProcessor = function (name, processorType, bundle, pt) {
549             var processorEntity = {
550                 'revision': nfClient.getRevision({
551                     'revision': {
552                         'version': 0
553                     }
554                 }),
555                 'disconnectedNodeAcknowledged': nfStorage.isDisconnectionAcknowledged(),
556                 'component': {
557                     'type': processorType,
558                     'bundle': bundle,
559                     'name': name,
560                     'position': {
561                         'x': pt.x,
562                         'y': pt.y
563                     }
564                 }
565             };
566
567             // create a new processor of the defined type
568             $.ajax({
569                 type: 'POST',
570                 url: serviceProvider.headerCtrl.toolboxCtrl.config.urls.api + '/process-groups/' + encodeURIComponent(nfCanvasUtils.getGroupId()) + '/processors',
571                 data: JSON.stringify(processorEntity),
572                 dataType: 'json',
573                 contentType: 'application/json'
574             }).done(function (response) {
575                 // add the processor to the graph
576                 nfGraph.add({
577                     'processors': [response]
578                 }, {
579                     'selectAll': true
580                 });
581
582                 // update component visibility
583                 nfGraph.updateVisibility();
584
585                 // update the birdseye
586                 nfBirdseye.refresh();
587             }).fail(nfErrorHandler.handleAjaxError);
588         };
589
590         /**
591          * Whether the specified item is selectable.
592          *
593          * @param item process type
594          */
595         var isSelectable = function (item) {
596             return item.restricted === false || nfCommon.canAccessComponentRestrictions(item.explicitRestrictions);
597         };
598
599         function ProcessorComponent() {
600
601             this.icon = 'icon icon-processor';
602
603             this.hoverIcon = 'icon icon-processor-add';
604
605             /**
606              * The processor component's modal.
607              */
608             this.modal = {
609
610                 /**
611                  * The processor component modal's filter.
612                  */
613                 filter: {
614
615                     /**
616                      * Initialize the filter.
617                      */
618                     init: function () {
619                         // initialize the processor type table
620                         var processorTypesColumns = [
621                             {
622                                 id: 'type',
623                                 name: 'Type',
624                                 field: 'label',
625                                 formatter: nfCommon.typeFormatter,
626                                 sortable: true,
627                                 resizable: true
628                             },
629                             {
630                                 id: 'version',
631                                 name: 'Version',
632                                 field: 'version',
633                                 formatter: nfCommon.typeVersionFormatter,
634                                 sortable: true,
635                                 resizable: true
636                             },
637                             {
638                                 id: 'tags',
639                                 name: 'Tags',
640                                 field: 'tags',
641                                 sortable: true,
642                                 resizable: true,
643                                 formatter: nfCommon.genericValueFormatter
644                             }
645                         ];
646
647                         var processorTypesOptions = {
648                             forceFitColumns: true,
649                             enableTextSelectionOnCells: true,
650                             enableCellNavigation: true,
651                             enableColumnReorder: false,
652                             autoEdit: false,
653                             multiSelect: false,
654                             rowHeight: 24
655                         };
656
657                         // initialize the dataview
658                         processorTypesData = new Slick.Data.DataView({
659                             inlineFilters: false
660                         });
661                         processorTypesData.setItems([]);
662                         processorTypesData.setFilterArgs({
663                             searchString: getFilterText()
664                         });
665                         processorTypesData.setFilter(filter);
666
667                         // initialize the sort
668                         nfCommon.sortType({
669                             columnId: 'type',
670                             sortAsc: true
671                         }, processorTypesData);
672
673                         // initialize the grid
674                         var processorTypesGrid = new Slick.Grid('#processor-types-table', processorTypesData, processorTypesColumns, processorTypesOptions);
675                         processorTypesGrid.setSelectionModel(new Slick.RowSelectionModel());
676                         processorTypesGrid.registerPlugin(new Slick.AutoTooltips());
677                         processorTypesGrid.setSortColumn('type', true);
678                         processorTypesGrid.onSort.subscribe(function (e, args) {
679                             nfCommon.sortType({
680                                 columnId: args.sortCol.field,
681                                 sortAsc: args.sortAsc
682                             }, processorTypesData);
683                         });
684                         processorTypesGrid.onSelectedRowsChanged.subscribe(function (e, args) {
685                             if ($.isArray(args.rows) && args.rows.length === 1) {
686                                 var processorTypeIndex = args.rows[0];
687                                 var processorType = processorTypesGrid.getDataItem(processorTypeIndex);
688
689                                 // set the processor type description
690                                 if (nfCommon.isDefinedAndNotNull(processorType)) {
691                                     if (nfCommon.isBlank(processorType.description)) {
692                                         $('#processor-type-description')
693                                             .attr('title', '')
694                                             .html('<span class="unset">No description specified</span>');
695                                     } else {
696                                         $('#processor-type-description')
697                                             .width($('#processor-description-container').innerWidth() - 1)
698                                             .html(processorType.description)
699                                             .ellipsis();
700                                     }
701
702                                     var bundle = nfCommon.formatBundle(processorType.bundle);
703                                     var type = nfCommon.formatType(processorType);
704
705                                     // populate the dom
706                                     $('#processor-type-name').text(type).attr('title', type);
707                                     $('#processor-type-bundle').text(bundle).attr('title', bundle);
708                                     $('#selected-processor-name').text(processorType.label);
709                                     $('#selected-processor-type').text(processorType.type).data('bundle', processorType.bundle);
710
711                                     // refresh the buttons based on the current selection
712                                     $('#new-processor-dialog').modal('refreshButtons');
713                                 }
714                             }
715                         });
716                         processorTypesGrid.onViewportChanged.subscribe(function (e, args) {
717                             nfCommon.cleanUpTooltips($('#processor-types-table'), 'div.view-usage-restriction');
718                         });
719
720                         // wire up the dataview to the grid
721                         processorTypesData.onRowCountChanged.subscribe(function (e, args) {
722                             processorTypesGrid.updateRowCount();
723                             processorTypesGrid.render();
724
725                             // update the total number of displayed processors
726                             $('#displayed-processor-types').text(args.current);
727                         });
728                         processorTypesData.onRowsChanged.subscribe(function (e, args) {
729                             processorTypesGrid.invalidateRows(args.rows);
730                             processorTypesGrid.render();
731                         });
732                         processorTypesData.syncGridSelection(processorTypesGrid, false);
733
734                         // hold onto an instance of the grid
735                         $('#processor-types-table').data('gridInstance', processorTypesGrid).on('mouseenter', 'div.slick-cell', function (e) {
736                             var usageRestriction = $(this).find('div.view-usage-restriction');
737                             if (usageRestriction.length && !usageRestriction.data('qtip')) {
738                                 var rowId = $(this).find('span.row-id').text();
739
740                                 // get the status item
741                                 var item = processorTypesData.getItemById(rowId);
742
743                                 // show the tooltip
744                                 if (item.restricted === true) {
745                                     var restrictionTip = $('<div></div>');
746
747                                     if (nfCommon.isBlank(item.usageRestriction)) {
748                                         restrictionTip.append($('<p style="margin-bottom: 3px;"></p>').text('Requires the following permissions:'));
749                                     } else {
750                                         restrictionTip.append($('<p style="margin-bottom: 3px;"></p>').text(item.usageRestriction + ' Requires the following permissions:'));
751                                     }
752
753                                     var restrictions = [];
754                                     if (nfCommon.isDefinedAndNotNull(item.explicitRestrictions)) {
755                                         $.each(item.explicitRestrictions, function (_, explicitRestriction) {
756                                             var requiredPermission = explicitRestriction.requiredPermission;
757                                             restrictions.push("'" + requiredPermission.label + "' - " + nfCommon.escapeHtml(explicitRestriction.explanation));
758                                         });
759                                     } else {
760                                         restrictions.push('Access to restricted components regardless of restrictions.');
761                                     }
762                                     restrictionTip.append(nfCommon.formatUnorderedList(restrictions));
763
764                                     usageRestriction.qtip($.extend({}, nfCommon.config.tooltipConfig, {
765                                         content: restrictionTip,
766                                         position: {
767                                             container: $('#summary'),
768                                             at: 'bottom right',
769                                             my: 'top left',
770                                             adjust: {
771                                                 x: 4,
772                                                 y: 4
773                                             }
774                                         }
775                                     }));
776                                 }
777                             }
778                         });
779
780                         var generalRestriction = nfCommon.getPolicyTypeListing('restricted-components');
781
782                         // load the available processor types, this select is shown in the
783                         // new processor dialog when a processor is dragged onto the screen
784                         $.ajax({
785                             type: 'GET',
786                             url:'../nifi-api/flow/processor-types',
787 //                            url: serviceProvider.headerCtrl.toolboxCtrl.config.urls.processorTypes,
788                             dataType: 'json'
789                         }).done(function (response) {
790                             console.log(response);
791                             var tags = [];
792                             var groups = d3.set();
793                             var restrictedUsage = d3.map();
794                             var requiredPermissions = d3.map();
795
796                             // begin the update
797                             processorTypesData.beginUpdate();
798
799                             // go through each processor type
800                             $.each(response.processorTypes, function (i, documentedType) {
801                                 var type = documentedType.type;
802
803                                 if (documentedType.restricted === true) {
804                                     if (nfCommon.isDefinedAndNotNull(documentedType.explicitRestrictions)) {
805                                         $.each(documentedType.explicitRestrictions, function (_, explicitRestriction) {
806                                             var requiredPermission = explicitRestriction.requiredPermission;
807
808                                             // update required permissions
809                                             if (!requiredPermissions.has(requiredPermission.id)) {
810                                                 requiredPermissions.set(requiredPermission.id, requiredPermission.label);
811                                             }
812
813                                             // update component restrictions
814                                             if (!restrictedUsage.has(requiredPermission.id)) {
815                                                 restrictedUsage.set(requiredPermission.id, []);
816                                             }
817
818                                             restrictedUsage.get(requiredPermission.id).push({
819                                                 type: nfCommon.formatType(documentedType),
820                                                 bundle: nfCommon.formatBundle(documentedType.bundle),
821                                                 explanation: nfCommon.escapeHtml(explicitRestriction.explanation)
822                                             })
823                                         });
824                                     } else {
825                                         // update required permissions
826                                         if (!requiredPermissions.has(generalRestriction.value)) {
827                                             requiredPermissions.set(generalRestriction.value, generalRestriction.text);
828                                         }
829
830                                         // update component restrictions
831                                         if (!restrictedUsage.has(generalRestriction.value)) {
832                                             restrictedUsage.set(generalRestriction.value, []);
833                                         }
834
835                                         restrictedUsage.get(generalRestriction.value).push({
836                                             type: nfCommon.formatType(documentedType),
837                                             bundle: nfCommon.formatBundle(documentedType.bundle),
838                                             explanation: nfCommon.escapeHtml(documentedType.usageRestriction)
839                                         });
840                                     }
841                                 }
842
843                                 // record the group
844                                 groups.add(documentedType.bundle.group);
845
846                                 // create the row for the processor type
847                                 processorTypesData.addItem({
848                                     id: i,
849                                     label: nfCommon.substringAfterLast(type, '.'),
850                                     type: type,
851                                     bundle: documentedType.bundle,
852                                     description: nfCommon.escapeHtml(documentedType.description),
853                                     restricted:  documentedType.restricted,
854                                     usageRestriction: nfCommon.escapeHtml(documentedType.usageRestriction),
855                                     explicitRestrictions: documentedType.explicitRestrictions,
856                                     tags: documentedType.tags.join(', ')
857                                 });
858
859                                 // count the frequency of each tag for this type
860                                 $.each(documentedType.tags, function (i, tag) {
861                                     tags.push(tag.toLowerCase());
862                                 });
863                             });
864
865                             // end the update
866                             processorTypesData.endUpdate();
867
868                             // resort
869                             processorTypesData.reSort();
870                             processorTypesGrid.invalidate();
871
872                             // set the component restrictions and the corresponding required permissions
873                             nfCanvasUtils.addComponentRestrictions(restrictedUsage, requiredPermissions);
874
875                             // set the total number of processors
876                             $('#total-processor-types, #displayed-processor-types').text(response.processorTypes.length);
877
878                             // create the tag cloud
879                             $('#processor-tag-cloud').tagcloud({
880                                 tags: tags,
881                                 select: applyFilter,
882                                 remove: applyFilter
883                             });
884
885                             // build the combo options
886                             var options = [{
887                                 text: 'all groups',
888                                 value: ''
889                             }];
890                             groups.each(function (group) {
891                                 options.push({
892                                     text: group,
893                                     value: group
894                                 });
895                             });
896
897                             // initialize the bundle group combo
898                             $('#processor-bundle-group-combo').combo({
899                                 options: options,
900                                 select: applyFilter
901                             });
902                         }).fail(nfErrorHandler.handleAjaxError);
903                     }
904                 },
905
906                 /**
907                  * Gets the modal element.
908                  *
909                  * @returns {*|jQuery|HTMLElement}
910                  */
911                 getElement: function () {
912                     return $('#new-processor-dialog');
913                 },
914
915                 /**
916                  * Initialize the modal.
917                  */
918                 init: function () {
919                     this.filter.init();
920
921                     // configure the new processor dialog
922                     this.getElement().modal({
923                         scrollableContentStyle: 'scrollable',
924                         headerText: 'Add Processor',
925                         handler: {
926                             resize: function () {
927                                 $('#processor-type-description')
928                                     .width($('#processor-description-container').innerWidth() - 1)
929                                     .text($('#processor-type-description').attr('title'))
930                                     .ellipsis();
931                             }
932                         }
933                     });
934                 },
935
936                 /**
937                  * Updates the modal config.
938                  *
939                  * @param {string} name             The name of the property to update.
940                  * @param {object|array} config     The config for the `name`.
941                  */
942                 update: function (name, config) {
943                     this.getElement().modal(name, config);
944                 },
945
946                 /**
947                  * Show the modal
948                  */
949                 show: function () {
950                     this.getElement().modal('show');
951                 },
952
953                 /**
954                  * Hide the modal
955                  */
956                 hide: function () {
957                     this.getElement().modal('hide');
958                 }
959             };
960         }
961
962         ProcessorComponent.prototype = {
963             constructor: ProcessorComponent,
964
965             /**
966              * Gets the component.
967              *
968              * @returns {*|jQuery|HTMLElement}
969              */
970             getElement: function () {
971                 return $('#processor-component');
972             },
973
974             /**
975              * Enable the component.
976              */
977             enabled: function () {
978                 this.getElement().attr('disabled', false);
979             },
980
981             /**
982              * Disable the component.
983              */
984             disabled: function () {
985                 this.getElement().attr('disabled', true);
986             },
987
988             /**
989              * Handler function for when component is dropped on the canvas.
990              *
991              * @argument {object} pt        The point that the component was dropped
992              */
993             dropHandler: function (pt) {
994                 this.promptForProcessorType(pt);
995             },
996
997             /**
998              * The drag icon for the toolbox component.
999              *
1000              * @param event
1001              * @returns {*|jQuery|HTMLElement}
1002              */
1003             dragIcon: function (event) {
1004                 return $('<div class="icon icon-processor-add"></div>');
1005             },
1006
1007             /**
1008              * Prompts the user to select the type of new processor to create.
1009              *
1010              * @argument {object} pt        The point that the processor was dropped
1011              */
1012             promptForProcessorType: function (pt) {
1013                 var processorComponent = this;
1014
1015                 // handles adding the selected processor at the specified point
1016                 var addProcessor = function () {
1017                     // get the type of processor currently selected
1018                     var name = $('#selected-processor-name').text();
1019                     var processorType = $('#selected-processor-type').text();
1020                     var bundle = $('#selected-processor-type').data('bundle');
1021
1022                     // ensure something was selected
1023                     if (name === '' || processorType === '') {
1024                         nfDialog.showOkDialog({
1025                             headerText: 'Add Processor',
1026                             dialogContent: 'The type of processor to create must be selected.'
1027                         });
1028                     } else {
1029                         // create the new processor
1030                         createProcessor(name, processorType, bundle, pt);
1031                     }
1032
1033                     // hide the dialog
1034                     processorComponent.modal.hide();
1035                 };
1036
1037                 // get the grid reference
1038                 var grid = $('#processor-types-table').data('gridInstance');
1039                 var dataview = grid.getData();
1040
1041                 // add the processor when its double clicked in the table
1042                 var gridDoubleClick = function (e, args) {
1043                     var processorType = grid.getDataItem(args.row);
1044
1045                     if (isSelectable(processorType)) {
1046                         $('#selected-processor-name').text(processorType.label);
1047                         $('#selected-processor-type').text(processorType.type).data('bundle', processorType.bundle);
1048
1049                         addProcessor();
1050                     }
1051                 };
1052
1053                 // register a handler for double click events
1054                 grid.onDblClick.subscribe(gridDoubleClick);
1055
1056                 // update the button model
1057                 this.modal.update('setButtonModel', [{
1058                     buttonText: 'Add',
1059                     color: {
1060                         base: '#728E9B',
1061                         hover: '#004849',
1062                         text: '#ffffff'
1063                     },
1064                     disabled: function () {
1065                         var selected = grid.getSelectedRows();
1066
1067                         if (selected.length > 0) {
1068                             // grid configured with multi-select = false
1069                             var item = grid.getDataItem(selected[0]);
1070                             return isSelectable(item) === false;
1071                         } else {
1072                             return dataview.getLength() === 0;
1073                         }
1074                     },
1075                     handler: {
1076                         click: addProcessor
1077                     }
1078                 },
1079                     {
1080                         buttonText: 'Cancel',
1081                         color: {
1082                             base: '#E3E8EB',
1083                             hover: '#C7D2D7',
1084                             text: '#004849'
1085                         },
1086                         handler: {
1087                             click: function () {
1088                                 $('#new-processor-dialog').modal('hide');
1089                             }
1090                         }
1091                     }]);
1092
1093                 // set a new handler for closing the the dialog
1094                 this.modal.update('setCloseHandler', function () {
1095                     // remove the handler
1096                     grid.onDblClick.unsubscribe(gridDoubleClick);
1097
1098                     // clear the current filters
1099                     resetProcessorDialog();
1100                 });
1101
1102                 // show the dialog
1103                 this.modal.show();
1104
1105                 var navigationKeys = [$.ui.keyCode.UP, $.ui.keyCode.PAGE_UP, $.ui.keyCode.DOWN, $.ui.keyCode.PAGE_DOWN];
1106
1107                 // setup the filter
1108                 $('#processor-type-filter').off('keyup').on('keyup', function (e) {
1109                     var code = e.keyCode ? e.keyCode : e.which;
1110
1111                     // ignore navigation keys
1112                     if ($.inArray(code, navigationKeys) !== -1) {
1113                         return;
1114                     }
1115
1116                     if (code === $.ui.keyCode.ENTER) {
1117                         var selected = grid.getSelectedRows();
1118
1119                         if (selected.length > 0) {
1120                             // grid configured with multi-select = false
1121                             var item = grid.getDataItem(selected[0]);
1122                             if (isSelectable(item)) {
1123                                 addProcessor();
1124                             }
1125                         }
1126                     } else {
1127                         applyFilter();
1128                     }
1129                 });
1130
1131                 // setup row navigation
1132                 nfFilteredDialogCommon.addKeydownListener('#processor-type-filter', grid, dataview);
1133
1134                 // adjust the grid canvas now that its been rendered
1135                 grid.resizeCanvas();
1136
1137                 // auto select the first row if possible
1138                 if (dataview.getLength() > 0) {
1139                     nfFilteredDialogCommon.choseFirstRow(grid);
1140                 }
1141
1142                 // set the initial focus
1143                 $('#processor-type-filter').focus()
1144             }
1145         };
1146
1147         var processorComponent = new ProcessorComponent();
1148         return processorComponent;
1149     };
1150 }));