summaryrefslogtreecommitdiffstats
path: root/mod/designtool/designtool-web/src/main/webapp
diff options
context:
space:
mode:
authorVijay Venkatesh Kumar <vv770d@att.com>2020-02-10 23:00:13 +0000
committerGerrit Code Review <gerrit@onap.org>2020-02-10 23:00:13 +0000
commit45341fa5e6e64e86286254d49ca951c43726ab94 (patch)
tree6bf7eeb9143b1a23aa823f924f0922de11854d88 /mod/designtool/designtool-web/src/main/webapp
parente0734cbb649157811a8a00dbb8e2dad2cbe28782 (diff)
parent9507f2f8d2ec616f01f5ee8825106300b95e8ddc (diff)
Merge "Add DCAE MOD design tool project"
Diffstat (limited to 'mod/designtool/designtool-web/src/main/webapp')
-rw-r--r--mod/designtool/designtool-web/src/main/webapp/WEB-INF/pages/canvas.jsp167
-rw-r--r--mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/canvas-header.jsp191
-rw-r--r--mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/connection-configuration.jsp218
-rw-r--r--mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/distribution-environment-dialog.jsp42
-rw-r--r--mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/flow-status.jsp33
-rw-r--r--mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/navigation.jsp129
-rw-r--r--mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/settings-content.jsp86
-rw-r--r--mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/shell.jsp34
-rw-r--r--mod/designtool/designtool-web/src/main/webapp/css/navigation.css338
-rw-r--r--mod/designtool/designtool-web/src/main/webapp/images/dcae-logo.pngbin0 -> 36755 bytes
-rw-r--r--mod/designtool/designtool-web/src/main/webapp/js/jquery/dcae-mod.js135
-rw-r--r--mod/designtool/designtool-web/src/main/webapp/js/nf/canvas/controllers/nf-ng-breadcrumbs-controller.js288
-rw-r--r--mod/designtool/designtool-web/src/main/webapp/js/nf/canvas/header/components/nf-ng-processor-component.js1150
-rw-r--r--mod/designtool/designtool-web/src/main/webapp/js/nf/canvas/nf-connection-configuration.js1587
-rw-r--r--mod/designtool/designtool-web/src/main/webapp/js/nf/canvas/nf-flow-version.js1990
-rw-r--r--mod/designtool/designtool-web/src/main/webapp/js/nf/canvas/nf-process-group.js1744
-rw-r--r--mod/designtool/designtool-web/src/main/webapp/js/nf/canvas/nf-settings.js2373
17 files changed, 10505 insertions, 0 deletions
diff --git a/mod/designtool/designtool-web/src/main/webapp/WEB-INF/pages/canvas.jsp b/mod/designtool/designtool-web/src/main/webapp/WEB-INF/pages/canvas.jsp
new file mode 100644
index 0000000..ccfee0c
--- /dev/null
+++ b/mod/designtool/designtool-web/src/main/webapp/WEB-INF/pages/canvas.jsp
@@ -0,0 +1,167 @@
+<%--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Modifications to the original nifi code for the ONAP project are made
+ available under the Apache License, Version 2.0
+--%>
+<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>NiFi</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+ <link rel="shortcut icon" href="images/nifi16.ico"/>
+ <link rel="stylesheet" href="assets/reset.css/reset.css" type="text/css" />
+ ${nf.canvas.style.tags}
+ <link rel="stylesheet" href="js/codemirror/lib/codemirror.css" type="text/css" />
+ <link rel="stylesheet" href="js/codemirror/addon/hint/show-hint.css" type="text/css" />
+ <link rel="stylesheet" href="js/jquery/nfeditor/jquery.nfeditor.css?${project.version}" type="text/css" />
+ <link rel="stylesheet" href="js/jquery/nfeditor/languages/nfel.css?${project.version}" type="text/css" />
+ <link rel="stylesheet" href="js/jquery/tabbs/jquery.tabbs.css?${project.version}" type="text/css" />
+ <link rel="stylesheet" href="js/jquery/combo/jquery.combo.css?${project.version}" type="text/css" />
+ <link rel="stylesheet" href="js/jquery/propertytable/jquery.propertytable.css?${project.version}" type="text/css" />
+ <link rel="stylesheet" href="js/jquery/tagcloud/jquery.tagcloud.css?${project.version}" type="text/css" />
+ <link rel="stylesheet" href="js/jquery/modal/jquery.modal.css?${project.version}" type="text/css" />
+ <link rel="stylesheet" href="assets/qtip2/dist/jquery.qtip.min.css?" type="text/css" />
+ <link rel="stylesheet" href="assets/jquery-ui-dist/jquery-ui.min.css" type="text/css" />
+ <link rel="stylesheet" href="assets/jquery-minicolors/jquery.minicolors.css" type="text/css" />
+ <link rel="stylesheet" href="assets/slickgrid/slick.grid.css" type="text/css" />
+ <link rel="stylesheet" href="css/slick-nifi-theme.css" type="text/css" />
+ <link rel="stylesheet" href="fonts/flowfont/flowfont.css" type="text/css" />
+ <link rel="stylesheet" href="assets/angular-material/angular-material.min.css" type="text/css" />
+ <link rel="stylesheet" href="assets/font-awesome/css/font-awesome.min.css" type="text/css" />
+ <script>
+ //force browsers to use URLSearchParams polyfill do to bugs and inconsistent browser implementations
+ URLSearchParams = undefined;
+ </script>
+ <script type="text/javascript" src="assets/url-search-params/build/url-search-params.js"></script>
+ <script type="text/javascript" src="js/codemirror/lib/codemirror-compressed.js"></script>
+ <script type="text/javascript" src="assets/d3/build/d3.min.js"></script>
+ <script type="text/javascript" src="assets/d3-selection-multi/build/d3-selection-multi.min.js"></script>
+ <script type="text/javascript" src="assets/jquery/dist/jquery.min.js"></script>
+ <script type="text/javascript" src="assets/jquery-ui-dist/jquery-ui.min.js"></script>
+ <script type="text/javascript" src="js/jquery/jquery.base64.js"></script>
+ <script type="text/javascript" src="js/jquery/jquery.center.js"></script>
+ <script type="text/javascript" src="js/jquery/jquery.ellipsis.js"></script>
+ <script type="text/javascript" src="js/jquery/jquery.each.js"></script>
+ <script type="text/javascript" src="js/jquery/jquery.tab.js"></script>
+ <script type="text/javascript" src="assets/jquery-form/jquery.form.js"></script>
+ <script type="text/javascript" src="js/jquery/tabbs/jquery.tabbs.js?${project.version}"></script>
+ <script type="text/javascript" src="js/jquery/combo/jquery.combo.js?${project.version}"></script>
+ <script type="text/javascript" src="js/jquery/modal/jquery.modal.js?${project.version}"></script>
+ <script type="text/javascript" src="assets/jquery-minicolors/jquery.minicolors.min.js"></script>
+ <script type="text/javascript" src="assets/qtip2/dist/jquery.qtip.min.js"></script>
+ <script type="text/javascript" src="assets/slickgrid/lib/jquery.event.drag-2.3.0.js"></script>
+ <script type="text/javascript" src="assets/slickgrid/plugins/slick.cellrangeselector.js"></script>
+ <script type="text/javascript" src="assets/slickgrid/plugins/slick.cellselectionmodel.js"></script>
+ <script type="text/javascript" src="assets/slickgrid/plugins/slick.rowselectionmodel.js"></script>
+ <script type="text/javascript" src="assets/slickgrid/plugins/slick.autotooltips.js"></script>
+ <script type="text/javascript" src="assets/slickgrid/slick.formatters.js"></script>
+ <script type="text/javascript" src="assets/slickgrid/slick.editors.js"></script>
+ <script type="text/javascript" src="assets/slickgrid/slick.dataview.js"></script>
+ <script type="text/javascript" src="assets/slickgrid/slick.core.js"></script>
+ <script type="text/javascript" src="assets/slickgrid/slick.grid.js"></script>
+ <script type="text/javascript" src="assets/angular/angular.min.js"></script>
+ <script type="text/javascript" src="assets/angular-messages/angular-messages.min.js"></script>
+ <script type="text/javascript" src="assets/angular-resource/angular-resource.min.js"></script>
+ <script type="text/javascript" src="assets/angular-route/angular-route.min.js"></script>
+ <script type="text/javascript" src="assets/angular-aria/angular-aria.min.js"></script>
+ <script type="text/javascript" src="assets/angular-animate/angular-animate.min.js"></script>
+ <script type="text/javascript" src="assets/angular-material/angular-material.min.js"></script>
+ <script type="text/javascript" src="assets/JSON2/json2.js"></script>
+ <script type="text/javascript" src="js/nf/nf-namespace.js?${project.version}"></script>
+ <script type="text/javascript" src="js/nf/nf-ng-namespace.js?${project.version}"></script>
+ <script type="text/javascript" src="js/nf/canvas/nf-ng-canvas-namespace.js?${project.version}"></script>
+ ${nf.canvas.script.tags}
+ <script type="text/javascript" src="js/jquery/nfeditor/languages/nfel.js?${project.version}"></script>
+ <script type="text/javascript" src="js/jquery/nfeditor/jquery.nfeditor.js?${project.version}"></script>
+ <script type="text/javascript" src="js/jquery/propertytable/jquery.propertytable.js?${project.version}"></script>
+ <script type="text/javascript" src="js/jquery/tagcloud/jquery.tagcloud.js?${project.version}"></script>
+
+ <script type="text/javascript" src="js/jquery/dcae-mod.js"></script>
+
+ </head>
+ <body ng-controller="ngCanvasAppCtrl" id="canvas-body">
+ <div id="splash">
+ <div id="splash-img" layout="row" layout-align="center center">
+ <md-progress-circular md-mode="indeterminate" class="md-warn" md-diameter="150"></md-progress-circular>
+ </div>
+ </div>
+ <jsp:include page="/WEB-INF/partials/message-pane.jsp"/>
+ <jsp:include page="/WEB-INF/partials/banners-main.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/canvas-header.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/flow-status.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/about-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/ok-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/yes-no-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/status-history-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/search-users-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/disable-controller-service-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/enable-controller-service-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/new-controller-service-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/new-reporting-task-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/new-processor-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/new-port-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/new-process-group-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/new-remote-process-group-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/new-template-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/upload-template-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/instantiate-template-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/fill-color-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/connections-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/save-flow-version-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/import-flow-version-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/revert-local-changes-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/show-local-changes-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/registry-configuration-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/distribution-environment-dialog.jsp"/>
+ <div id="canvas-container" class="unselectable"></div>
+ <div id="canvas-tooltips">
+ <div id="processor-tooltips"></div>
+ <div id="port-tooltips"></div>
+ <div id="process-group-tooltips"></div>
+ <div id="remote-process-group-tooltips"></div>
+ </div>
+ <jsp:include page="/WEB-INF/partials/canvas/navigation.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/settings-content.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/shell.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/controller-service-configuration.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/reporting-task-configuration.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/processor-configuration.jsp"/>
+ <jsp:include page="/WEB-INF/partials/processor-details.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/variable-configuration.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/process-group-configuration.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/override-policy-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/policy-management.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/remote-process-group-configuration.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/remote-process-group-details.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/remote-process-group-ports.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/remote-port-configuration.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/port-configuration.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/port-details.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/label-configuration.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/connection-configuration.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/drop-request-status-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/flowfile-details-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/listing-request-status-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/queue-listing.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/component-state-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/canvas/component-version-dialog.jsp"/>
+ <jsp:include page="/WEB-INF/partials/connection-details.jsp"/>
+ <div id="context-menu" class="context-menu unselectable"></div>
+ <span id="nifi-content-viewer-url" class="hidden"></span>
+ </body>
+</html>
diff --git a/mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/canvas-header.jsp b/mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/canvas-header.jsp
new file mode 100644
index 0000000..3afbe66
--- /dev/null
+++ b/mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/canvas-header.jsp
@@ -0,0 +1,191 @@
+<%--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Modifications to the original nifi code for the ONAP project are made
+ available under the Apache License, Version 2.0
+--%>
+<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
+<md-toolbar id="header" layout-align="space-between center" layout="row" class="md-small md-accent md-hue-1">
+ <img id="nifi-logo" src="images/dcae-logo.png">
+ <div flex layout="row" layout-align="space-between center">
+ <div id="component-container">
+ <button title="{{appCtrl.serviceProvider.headerCtrl.toolboxCtrl.config.type.processor}}"
+ id="processor-component"
+ class="component-button icon icon-processor"
+ ng-disabled="!appCtrl.nf.CanvasUtils.canWriteCurrentGroup();"
+ nf-draggable="appCtrl.serviceProvider.headerCtrl.toolboxCtrl.draggableComponentConfig(appCtrl.serviceProvider.headerCtrl.toolboxCtrl.processorComponent);">
+ <span class="component-button-grip"></span>
+ </button>
+ <button title="{{appCtrl.serviceProvider.headerCtrl.toolboxCtrl.config.type.inputPort}}"
+ id="port-in-component"
+ class="component-button icon icon-port-in"
+ ng-disabled="!appCtrl.nf.CanvasUtils.canWriteCurrentGroup();"
+ nf-draggable="appCtrl.serviceProvider.headerCtrl.toolboxCtrl.draggableComponentConfig(appCtrl.serviceProvider.headerCtrl.toolboxCtrl.inputPortComponent);">
+ <span class="component-button-grip"></span>
+ </button>
+ <button title="{{appCtrl.serviceProvider.headerCtrl.toolboxCtrl.config.type.outputPort}}"
+ id="port-out-component"
+ class="component-button icon icon-port-out"
+ ng-disabled="!appCtrl.nf.CanvasUtils.canWriteCurrentGroup();"
+ nf-draggable="appCtrl.serviceProvider.headerCtrl.toolboxCtrl.draggableComponentConfig(appCtrl.serviceProvider.headerCtrl.toolboxCtrl.outputPortComponent);">
+ <span class="component-button-grip"></span>
+ </button>
+ <button title="{{appCtrl.serviceProvider.headerCtrl.toolboxCtrl.config.type.processGroup}}"
+ id="group-component"
+ class="component-button icon icon-group"
+ ng-disabled="!appCtrl.nf.CanvasUtils.canWriteCurrentGroup();"
+ nf-draggable="appCtrl.serviceProvider.headerCtrl.toolboxCtrl.draggableComponentConfig(appCtrl.serviceProvider.headerCtrl.toolboxCtrl.groupComponent);">
+ <span class="component-button-grip"></span>
+ </button>
+ <button title="{{appCtrl.serviceProvider.headerCtrl.toolboxCtrl.config.type.remoteProcessGroup}}"
+ id="group-remote-component"
+ class="component-button icon icon-group-remote"
+ ng-disabled="!appCtrl.nf.CanvasUtils.canWriteCurrentGroup();"
+ nf-draggable="appCtrl.serviceProvider.headerCtrl.toolboxCtrl.draggableComponentConfig(appCtrl.serviceProvider.headerCtrl.toolboxCtrl.remoteGroupComponent);">
+ <span class="component-button-grip"></span>
+ </button>
+ <button title="{{appCtrl.serviceProvider.headerCtrl.toolboxCtrl.config.type.funnel}}"
+ id="funnel-component"
+ class="component-button icon icon-funnel"
+ ng-disabled="!appCtrl.nf.CanvasUtils.canWriteCurrentGroup();"
+ nf-draggable="appCtrl.serviceProvider.headerCtrl.toolboxCtrl.draggableComponentConfig(appCtrl.serviceProvider.headerCtrl.toolboxCtrl.funnelComponent);">
+ <span class="component-button-grip"></span>
+ </button>
+ <button title="{{appCtrl.serviceProvider.headerCtrl.toolboxCtrl.config.type.template}}"
+ id="template-component"
+ class="component-button icon icon-template"
+ ng-disabled="!appCtrl.nf.CanvasUtils.canWriteCurrentGroup();"
+ nf-draggable="appCtrl.serviceProvider.headerCtrl.toolboxCtrl.draggableComponentConfig(appCtrl.serviceProvider.headerCtrl.toolboxCtrl.templateComponent);">
+ <span class="component-button-grip"></span>
+ </button>
+ <button title="{{appCtrl.serviceProvider.headerCtrl.toolboxCtrl.config.type.label}}"
+ id="label-component"
+ class="component-button icon icon-label"
+ ng-disabled="!appCtrl.nf.CanvasUtils.canWriteCurrentGroup();"
+ nf-draggable="appCtrl.serviceProvider.headerCtrl.toolboxCtrl.draggableComponentConfig(appCtrl.serviceProvider.headerCtrl.toolboxCtrl.labelComponent);">
+ <span class="component-button-grip"></span>
+ </button>
+ </div>
+ <div layout="row" layout-align="space-between center">
+ <div layout-align="space-between end" layout="column">
+ <div layout="row" layout-align="space-between center" id="current-user-container">
+ <span id="anonymous-user-alert" class="hidden fa fa-warning"></span>
+ <div></div>
+ <div id="current-user"></div>
+ </div>
+ <div id="login-link-container">
+ <span id="login-link" class="link"
+ ng-click="appCtrl.serviceProvider.headerCtrl.loginCtrl.shell.launch();">log in</span>
+ </div>
+ <div id="logout-link-container" style="display: none;">
+ <span id="logout-link" class="link"
+ ng-click="appCtrl.serviceProvider.headerCtrl.logoutCtrl.logout();">log out</span>
+ </div>
+ </div>
+ <md-menu md-position-mode="target-right target" md-offset="-1 44">
+ <button md-menu-origin id="global-menu-button" ng-click="$mdMenu.open()">
+ <div class="fa fa-navicon"></div>
+ </button>
+ <md-menu-content id="global-menu-content">
+ <md-menu-item layout-align="space-around center">
+ <a id="reporting-link"
+ ng-click="appCtrl.serviceProvider.headerCtrl.globalMenuCtrl.summary.shell.launch();">
+ <i class="fa fa-table"></i>Summary
+ </a>
+ </md-menu-item>
+ <md-menu-item layout-align="space-around center">
+ <a id="counters-link"
+ ng-click="appCtrl.serviceProvider.headerCtrl.globalMenuCtrl.counters.shell.launch();"
+ ng-class="{disabled: !appCtrl.nf.Common.canAccessCounters()}">
+ <i class="icon icon-counter"></i>Counters
+ </a>
+ </md-menu-item>
+ <md-menu-item layout-align="space-around center">
+ <a id="bulletin-board-link"
+ ng-click="appCtrl.serviceProvider.headerCtrl.globalMenuCtrl.bulletinBoard.shell.launch();">
+ <i class="fa fa-sticky-note-o"></i>Bulletin Board
+ </a>
+ </md-menu-item>
+ <md-menu-divider></md-menu-divider>
+ <md-menu-item
+ layout-align="space-around center">
+ <a id="provenance-link"
+ ng-click="appCtrl.serviceProvider.headerCtrl.globalMenuCtrl.dataProvenance.shell.launch();"
+ ng-class="{disabled: !appCtrl.nf.Common.canAccessProvenance()}">
+ <i class="icon icon-provenance"></i>Data Provenance
+ </a>
+ </md-menu-item>
+ <md-menu-divider></md-menu-divider>
+ <md-menu-item layout-align="space-around center">
+ <a id="flow-settings-link"
+ ng-click="appCtrl.serviceProvider.headerCtrl.globalMenuCtrl.controllerSettings.shell.launch();">
+ <i class="fa fa-wrench"></i>Controller Settings
+ </a>
+ </md-menu-item>
+ <md-menu-item ng-if="appCtrl.serviceProvider.headerCtrl.globalMenuCtrl.cluster.visible();"
+ layout-align="space-around center">
+ <a id="cluster-link"
+ ng-click="appCtrl.serviceProvider.headerCtrl.globalMenuCtrl.cluster.shell.launch();"
+ ng-class="{disabled: !appCtrl.nf.Common.canAccessController()}">
+ <i class="fa fa-cubes"></i>Cluster
+ </a>
+ </md-menu-item>
+ <md-menu-item layout-align="space-around center">
+ <a id="history-link"
+ ng-click="appCtrl.serviceProvider.headerCtrl.globalMenuCtrl.flowConfigHistory.shell.launch();">
+ <i class="fa fa-history"></i>Flow Configuration History
+ </a>
+ </md-menu-item>
+ <md-menu-divider ng-if="appCtrl.nf.CanvasUtils.isManagedAuthorizer()"></md-menu-divider>
+ <md-menu-item layout-align="space-around center" ng-if="appCtrl.nf.CanvasUtils.isManagedAuthorizer()">
+ <a id="users-link" layout="row"
+ ng-click="appCtrl.serviceProvider.headerCtrl.globalMenuCtrl.users.shell.launch();"
+ ng-class="{disabled: !(appCtrl.nf.Common.canAccessTenants())}">
+ <i class="fa fa-users"></i>Users
+ </a>
+ </md-menu-item>
+ <md-menu-item layout-align="space-around center" ng-if="appCtrl.nf.CanvasUtils.isManagedAuthorizer()">
+ <a id="policies-link" layout="row"
+ ng-click="appCtrl.serviceProvider.headerCtrl.globalMenuCtrl.policies.shell.launch();"
+ ng-class="{disabled: !(appCtrl.nf.Common.canAccessTenants() && appCtrl.nf.Common.canModifyPolicies())}">
+ <i class="fa fa-key"></i>Policies
+ </a>
+ </md-menu-item>
+ <md-menu-divider></md-menu-divider>
+ <md-menu-item layout-align="space-around center">
+ <a id="templates-link"
+ ng-click="appCtrl.serviceProvider.headerCtrl.globalMenuCtrl.templates.shell.launch();">
+ <i class="icon icon-template"></i>Templates
+ </a>
+ </md-menu-item>
+ <md-menu-divider></md-menu-divider>
+ <md-menu-item layout-align="space-around center">
+ <a id="help-link"
+ ng-click="appCtrl.serviceProvider.headerCtrl.globalMenuCtrl.help.shell.launch();">
+ <i class="fa fa-question-circle"></i>Help
+ </a>
+ </md-menu-item>
+ <md-menu-item layout-align="space-around center">
+ <a id="about-link"
+ ng-click="appCtrl.serviceProvider.headerCtrl.globalMenuCtrl.about.modal.show();">
+ <i class="fa fa-info-circle"></i>About
+ </a>
+ </md-menu-item>
+ </md-menu-content>
+ </md-menu>
+ </div>
+ </div>
+</md-toolbar>
diff --git a/mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/connection-configuration.jsp b/mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/connection-configuration.jsp
new file mode 100644
index 0000000..c0e368c
--- /dev/null
+++ b/mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/connection-configuration.jsp
@@ -0,0 +1,218 @@
+<%--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Modifications to the original nifi code for the ONAP project are made
+ available under the Apache License, Version 2.0
+--%>
+<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
+<div id="connection-configuration" layout="column" class="hidden large-dialog">
+ <div class="connection-configuration-tab-container dialog-content">
+ <div id="connection-configuration-tabs" class="tab-container"></div>
+ <div id="connection-configuration-tabs-content">
+ <div id="connection-settings-tab-content" class="configuration-tab">
+ <div class="settings-left">
+ <div class="setting">
+ <div class="setting-name">Name</div>
+ <div class="setting-field">
+ <input type="text" id="connection-name" name="connection-name" class="setting-input"/>
+ </div>
+ </div>
+ <div class="setting">
+ <div class="setting-name">Id</div>
+ <div class="setting-field">
+ <span type="text" id="connection-id"></span>
+ </div>
+ </div>
+ <div class="setting">
+ <div class="setting-name">
+ FlowFile expiration
+ <div class="fa fa-question-circle" alt="Info" title="The maximum amount of time an object may be in the flow before it will be automatically aged out of the flow."></div>
+ </div>
+ <div class="setting-field">
+ <input type="text" id="flow-file-expiration" name="flow-file-expiration" class="setting-input"/>
+ </div>
+ </div>
+ <div class="multi-column-settings">
+ <div class="setting">
+ <div class="setting-name">
+ Back Pressure<br/>Object threshold
+ <div class="fa fa-question-circle" alt="Info" title="The maximum number of objects that can be queued before back pressure is applied."></div>
+ </div>
+ <div class="setting-field">
+ <input type="text" id="back-pressure-object-threshold" name="back-pressure-object-threshold" class="setting-input"/>
+ </div>
+ </div>
+ <div class="separator">&nbsp;</div>
+ <div class="setting">
+ <div class="setting-name">
+ &nbsp;<br/>Size threshold
+ <div class="fa fa-question-circle" alt="Info" title="The maximum data size of objects that can be queued before back pressure is applied."></div>
+ </div>
+ <div class="setting-field">
+ <input type="text" id="back-pressure-data-size-threshold" name="back-pressure-data-size-threshold" class="setting-input"/>
+ </div>
+ </div>
+ </div>
+ <div>
+ <div class="multi-column-settings">
+ <div class="setting">
+ <div class="setting-name">
+ Load Balance Strategy
+ <div class="fa fa-question-circle" alt="Info" title="How to load balance the data in this Connection across the nodes in the cluster."></div>
+ </div>
+ <div class="setting-field">
+ <div id="load-balance-strategy-combo"></div>
+ </div>
+ </div>
+ <div id="load-balance-partition-attribute-setting-separator" class="separator">&nbsp;</div>
+ <div id="load-balance-partition-attribute-setting" class="setting">
+ <div class="setting-name">
+ Attribute Name
+ <div class="fa fa-question-circle" alt="Info" title="The FlowFile Attribute to use for determining which node a FlowFile will go to."></div>
+ </div>
+ <div class="setting-field">
+ <input type="text" id="load-balance-partition-attribute" name="load-balance-partition-attribute" class="setting-input"/>
+ </div>
+ </div>
+ </div>
+ <div id="load-balance-compression-setting" class="setting">
+ <div class="setting-name">
+ Load Balance Compression
+ <div class="fa fa-question-circle" alt="Info" title="Whether or not data should be compressed when being transferred between nodes in the cluster."></div>
+ </div>
+ <div class="setting-field">
+ <div id="load-balance-compression-combo"></div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="spacer">&nbsp;</div>
+ <div class="settings-right">
+ <div class="setting">
+ <div class="setting-name">
+ Available prioritizers
+ <div class="fa fa-question-circle" alt="Info" title="Available prioritizers that could reprioritize FlowFiles in this work queue."></div>
+ </div>
+ <div class="setting-field">
+ <ul id="prioritizer-available"></ul>
+ </div>
+ </div>
+ <div class="setting">
+ <div class="setting-name">
+ Selected prioritizers
+ <div class="fa fa-question-circle" alt="Info" title="Prioritizers that have been selected to reprioritize FlowFiles in this work queue."></div>
+ </div>
+ <div class="setting-field">
+ <ul id="prioritizer-selected"></ul>
+ </div>
+ </div>
+ </div>
+ <input type="hidden" id="connection-uri" name="connection-uri"/>
+ <input type="hidden" id="connection-source-component-id" name="connection-source-component-id"/>
+ <input type="hidden" id="connection-source-id" name="connection-source-id"/>
+ <input type="hidden" id="connection-source-group-id" name="connection-source-group-id"/>
+ <input type="hidden" id="connection-destination-component-id" name="connection-destination-component-id"/>
+ <input type="hidden" id="connection-destination-id" name="connection-destination-id"/>
+ <input type="hidden" id="connection-destination-group-id" name="connection-destination-group-id"/>
+ </div>
+ <div id="connection-details-tab-content" class="configuration-tab">
+ <div class="settings-left">
+ <div id="read-only-output-port-source" class="setting hidden">
+ <div class="setting-name">From output</div>
+ <div class="setting-field connection-terminal-label">
+ <div id="read-only-output-port-name" class="ellipsis"></div>
+ </div>
+ </div>
+ <div id="output-port-source" class="setting hidden">
+ <div class="setting-name">From output</div>
+ <div class="setting-field connection-terminal-label">
+ <div id="output-port-options"></div>
+ </div>
+ </div>
+ <div id="input-port-source" class="setting hidden">
+ <div class="setting-name">From input</div>
+ <div class="setting-field connection-terminal-label">
+ <div id="input-port-source-name" class="label ellipsis"></div>
+ </div>
+ </div>
+ <div id="funnel-source" class="setting hidden">
+ <div class="setting-name">From funnel</div>
+ <div class="setting-field connection-terminal-label">
+ <div id="funnel-source-name" class="label ellipsis" title="funnel">funnel</div>
+ </div>
+ </div>
+ <div id="processor-source" class="setting hidden">
+ <div class="setting-name">From processor</div>
+ <div class="setting-field connection-terminal-label">
+ <div id="processor-source-details">
+ <div id="processor-source-name" class="label ellipsis"></div>
+ <div id="processor-source-type" class="ellipsis"></div>
+ </div>
+ </div>
+ </div>
+ <div id="connection-source-group" class="setting">
+ <div class="setting-name">Within group</div>
+ <div class="setting-field">
+ <div id="connection-source-group-name"></div>
+ </div>
+ </div>
+ </div>
+ <div class="spacer">&nbsp;</div>
+ <div class="settings-right">
+ <div id="input-port-destination" class="setting hidden">
+ <div class="setting-name">To input</div>
+ <div class="setting-field connection-terminal-label">
+ <div id="input-port-options"></div>
+ </div>
+ </div>
+ <div id="output-port-destination" class="setting hidden">
+ <div class="setting-name">To output</div>
+ <div class="setting-field connection-terminal-label">
+ <div id="output-port-destination-name" class="label ellipsis"></div>
+ </div>
+ </div>
+ <div id="funnel-destination" class="setting hidden">
+ <div class="setting-name">To funnel</div>
+ <div class="setting-field connection-terminal-label">
+ <div id="funnel-destination-name" class="label ellipsis" title="funnel">funnel</div>
+ </div>
+ </div>
+ <div id="processor-destination" class="setting hidden">
+ <div class="setting-name">To processor</div>
+ <div class="setting-field connection-terminal-label">
+ <div id="processor-destination-details">
+ <div id="processor-destination-name" class="label ellipsis"></div>
+ <div id="processor-destination-type" class="ellipsis"></div>
+ </div>
+ </div>
+ </div>
+ <div id="connection-destination-group" class="setting">
+ <div class="setting-name">Within group</div>
+ <div class="setting-field">
+ <div id="connection-destination-group-name"></div>
+ </div>
+ </div>
+ </div>
+ <div id="relationship-names-container" class="hidden">
+ <div class="setting-name">Data relationships</div>
+ <div class="setting-field">
+ <div id="relationship-names"></div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/distribution-environment-dialog.jsp b/mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/distribution-environment-dialog.jsp
new file mode 100644
index 0000000..3d7e8d9
--- /dev/null
+++ b/mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/distribution-environment-dialog.jsp
@@ -0,0 +1,42 @@
+<%--
+================================================================================
+Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+================================================================================
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+============LICENSE_END=========================================================
+--%>
+<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
+<div id="distribution-environment-dialog" layout="column" class="hidden medium-dialog">
+ <div class="dialog-content">
+ <div class="setting">
+ <div class="setting-name">Name</div>
+ <div class="setting-field">
+ <span id="distribution-environment-id" class="hidden"></span>
+ <input type="text" id="distribution-environment-name" class="setting-input"/>
+ </div>
+ </div>
+ <div class="setting">
+ <div class="setting-name">Runtime API URL</div>
+ <div class="setting-field">
+ <input type="text" id="distribution-environment-location" class="setting-input" placeholder="http://runtime-host:port"/>
+ </div>
+ </div>
+ <div class="setting">
+ <div class="setting-name">Description</div>
+ <div class="setting-field">
+ <textarea id="distribution-environment-description" class="setting-input"></textarea>
+ </div>
+ </div>
+
+ </div>
+</div>
diff --git a/mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/flow-status.jsp b/mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/flow-status.jsp
new file mode 100644
index 0000000..2efe0a1
--- /dev/null
+++ b/mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/flow-status.jsp
@@ -0,0 +1,33 @@
+<%--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Modifications to the original nifi code for the ONAP project are made
+ available under the Apache License, Version 2.0
+--%>
+<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
+<div id="flow-status" flex layout="row" layout-align="space-between center">
+ <div id="flow-status-container" layout="row" layout-align="space-around center">
+ </div>
+
+ <div layout="row" layout-align="end center">
+ <div id="search-container">
+ <button id="search-button" ng-click="appCtrl.serviceProvider.headerCtrl.flowStatusCtrl.search.toggleSearchField();"><i class="fa fa-search"></i></button>
+ <input id="search-field" type="text" placeholder="Search"/>
+ </div>
+ <button id="bulletin-button"><i class="fa fa-sticky-note-o"></i></button>
+ </div>
+ </div>
+<div id="search-flow-results"></div>
diff --git a/mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/navigation.jsp b/mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/navigation.jsp
new file mode 100644
index 0000000..caf7278
--- /dev/null
+++ b/mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/navigation.jsp
@@ -0,0 +1,129 @@
+<%--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Modifications to the original nifi code for the ONAP project are made
+ available under the Apache License, Version 2.0
+--%>
+<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
+<nf-breadcrumbs
+ breadcrumbs="appCtrl.serviceProvider.breadcrumbsCtrl.getBreadcrumbs();"
+ click-func="appCtrl.nf.CanvasUtils.getComponentByType('ProcessGroup').enterGroup"
+ highlight-crumb-id="appCtrl.nf.CanvasUtils.getGroupId();"
+ separator-func="appCtrl.nf.Common.isDefinedAndNotNull"
+ is-tracking="appCtrl.serviceProvider.breadcrumbsCtrl.isTracking"
+ get-version-control-class="appCtrl.serviceProvider.breadcrumbsCtrl.getVersionControlClass"
+ get-version-control-tooltip="appCtrl.serviceProvider.breadcrumbsCtrl.getVersionControlTooltip">
+</nf-breadcrumbs>
+<div id="graph-controls">
+ <div id="navigation-control" class="graph-control">
+ <div class="graph-control-docked pointer fa fa-compass" title="Navigate"
+ ng-click="appCtrl.serviceProvider.graphControlsCtrl.undock($event)">
+ </div>
+ <div class="graph-control-header-container hidden pointer"
+ ng-click="appCtrl.serviceProvider.graphControlsCtrl.expand($event)">
+ <div class="graph-control-header-icon fa fa-compass">
+ </div>
+ <div class="graph-control-header">Navigate</div>
+ <div class="graph-control-header-action">
+ <div class="graph-control-expansion fa fa-plus-square-o pointer"></div>
+ </div>
+ <div class="clear"></div>
+ </div>
+ <div class="graph-control-content hidden">
+ <div id="navigation-buttons">
+ <div id="naviagte-zoom-in" class="action-button" title="Zoom In"
+ ng-click="appCtrl.serviceProvider.graphControlsCtrl.navigateCtrl.zoomIn();">
+ <button><div class="graph-control-action-icon fa fa-search-plus"></div></button>
+ </div>
+ <div class="button-spacer-small">&nbsp;</div>
+ <div id="naviagte-zoom-out" class="action-button" title="Zoom Out"
+ ng-click="appCtrl.serviceProvider.graphControlsCtrl.navigateCtrl.zoomOut();">
+ <button><div class="graph-control-action-icon fa fa-search-minus"></div></button>
+ </div>
+ <div class="button-spacer-large">&nbsp;</div>
+ <div id="naviagte-zoom-fit" class="action-button" title="Fit"
+ ng-click="appCtrl.serviceProvider.graphControlsCtrl.navigateCtrl.zoomFit();">
+ <button><div class="graph-control-action-icon icon icon-zoom-fit"></div></button>
+ </div>
+ <div class="button-spacer-small">&nbsp;</div>
+ <div id="naviagte-zoom-actual-size" class="action-button" title="Actual"
+ ng-click="appCtrl.serviceProvider.graphControlsCtrl.navigateCtrl.zoomActualSize();">
+ <button><div class="graph-control-action-icon icon icon-zoom-actual"></div></button>
+ </div>
+ <div class="clear"></div>
+ </div>
+ <div id="birdseye"></div>
+ </div>
+ </div>
+ <div id="operation-control" class="graph-control">
+ <div class="graph-control-docked pointer fa fa-hand-o-up" title="Operate"
+ ng-click="appCtrl.serviceProvider.graphControlsCtrl.undock($event)">
+ </div>
+ <div class="graph-control-header-container hidden pointer"
+ ng-click="appCtrl.serviceProvider.graphControlsCtrl.expand($event)">
+ <div class="graph-control-header-icon fa fa-hand-o-up">
+ </div>
+ <div class="graph-control-header">Operate</div>
+ <div class="graph-control-header-action">
+ <div class="graph-control-expansion fa fa-plus-square-o pointer"></div>
+ </div>
+ <div class="clear"></div>
+ </div>
+ <div class="graph-control-content hidden">
+ <div id="operation-context">
+ <div id="operation-context-logo">
+ <i class="icon" ng-class="appCtrl.serviceProvider.graphControlsCtrl.getContextIcon()"></i>
+ </div>
+ <div id="operation-context-details-container">
+ <div id="operation-context-name"><strong> {{appCtrl.serviceProvider.graphControlsCtrl.getContextName()}} </strong></div>
+ <div id="operation-context-type" ng-class="appCtrl.serviceProvider.graphControlsCtrl.hide()">{{appCtrl.serviceProvider.graphControlsCtrl.getContextType()}}</div>
+ </div>
+ <div class="clear"></div>
+ <div id="operation-context-id" ng-class="appCtrl.serviceProvider.graphControlsCtrl.hide()">{{appCtrl.serviceProvider.graphControlsCtrl.getContextId()}}</div>
+ </div> <div id="operation-buttons">
+ <div>
+
+ <div id="operation-context-type">Distribute for deployment:</div>
+ <br>
+ <div>
+ <select name="environment" id="environmentType" class="combo" onchange="onEnvironmentSelect()">
+ <option class="combo-option-text" disabled selected>Select Environment</option>
+ </select>
+ </div>
+
+ <br>
+ <div class="button-spacer-large">&nbsp;</div>
+ <div id="operate-refresh" class="action-button" title="Refresh Environments">
+ <button id="refresh-env-btn" onclick="refreshEnvironments()" >
+ <div class="graph-control-action-icon fa fa-refresh"></div><span></span></button>
+ </div>
+ <div class="button-spacer-large">&nbsp;</div>
+ <div id="operate-delete" class="action-button" title="Delete">
+ <button ng-click="appCtrl.nf.Actions['delete'](appCtrl.nf.CanvasUtils.getSelection());"
+ ng-disabled="!appCtrl.nf.CanvasUtils.areDeletable(appCtrl.nf.CanvasUtils.getSelection());">
+ <div class="graph-control-action-icon fa fa-trash"></div><span></span></button>
+ </div>
+ <div class="button-spacer-large">&nbsp;</div>
+ <div id="operate-submit" class="action-button" title="Submit">
+ <button id="operate-submit-btn" onclick="distributeGraph()" >
+ <div class="graph-control-action-icon fa fa-check"></div><span></span></button>
+ </div>
+ <div class="clear"></div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/settings-content.jsp b/mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/settings-content.jsp
new file mode 100644
index 0000000..b540ff7
--- /dev/null
+++ b/mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/settings-content.jsp
@@ -0,0 +1,86 @@
+<%--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Modifications to the original nifi code for the ONAP project are made
+ available under the Apache License, Version 2.0
+--%>
+<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
+<div id="settings" class="hidden">
+ <div id="settings-header-text" class="settings-header-text">NiFi Settings</div>
+ <div class="settings-container">
+ <div>
+ <div id="settings-tabs" class="settings-tabs tab-container"></div>
+ <div class="clear"></div>
+ </div>
+ <div id="settings-tabs-content">
+ <button id="new-service-or-task" class="add-button fa fa-plus" title="Create a new reporting task controller service" style="display: block;"></button>
+ <div id="general-settings-tab-content" class="configuration-tab">
+ <div id="general-settings">
+ <div class="setting">
+ <div class="setting-name">
+ Maximum timer driven thread count
+ <div class="fa fa-question-circle" alt="Info" title="The maximum number of threads for timer driven processors available to the system."></div>
+ </div>
+ <div class="editable setting-field">
+ <input type="text" id="maximum-timer-driven-thread-count-field" class="setting-input"/>
+ </div>
+ <div class="read-only setting-field">
+ <span id="read-only-maximum-timer-driven-thread-count-field"></span>
+ </div>
+ </div>
+ <div class="setting">
+ <div class="setting-name">
+ Maximum event driven thread count
+ <div class="fa fa-question-circle" alt="Info" title="The maximum number of threads for event driven processors available to the system."></div>
+ </div>
+ <div class="editable setting-field">
+ <input type="text" id="maximum-event-driven-thread-count-field" class="setting-input"/>
+ </div>
+ <div class="read-only setting-field">
+ <span id="read-only-maximum-event-driven-thread-count-field"></span>
+ </div>
+ </div>
+ <div class="editable settings-buttons">
+ <div id="settings-save" class="button">Apply</div>
+ <div class="clear"></div>
+ </div>
+ </div>
+ </div>
+ <div id="controller-services-tab-content" class="configuration-tab controller-settings-table">
+ <div id="controller-services-table" class="settings-table"></div>
+ </div>
+ <div id="reporting-tasks-tab-content" class="configuration-tab controller-settings-table">
+ <div id="reporting-tasks-table" class="settings-table"></div>
+ </div>
+ <div id="registries-tab-content" class="configuration-tab controller-settings-table">
+ <div id="registries-table" class="settings-table"></div>
+ </div>
+ <div id="distribution-environment-content" class="configuration-tab controller-settings-table">
+ <div id="distribution-environments-table" class="settings-table" style="width:100%; margin:20px;"></div>
+ </div>
+
+ </div>
+ </div>
+ <div id="settings-refresh-container">
+ <button id="settings-refresh-button" class="refresh-button pointer fa fa-refresh" title="Refresh"></button>
+ <div id="settings-last-refreshed-container" class="last-refreshed-container">
+ Last updated:&nbsp;<span id="settings-last-refreshed" class="value-color"></span>
+ </div>
+ <div id="settings-loading-container" class="loading-container"></div>
+ <div id="controller-cs-availability" class="hidden">Listed services are available to all Reporting Tasks and services defined in the Controller Settings.</div>
+ <div class="clear"></div>
+ </div>
+</div>
diff --git a/mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/shell.jsp b/mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/shell.jsp
new file mode 100644
index 0000000..5b6c4c3
--- /dev/null
+++ b/mod/designtool/designtool-web/src/main/webapp/WEB-INF/partials/canvas/shell.jsp
@@ -0,0 +1,34 @@
+<%--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Modifications to the original nifi code for the ONAP project are made
+ available under the Apache License, Version 2.0
+--%>
+<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
+<div id="shell-dialog" class="hidden cancellable">
+ <div id="shell-container" class="dialog-content">
+ <div id="shell-close-container">
+ <button id="shell-undock-button" class="undock-normal pointer " title="Open in New Window">
+ <div class="fa fa-external-link-square"></div>
+ </button>
+ <button id="shell-close-button" class="close-normal pointer" onclick="onCloseSettings()" title="Close">
+ <div class="fa fa-times"></div>
+ </button>
+ <div class="clear"></div>
+ </div>
+ <div id="shell"></div>
+ </div>
+</div>
diff --git a/mod/designtool/designtool-web/src/main/webapp/css/navigation.css b/mod/designtool/designtool-web/src/main/webapp/css/navigation.css
new file mode 100644
index 0000000..05adc45
--- /dev/null
+++ b/mod/designtool/designtool-web/src/main/webapp/css/navigation.css
@@ -0,0 +1,338 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Modifications to the original nifi code for the ONAP project are made
+ * available under the Apache License, Version 2.0
+ */
+
+/* general graph control styles */
+
+#graph-controls {
+ position: absolute;
+ left: 0;
+ top: 110px;
+ z-index: 2;
+}
+
+#graph-controls .icon {
+ font-size: 18px;
+ line-height: 23px;
+ margin-left: -2px;
+}
+
+#graph-controls .fa {
+ font-size: 18px;
+ margin-left: -2px;
+}
+
+.graph-control-header-icon.fa {
+ color: #004849; /*link-color*/
+ margin-left: 7px !important;
+}
+
+div.graph-control {
+ box-shadow: 0 1px 6px rgba(0,0,0,0.25);
+ background-color: rgba(249, 250, 251, 0.9);
+ border-top: 1px solid #aabbc3;
+ border-right: 1px solid #aabbc3;
+ border-bottom: 1px solid #aabbc3;
+ margin-bottom: 2px;
+}
+
+.graph-control-content {
+ margin-left: 10px;
+ margin-right: 10px;
+ margin-bottom: 10px;
+}
+
+.docked {
+ height: 32px;
+ width: 32px;
+}
+
+div.graph-control-docked {
+ height: 100%;
+ width: 100%;
+ text-align: center;
+ line-height: 34px;
+ color: #004849;
+}
+
+.docked:hover {
+ border-top: 1px solid #004849; /*tint base-color 60%*/
+ border-right: 1px solid #004849; /*tint base-color 60%*/
+ border-bottom: 1px solid #004849; /*tint base-color 60%*/
+}
+
+div.graph-control button {
+ line-height: 30px;
+ border: 1px solid #CCDADB; /*tint link-color 80%*/
+ background-color: rgba(249,250,251,1);
+ color: #004849;
+}
+
+div.graph-control button:hover {
+ border: 1px solid #004849; /*link-color*/
+}
+
+div.graph-control button:disabled {
+ color: #CCDADB; /*tint link-color 80%*/
+ cursor: not-allowed;
+ border: 1px solid #CCDADB; /*tint link-color 80%*/
+}
+
+div.graph-control div.graph-control-expansion {
+ color: #728E9B;
+ line-height: 34px;
+ margin-left: 9px !important;
+}
+
+div.graph-control-header-icon {
+ float: left;
+ margin: 8px 10px 0px 0px;
+}
+
+div.graph-control-header {
+ float: left;
+ font-size: 12px;
+ font-family: 'Roboto Slab';
+ color: #262626;
+ letter-spacing: 0.05rem;
+ margin: 10px 0px;
+}
+
+div.graph-control-header-action {
+ float: right;
+ height: 32px;
+ width: 32px;
+}
+
+.graph-control-header-container:hover {
+ background: linear-gradient(90deg, rgba(227,232,235,0) 254px, rgba(227,232,235,1) 32px);
+}
+
+/* navigate buttons */
+
+#navigation-buttons {
+ margin-bottom: 5px;
+ margin-top: 10px;
+}
+
+#operation-context {
+ margin-top: 10px;
+}
+
+#operation-context-logo {
+ float: left;
+}
+
+#operation-context-logo i.icon {
+ font-size: 32px;
+ font-family: flowfont;
+ color: #ad9897;
+}
+
+#operation-context-details-container {
+ float: left;
+ padding-left: 10px;
+}
+
+#operation-context-name {
+ height: 15px;
+ font-size: 15px;
+ font-family: Roboto;
+ color: #262626;
+ width: 230px;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+}
+
+#operation-context-type {
+ font-size: 12px;
+ font-family: Roboto;
+ color: #728e9b;
+ margin-top: 3px;
+}
+
+#operation-context-id {
+ font-size: 12px;
+ font-family: Roboto;
+ color: #775351;
+ margin-top: 10px;
+}
+
+#operation-context-type.invisible, #operation-context-id.invisible {
+ visibility: hidden;
+}
+
+#operation-buttons {
+ margin-top: 10px;
+}
+
+div.action-button {
+ float: left;
+}
+
+
+#operate-delete button {
+ width: inherit;
+ padding: 0 7px;
+}
+
+#operate-delete button span{
+ padding-left: 5px;
+ font-size: 12px;
+ }
+
+#operate-submit button {
+ width: inherit;
+ padding: 0 7px;
+}
+
+ #operate-submit button span{
+ padding-left: 5px;
+ font-size: 12px;
+ color: green;
+ }
+
+#operate-refresh button {
+ width: inherit;
+ padding: 0 7px;
+}
+
+ #operate-refresh button span{
+ padding-left: 5px;
+ font-size: 12px;
+ color: blue;
+ }
+
+div.graph-control div.icon-disabled {
+ color: #ddd;
+}
+
+div.button-spacer-small {
+ float: left;
+ width: 2px;
+}
+
+div.button-spacer-large {
+ float: left;
+ width: 12px;
+}
+
+/* outline/birdseye */
+
+#birdseye svg, #birdseye canvas {
+ position: absolute;
+ overflow: hidden;
+}
+
+#birdseye {
+ width: 264px;
+ height: 150px;
+ background: #fff;
+ z-index: 1001;
+ overflow: hidden;
+ border: 1px solid #e5ebed;
+}
+
+.brush .selection {
+ stroke: #666;
+ fill-opacity: .125;
+ shape-rendering: crispEdges;
+}
+
+rect.birdseye-brush {
+ stroke: #7098ad;
+ fill: transparent;
+}
+
+/* styles for the breadcrumbs bar */
+
+#breadcrumbs {
+ position: absolute;
+ bottom: 0px;
+ box-shadow: 0 1px 6px rgba(0, 0, 0, 0.25);
+ background-color: rgba(249, 250, 251, 0.9);
+ border-top: 1px solid #aabbc3;
+ color: #598599;
+ z-index: 3;
+ height: 31px;
+ width: 100%;
+}
+
+#cluster-indicator {
+ width: 49px;
+ height: 15px;
+ background-color: transparent;
+ display: none;
+ position: absolute;
+ left: 59px;
+ top: 8px;
+}
+
+span.breadcrumb-version-control-green {
+ color: #1a9964;
+}
+
+span.breadcrumb-version-control-red {
+ color: #ba554a;
+}
+
+span.breadcrumb-version-control-gray {
+ color: #666666;
+}
+
+#breadcrumbs-left-border {
+ position: absolute;
+ left: 0;
+ width: 10px;
+ height: 14px;
+ z-index: 3;
+ background-color: transparent;
+ background: linear-gradient(to right, rgba(249, 250, 251, 0.97), rgba(255, 255, 255, 0));
+ filter: progid:DXImageTransform.Microsoft.gradient(gradientType=1, startColorstr=#ffffffff, endColorstr=#00ffffff);
+}
+
+#breadcrumbs-right-border {
+ position: absolute;
+ right: 0px;
+ width: 10px;
+ height: 14px;
+ z-index: 3;
+ background-color: transparent;
+ background: linear-gradient(to left, rgba(249, 250, 251, 0.97), rgba(255, 255, 255, 0));
+ filter: progid:DXImageTransform.Microsoft.gradient(gradientType=1, startColorstr=#00ffffff, endColorstr=#ffffffff);
+}
+
+#data-flow-title-viewport {
+ overflow: hidden;
+ position: absolute;
+ left: 5px;
+ top: 8px;
+ right: 5px;
+ z-index: 4;
+}
+
+#data-flow-title-container {
+ font-size: 13px;
+ color: #000;
+ position: relative;
+ float: left;
+ white-space: nowrap;
+ line-height: normal;
+}
diff --git a/mod/designtool/designtool-web/src/main/webapp/images/dcae-logo.png b/mod/designtool/designtool-web/src/main/webapp/images/dcae-logo.png
new file mode 100644
index 0000000..2e0d5a0
--- /dev/null
+++ b/mod/designtool/designtool-web/src/main/webapp/images/dcae-logo.png
Binary files differ
diff --git a/mod/designtool/designtool-web/src/main/webapp/js/jquery/dcae-mod.js b/mod/designtool/designtool-web/src/main/webapp/js/jquery/dcae-mod.js
new file mode 100644
index 0000000..879739c
--- /dev/null
+++ b/mod/designtool/designtool-web/src/main/webapp/js/jquery/dcae-mod.js
@@ -0,0 +1,135 @@
+/*
+============LICENSE_START=======================================================
+Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+================================================================================
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+============LICENSE_END=========================================================
+*/
+
+console.log("loading dcae-mod");
+
+ var dt_id;
+ var hostname;
+
+ /**
+ * @desc: on load of page, makes submit button disabled. Also makes an api call to get the host IP of the current instance
+ */
+ $(document).ready(function (){
+ if(dt_id == null){ $('#operate-submit-btn').prop('disabled', true); }
+
+ //get hostname
+ $.ajax({
+ type: 'GET',
+ url: '../nifi-api/flow/config',
+ dataType: 'json',
+ contentType: 'application/json',
+ success: function(data){
+ hostname= data.flowConfiguration.dcaeDistributorApiHostname;
+
+ //function call: invokes api to refresh the list of Envs
+ if(hostname){ getDistributionTargets(); }
+ }
+ });
+ });
+
+ /**
+ * common function to reuse : invokes api to get new updates list environments.
+ * @desc: Makes the select dropdown empty first. Then manually add Placeholder as first/default Option.
+ * And then dynamically add list of Environments as Options.
+ */
+ function getDistributionTargets(){
+ var select = document.getElementById("environmentType");
+ if(select && select.options && select.options.length > 0){
+ select.options.length=0;
+ var element= document.createElement("option");
+ element.textContent= "Select Environment";
+ element.selected=true;
+ element.disabled=true;
+ element.className="combo-option-text";
+ select.appendChild(element);
+ }else{ select=[]; }
+
+ $.ajax({
+ type: 'GET',
+ url: hostname+'/distribution-targets',
+ dataType: 'json',
+ contentType: 'application/json',
+ success: function(data){
+ if(data){
+ for(var i=0; i < data.distributionTargets.length; i++){
+ var opt= data.distributionTargets[i];
+ var element= document.createElement("option");
+ element.textContent= opt.name;
+ element.value= opt.id;
+ element.className="combo-option-text";
+ select.appendChild(element);
+ }
+ }
+ }
+ })
+ }
+
+ /**
+ * @desc: submit button functionality to distribute/POST process group to the environment.
+ */
+ var distributeGraph = function(){
+ var selected_id = $('#operation-context-id').text();
+ // process group id (nifi api) != flow id (nifi registry api)
+ // so must first fetch the flow id from nifi api
+ $.ajax({
+ type: 'GET',
+ url: '../nifi-api/process-groups/'+selected_id,
+ contentType: 'application/json',
+ success: function(data) {
+ const flow_id = data["component"]["versionControlInformation"]["flowId"];
+ const request = {"processGroupId": flow_id}
+
+ $.ajax({
+ type: 'POST',
+ data: JSON.stringify(request),
+ url: hostname+'/distribution-targets/'+dt_id+'/process-groups',
+ dataType: 'json',
+ contentType: 'application/json',
+ success: function(data){
+ alert("Success, Your flow have been distributed successfully");
+ },
+ error: function(err) {
+ alert("Issue with distribution:\n\n" + JSON.stringify(err, null, 2));
+ }
+ });
+ }
+ })
+ };
+
+
+ /**
+ * @desc: selection of distribution target environment to post the process group
+ */
+ var onEnvironmentSelect = function(){
+ dt_id = $('#environmentType').val();
+ console.log(dt_id);
+ if(dt_id == null){ $('#operate-submit-btn').prop('disabled', true); }
+ else{ $('#operate-submit-btn').prop('disabled', false); }
+ };
+
+
+ /**
+ * @desc: event handler for Refresh icon in Operate panel : invokes api to refresh the list of Envs
+ */
+ var refreshEnvironments= function(){ getDistributionTargets(); };
+
+
+ /**
+ * @desc: event handler for Close icon of Setting/ Distribution Env CRUD dialog : invokes api to refresh the list of Envs
+ */
+ var onCloseSettings= function(){ getDistributionTargets(); };
diff --git a/mod/designtool/designtool-web/src/main/webapp/js/nf/canvas/controllers/nf-ng-breadcrumbs-controller.js b/mod/designtool/designtool-web/src/main/webapp/js/nf/canvas/controllers/nf-ng-breadcrumbs-controller.js
new file mode 100644
index 0000000..0005837
--- /dev/null
+++ b/mod/designtool/designtool-web/src/main/webapp/js/nf/canvas/controllers/nf-ng-breadcrumbs-controller.js
@@ -0,0 +1,288 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Modifications to the original nifi code for the ONAP project are made
+ * available under the Apache License, Version 2.0
+ */
+
+/* global define, module, require, exports */
+
+(function (root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ define(['jquery',
+ 'nf.Common'],
+ function ($, nfCommon) {
+ return (nf.ng.BreadcrumbsCtrl = factory($, nfCommon));
+ });
+ } else if (typeof exports === 'object' && typeof module === 'object') {
+ module.exports = (nf.ng.BreadcrumbsCtrl =
+ factory(require('jquery'),
+ require('nf.Common')));
+ } else {
+ nf.ng.BreadcrumbsCtrl = factory(root.$,
+ root.nf.Common);
+ }
+}(this, function ($, nfCommon) {
+ 'use strict';
+
+ return function (serviceProvider) {
+ 'use strict';
+
+ function BreadcrumbsCtrl() {
+ this.breadcrumbs = [];
+ }
+
+ BreadcrumbsCtrl.prototype = {
+ constructor: BreadcrumbsCtrl,
+
+ /**
+ * Register the breadcrumbs controller.
+ */
+ register: function () {
+ if (serviceProvider.breadcrumbsCtrl === undefined) {
+ serviceProvider.register('breadcrumbsCtrl', breadcrumbsCtrl);
+ }
+ },
+
+ /**
+ * Generate the breadcrumbs.
+ *
+ * @param {object} breadcrumbEntity The breadcrumb
+ */
+ generateBreadcrumbs: function (breadcrumbEntity) {
+ var label = breadcrumbEntity.id;
+ if (breadcrumbEntity.permissions.canRead) {
+ label = breadcrumbEntity.breadcrumb.name;
+ }
+
+ this.breadcrumbs.unshift($.extend({
+ 'label': label
+ }, breadcrumbEntity));
+
+ if (nfCommon.isDefinedAndNotNull(breadcrumbEntity.parentBreadcrumb)) {
+ this.generateBreadcrumbs(breadcrumbEntity.parentBreadcrumb);
+ }
+ },
+
+ /**
+ * Updates the version control information for the specified process group.
+ *
+ * @param processGroupId
+ * @param versionControlInformation
+ */
+ updateVersionControlInformation: function (processGroupId, versionControlInformation) {
+ $.each(this.breadcrumbs, function (_, breadcrumbEntity) {
+ if (breadcrumbEntity.id === processGroupId) {
+ breadcrumbEntity.breadcrumb.versionControlInformation = versionControlInformation;
+ return false;
+ }
+ });
+ },
+
+ /**
+ * Reset the breadcrumbs.
+ */
+ resetBreadcrumbs: function () {
+ this.breadcrumbs = [];
+ },
+
+ /**
+ * Whether this crumb is tracking.
+ *
+ * @param breadcrumbEntity
+ * @returns {*}
+ */
+ isTracking: function (breadcrumbEntity) {
+ return nfCommon.isDefinedAndNotNull(breadcrumbEntity.versionedFlowState);
+ },
+
+ /**
+ * Returns the class string to use for the version control of the specified breadcrumb.
+ *
+ * @param breadcrumbEntity
+ * @returns {string}
+ */
+ getVersionControlClass: function (breadcrumbEntity) {
+ if (nfCommon.isDefinedAndNotNull(breadcrumbEntity.versionedFlowState)) {
+ var vciState = breadcrumbEntity.versionedFlowState;
+ if (vciState === 'SYNC_FAILURE') {
+ console.log("it is been sync failed..000");
+ $('#environmentType').prop('disabled', true);
+ if($('#environmentType').val() && !$('#environmentType').prop('disabled')){
+ $('#operate-submit-btn').prop('disabled', false);
+ }else{$('#operate-submit-btn').prop('disabled', true);}
+
+ return 'breadcrumb-version-control-gray fa fa-question'
+ } else if (vciState === 'LOCALLY_MODIFIED_AND_STALE') {
+ console.log("it is been locally modified and stale...000");
+ $('#environmentType').prop('disabled', true);
+ if($('#environmentType').val() && !$('#environmentType').prop('disabled')){
+ $('#operate-submit-btn').prop('disabled', false);
+ }else{$('#operate-submit-btn').prop('disabled', true);}
+
+ return 'breadcrumb-version-control-red fa fa-exclamation-circle';
+ } else if (vciState === 'STALE') {
+ console.log("it is been stale...000");
+ $('#environmentType').prop('disabled', true);
+ if($('#environmentType').val() && !$('#environmentType').prop('disabled')){
+ $('#operate-submit-btn').prop('disabled', false);
+ }else{$('#operate-submit-btn').prop('disabled', true);}
+
+ return 'breadcrumb-version-control-red fa fa-arrow-circle-up';
+ } else if (vciState === 'LOCALLY_MODIFIED') {
+ console.log("it is been locally modified...000");
+ $('#environmentType').prop('disabled', true);
+ if($('#environmentType').val() && !$('#environmentType').prop('disabled')){
+ $('#operate-submit-btn').prop('disabled', false);
+ }else{$('#operate-submit-btn').prop('disabled', true);}
+
+ return 'breadcrumb-version-control-gray fa fa-asterisk';
+ } else {
+ $('#environmentType').prop('disabled', false);
+ if($('#environmentType').val() && !$('#environmentType').prop('disabled')){
+ $('#operate-submit-btn').prop('disabled', false);
+ }else{$('#operate-submit-btn').prop('disabled', true);}
+ return 'breadcrumb-version-control-green fa fa-check';
+ }
+ } else {
+ console.log("it is NOT been version controlled...000");
+ $('#environmentType').prop('disabled', true);
+ return '';
+ }
+ },
+
+ /**
+ * Gets the content for the version control tooltip for the specified breadcrumb.
+ *
+ * @param breadcrumbEntity
+ */
+ getVersionControlTooltip: function (breadcrumbEntity) {
+ if (nfCommon.isDefinedAndNotNull(breadcrumbEntity.versionedFlowState) && breadcrumbEntity.permissions.canRead) {
+ return nfCommon.getVersionControlTooltip(breadcrumbEntity.breadcrumb.versionControlInformation);
+ } else {
+ return 'This Process Group is not under version control.'
+ }
+ },
+
+ /**
+ * Get the breadcrumbs.
+ */
+ getBreadcrumbs: function () {
+ return this.breadcrumbs;
+ },
+
+ /**
+ * Update the breadcrumbs css.
+ *
+ * @param {object} style The style to be applied.
+ */
+ updateBreadcrumbsCss: function (style) {
+ $('#breadcrumbs').css(style);
+ },
+
+ /**
+ * Reset initial scroll position.
+ */
+ resetScrollPosition: function () {
+ var title = $('#data-flow-title-container');
+ var titlePosition = title.position();
+ var titleWidth = title.outerWidth();
+ var titleRight = titlePosition.left + titleWidth;
+
+ var padding = $('#breadcrumbs-right-border').width();
+ var viewport = $('#data-flow-title-viewport');
+ var viewportWidth = viewport.width();
+ var viewportRight = viewportWidth - padding;
+
+ // if the title's right is past the viewport's right, shift accordingly
+ if (titleRight > viewportRight) {
+ // adjust the position
+ title.css('left', (titlePosition.left - (titleRight - viewportRight)) + 'px');
+ } else {
+ title.css('left', '10px');
+ }
+ },
+
+ /**
+ * Registers a scroll event on the `element`
+ *
+ * @param {object} element The element event listener will be registered upon.
+ */
+ registerMouseWheelEvent: function (element) {
+ // mousewheel -> IE, Chrome
+ // DOMMouseScroll -> FF
+ // wheel -> FF, IE
+
+ // still having issues with this in IE :/
+ element.on('DOMMouseScroll mousewheel', function (evt, d) {
+ if (nfCommon.isUndefinedOrNull(evt.originalEvent)) {
+ return;
+ }
+
+ var title = $('#data-flow-title-container');
+ var titlePosition = title.position();
+ var titleWidth = title.outerWidth();
+ var titleRight = titlePosition.left + titleWidth;
+
+ var padding = $('#breadcrumbs-right-border').width();
+ var viewport = $('#data-flow-title-viewport');
+ var viewportWidth = viewport.width();
+ var viewportRight = viewportWidth - padding;
+
+ // if the width of the title is larger than the viewport
+ if (titleWidth > viewportWidth) {
+ var adjust = false;
+
+ var delta = 0;
+
+ //Chrome and Safari both have evt.originalEvent.detail defined but
+ //evt.originalEvent.wheelDelta holds the correct value so we must
+ //check for evt.originalEvent.wheelDelta first!
+ if (nfCommon.isDefinedAndNotNull(evt.originalEvent.wheelDelta)) {
+ delta = evt.originalEvent.wheelDelta;
+ } else if (nfCommon.isDefinedAndNotNull(evt.originalEvent.detail)) {
+ delta = -evt.originalEvent.detail;
+ }
+
+ // determine the increment
+ if (delta > 0 && titleRight > viewportRight) {
+ var increment = -25;
+ adjust = true;
+ } else if (delta < 0 && (titlePosition.left - padding) < 0) {
+ increment = 25;
+
+ // don't shift too far
+ if (titlePosition.left + increment > padding) {
+ increment = padding - titlePosition.left;
+ }
+
+ adjust = true;
+ }
+
+ if (adjust) {
+ // adjust the position
+ title.css('left', (titlePosition.left + increment) + 'px');
+ }
+ }
+ });
+ }
+ }
+
+ var breadcrumbsCtrl = new BreadcrumbsCtrl();
+ breadcrumbsCtrl.register();
+ return breadcrumbsCtrl;
+ }
+}));
diff --git a/mod/designtool/designtool-web/src/main/webapp/js/nf/canvas/header/components/nf-ng-processor-component.js b/mod/designtool/designtool-web/src/main/webapp/js/nf/canvas/header/components/nf-ng-processor-component.js
new file mode 100644
index 0000000..0f4b953
--- /dev/null
+++ b/mod/designtool/designtool-web/src/main/webapp/js/nf/canvas/header/components/nf-ng-processor-component.js
@@ -0,0 +1,1150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Modifications to the original nifi code for the ONAP project are made
+ * available under the Apache License, Version 2.0
+ */
+
+/* global define, module, require, exports */
+
+(function (root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ define(['jquery',
+ 'Slick',
+ 'nf.Client',
+ 'nf.Birdseye',
+ 'nf.Storage',
+ 'nf.Graph',
+ 'nf.CanvasUtils',
+ 'nf.ErrorHandler',
+ 'nf.FilteredDialogCommon',
+ 'nf.Dialog',
+ 'nf.Common'],
+ function ($, Slick, nfClient, nfBirdseye, nfStorage, nfGraph, nfCanvasUtils, nfErrorHandler, nfFilteredDialogCommon, nfDialog, nfCommon) {
+ return (nf.ng.ProcessorComponent = factory($, Slick, nfClient, nfBirdseye, nfStorage, nfGraph, nfCanvasUtils, nfErrorHandler, nfFilteredDialogCommon, nfDialog, nfCommon));
+ });
+ } else if (typeof exports === 'object' && typeof module === 'object') {
+ module.exports = (nf.ng.ProcessorComponent =
+ factory(require('jquery'),
+ require('Slick'),
+ require('nf.Client'),
+ require('nf.Birdseye'),
+ require('nf.Storage'),
+ require('nf.Graph'),
+ require('nf.CanvasUtils'),
+ require('nf.ErrorHandler'),
+ require('nf.FilteredDialogCommon'),
+ require('nf.Dialog'),
+ require('nf.Common')));
+ } else {
+ nf.ng.ProcessorComponent = factory(root.$,
+ root.Slick,
+ root.nf.Client,
+ root.nf.Birdseye,
+ root.nf.Storage,
+ root.nf.Graph,
+ root.nf.CanvasUtils,
+ root.nf.ErrorHandler,
+ root.nf.FilteredDialogCommon,
+ root.nf.Dialog,
+ root.nf.Common);
+ }
+}(this, function ($, Slick, nfClient, nfBirdseye, nfStorage, nfGraph, nfCanvasUtils, nfErrorHandler, nfFilteredDialogCommon, nfDialog, nfCommon) {
+ 'use strict';
+
+ return function (serviceProvider) {
+ 'use strict';
+
+
+ var latestResponse;
+
+ var processorTypesData;
+
+
+ /**
+ * Filters the processor type table.
+ */
+ var applyFilter = function () {
+ // get the dataview
+ var processorTypesGrid = $('#processor-types-table').data('gridInstance');
+
+ // ensure the grid has been initialized
+ if (nfCommon.isDefinedAndNotNull(processorTypesGrid)) {
+ var processorTypesDataForFilter = processorTypesGrid.getData();
+
+ // update the search criteria
+ processorTypesDataForFilter.setFilterArgs({
+ searchString: getFilterText()
+ });
+ processorTypesDataForFilter.refresh();
+
+ // update the buttons to possibly trigger the disabled state
+ $('#new-processor-dialog').modal('refreshButtons');
+
+ // update the selection if possible
+ if (processorTypesDataForFilter.getLength() > 0) {
+ nfFilteredDialogCommon.choseFirstRow(processorTypesGrid);
+ // make the first row visible
+ processorTypesGrid.scrollRowToTop(0);
+ }
+ }
+ };
+
+ /**
+ * Determines if the item matches the filter.
+ *
+ * @param {object} item The item to filter.
+ * @param {object} args The filter criteria.
+ * @returns {boolean} Whether the item matches the filter.
+ */
+ var matchesRegex = function (item, args) {
+ if (args.searchString === '') {
+ return true;
+ }
+
+ try {
+ // perform the row filtering
+ var filterExp = new RegExp(args.searchString, 'i');
+ } catch (e) {
+ // invalid regex
+ return false;
+ }
+
+ // determine if the item matches the filter
+ var matchesLabel = item['label'].search(filterExp) >= 0;
+ var matchesTags = item['tags'].search(filterExp) >= 0;
+ return matchesLabel || matchesTags;
+ };
+
+ /**
+ * Performs the filtering.
+ *
+ * @param {object} item The item subject to filtering.
+ * @param {object} args Filter arguments.
+ * @returns {Boolean} Whether or not to include the item.
+ */
+ var filter = function (item, args) {
+ // determine if the item matches the filter
+ var matchesFilter = matchesRegex(item, args);
+
+ // determine if the row matches the selected tags
+ var matchesTags = true;
+ if (matchesFilter) {
+ var tagFilters = $('#processor-tag-cloud').tagcloud('getSelectedTags');
+ var hasSelectedTags = tagFilters.length > 0;
+ if (hasSelectedTags) {
+ matchesTags = matchesSelectedTags(tagFilters, item['tags']);
+ }
+ }
+
+ // determine if the row matches the selected source group
+ var matchesGroup = true;
+ if (matchesFilter && matchesTags) {
+ var bundleGroup = $('#processor-bundle-group-combo').combo('getSelectedOption');
+ if (nfCommon.isDefinedAndNotNull(bundleGroup) && bundleGroup.value !== '') {
+ matchesGroup = (item.bundle.group === bundleGroup.value);
+ }
+ }
+
+ // determine if this row should be visible
+ var matches = matchesFilter && matchesTags && matchesGroup;
+
+ // if this row is currently selected and its being filtered
+ if (matches === false && $('#selected-processor-type').text() === item['type']) {
+ // clear the selected row
+ $('#processor-type-description').attr('title', '').text('');
+ $('#processor-type-name').attr('title', '').text('');
+ $('#processor-type-bundle').attr('title', '').text('');
+ $('#selected-processor-name').text('');
+ $('#selected-processor-type').text('').removeData('bundle');
+
+ // clear the active cell the it can be reselected when its included
+ var processTypesGrid = $('#processor-types-table').data('gridInstance');
+ processTypesGrid.resetActiveCell();
+ }
+
+ return matches;
+ };
+
+ /**
+ * Determines if the specified tags match all the tags selected by the user.
+ *
+ * @argument {string[]} tagFilters The tag filters.
+ * @argument {string} tags The tags to test.
+ */
+ var matchesSelectedTags = function (tagFilters, tags) {
+ var selectedTags = [];
+ $.each(tagFilters, function (_, filter) {
+ selectedTags.push(filter);
+ });
+
+ // normalize the tags
+ var normalizedTags = tags.toLowerCase();
+
+ var matches = true;
+ $.each(selectedTags, function (i, selectedTag) {
+ if (normalizedTags.indexOf(selectedTag) === -1) {
+ matches = false;
+ return false;
+ }
+ });
+
+ return matches;
+ };
+
+ /**
+ * Get the text out of the filter field. If the filter field doesn't
+ * have any text it will contain the text 'filter list' so this method
+ * accounts for that.
+ */
+ var getFilterText = function () {
+ return $('#processor-type-filter').val();
+ };
+
+ /**
+ * Resets the filtered processor types.
+ */
+ var resetProcessorDialog = function () {
+
+ //********* REPLICATED A BLOCK OF CODE to get logic of autoloading processor ---STARTING FROM HERE----********************
+
+ // initialize the processor type table
+ var processorTypesColumns = [
+ {
+ id: 'type',
+ name: 'Type',
+ field: 'label',
+ formatter: nfCommon.typeFormatter,
+ sortable: true,
+ resizable: true
+ },
+ {
+ id: 'version',
+ name: 'Version',
+ field: 'version',
+ formatter: nfCommon.typeVersionFormatter,
+ sortable: true,
+ resizable: true
+ },
+ {
+ id: 'tags',
+ name: 'Tags',
+ field: 'tags',
+ sortable: true,
+ resizable: true,
+ formatter: nfCommon.genericValueFormatter
+ }
+ ];
+
+ var processorTypesOptions = {
+ forceFitColumns: true,
+ enableTextSelectionOnCells: true,
+ enableCellNavigation: true,
+ enableColumnReorder: false,
+ autoEdit: false,
+ multiSelect: false,
+ rowHeight: 24
+ };
+
+ // initialize the dataview
+ processorTypesData = new Slick.Data.DataView({
+ inlineFilters: false
+ });
+ processorTypesData.setItems([]);
+ processorTypesData.setFilterArgs({
+ searchString: getFilterText()
+ });
+ processorTypesData.setFilter(filter);
+
+ // initialize the sort
+ nfCommon.sortType({
+ columnId: 'type',
+ sortAsc: true
+ }, processorTypesData);
+
+ // initialize the grid
+ var processorTypesGrid = new Slick.Grid('#processor-types-table', processorTypesData, processorTypesColumns, processorTypesOptions);
+ processorTypesGrid.setSelectionModel(new Slick.RowSelectionModel());
+ processorTypesGrid.registerPlugin(new Slick.AutoTooltips());
+ processorTypesGrid.setSortColumn('type', true);
+ processorTypesGrid.onSort.subscribe(function (e, args) {
+ nfCommon.sortType({
+ columnId: args.sortCol.field,
+ sortAsc: args.sortAsc
+ }, processorTypesData);
+ });
+ processorTypesGrid.onSelectedRowsChanged.subscribe(function (e, args) {
+ if ($.isArray(args.rows) && args.rows.length === 1) {
+ var processorTypeIndex = args.rows[0];
+ var processorType = processorTypesGrid.getDataItem(processorTypeIndex);
+
+ // set the processor type description
+ if (nfCommon.isDefinedAndNotNull(processorType)) {
+ if (nfCommon.isBlank(processorType.description)) {
+ $('#processor-type-description')
+ .attr('title', '')
+ .html('<span class="unset">No description specified</span>');
+ } else {
+ $('#processor-type-description')
+ .width($('#processor-description-container').innerWidth() - 1)
+ .html(processorType.description)
+ .ellipsis();
+ }
+
+ var bundle = nfCommon.formatBundle(processorType.bundle);
+ var type = nfCommon.formatType(processorType);
+
+ // populate the dom
+ $('#processor-type-name').text(type).attr('title', type);
+ $('#processor-type-bundle').text(bundle).attr('title', bundle);
+ $('#selected-processor-name').text(processorType.label);
+ $('#selected-processor-type').text(processorType.type).data('bundle', processorType.bundle);
+
+ // refresh the buttons based on the current selection
+ $('#new-processor-dialog').modal('refreshButtons');
+ }
+ }
+ });
+ processorTypesGrid.onViewportChanged.subscribe(function (e, args) {
+ nfCommon.cleanUpTooltips($('#processor-types-table'), 'div.view-usage-restriction');
+ });
+
+ // wire up the dataview to the grid
+ processorTypesData.onRowCountChanged.subscribe(function (e, args) {
+ processorTypesGrid.updateRowCount();
+ processorTypesGrid.render();
+
+ // update the total number of displayed processors
+ $('#displayed-processor-types').text(args.current);
+ });
+ processorTypesData.onRowsChanged.subscribe(function (e, args) {
+ processorTypesGrid.invalidateRows(args.rows);
+ processorTypesGrid.render();
+ });
+ processorTypesData.syncGridSelection(processorTypesGrid, false);
+
+ // hold onto an instance of the grid
+ $('#processor-types-table').data('gridInstance', processorTypesGrid).on('mouseenter', 'div.slick-cell', function (e) {
+ var usageRestriction = $(this).find('div.view-usage-restriction');
+ if (usageRestriction.length && !usageRestriction.data('qtip')) {
+ var rowId = $(this).find('span.row-id').text();
+
+ // get the status item
+ var item = processorTypesData.getItemById(rowId);
+
+ // show the tooltip
+ if (item.restricted === true) {
+ var restrictionTip = $('<div></div>');
+
+ if (nfCommon.isBlank(item.usageRestriction)) {
+ restrictionTip.append($('<p style="margin-bottom: 3px;"></p>').text('Requires the following permissions:'));
+ } else {
+ restrictionTip.append($('<p style="margin-bottom: 3px;"></p>').text(item.usageRestriction + ' Requires the following permissions:'));
+ }
+
+ var restrictions = [];
+ if (nfCommon.isDefinedAndNotNull(item.explicitRestrictions)) {
+ $.each(item.explicitRestrictions, function (_, explicitRestriction) {
+ var requiredPermission = explicitRestriction.requiredPermission;
+ restrictions.push("'" + requiredPermission.label + "' - " + nfCommon.escapeHtml(explicitRestriction.explanation));
+ });
+ } else {
+ restrictions.push('Access to restricted components regardless of restrictions.');
+ }
+ restrictionTip.append(nfCommon.formatUnorderedList(restrictions));
+
+ usageRestriction.qtip($.extend({}, nfCommon.config.tooltipConfig, {
+ content: restrictionTip,
+ position: {
+ container: $('#summary'),
+ at: 'bottom right',
+ my: 'top left',
+ adjust: {
+ x: 4,
+ y: 4
+ }
+ }
+ }));
+ }
+ }
+ });
+
+ var generalRestriction = nfCommon.getPolicyTypeListing('restricted-components');
+
+ // load the available processor types, this select is shown in the
+ // new processor dialog when a processor is dragged onto the screen
+ $.ajax({
+ type: 'GET',
+ url:'../nifi-api/flow/processor-types',
+ // url: serviceProvider.headerCtrl.toolboxCtrl.config.urls.processorTypes,
+ dataType: 'json'
+ }).done(function (response) {
+ console.log(response);
+ var tags = [];
+ var groups = d3.set();
+ var restrictedUsage = d3.map();
+ var requiredPermissions = d3.map();
+
+ // begin the update
+ processorTypesData.beginUpdate();
+
+ // go through each processor type
+ $.each(response.processorTypes, function (i, documentedType) {
+ var type = documentedType.type;
+
+ if (documentedType.restricted === true) {
+ if (nfCommon.isDefinedAndNotNull(documentedType.explicitRestrictions)) {
+ $.each(documentedType.explicitRestrictions, function (_, explicitRestriction) {
+ var requiredPermission = explicitRestriction.requiredPermission;
+
+ // update required permissions
+ if (!requiredPermissions.has(requiredPermission.id)) {
+ requiredPermissions.set(requiredPermission.id, requiredPermission.label);
+ }
+
+ // update component restrictions
+ if (!restrictedUsage.has(requiredPermission.id)) {
+ restrictedUsage.set(requiredPermission.id, []);
+ }
+
+ restrictedUsage.get(requiredPermission.id).push({
+ type: nfCommon.formatType(documentedType),
+ bundle: nfCommon.formatBundle(documentedType.bundle),
+ explanation: nfCommon.escapeHtml(explicitRestriction.explanation)
+ })
+ });
+ } else {
+ // update required permissions
+ if (!requiredPermissions.has(generalRestriction.value)) {
+ requiredPermissions.set(generalRestriction.value, generalRestriction.text);
+ }
+
+ // update component restrictions
+ if (!restrictedUsage.has(generalRestriction.value)) {
+ restrictedUsage.set(generalRestriction.value, []);
+ }
+
+ restrictedUsage.get(generalRestriction.value).push({
+ type: nfCommon.formatType(documentedType),
+ bundle: nfCommon.formatBundle(documentedType.bundle),
+ explanation: nfCommon.escapeHtml(documentedType.usageRestriction)
+ });
+ }
+ }
+
+ // record the group
+ groups.add(documentedType.bundle.group);
+
+ // create the row for the processor type
+ processorTypesData.addItem({
+ id: i,
+ label: nfCommon.substringAfterLast(type, '.'),
+ type: type,
+ bundle: documentedType.bundle,
+ description: nfCommon.escapeHtml(documentedType.description),
+ restricted: documentedType.restricted,
+ usageRestriction: nfCommon.escapeHtml(documentedType.usageRestriction),
+ explicitRestrictions: documentedType.explicitRestrictions,
+ tags: documentedType.tags.join(', ')
+ });
+
+ // count the frequency of each tag for this type
+ $.each(documentedType.tags, function (i, tag) {
+ tags.push(tag.toLowerCase());
+ });
+ });
+
+ // end the update
+ processorTypesData.endUpdate();
+
+ // resort
+ processorTypesData.reSort();
+ processorTypesGrid.invalidate();
+
+ // set the component restrictions and the corresponding required permissions
+ nfCanvasUtils.addComponentRestrictions(restrictedUsage, requiredPermissions);
+
+ // set the total number of processors
+ $('#total-processor-types, #displayed-processor-types').text(response.processorTypes.length);
+
+ // create the tag cloud
+ $('#processor-tag-cloud').tagcloud({
+ tags: tags,
+ select: applyFilter,
+ remove: applyFilter
+ });
+
+ // build the combo options
+ var options = [{
+ text: 'all groups',
+ value: ''
+ }];
+ groups.each(function (group) {
+ options.push({
+ text: group,
+ value: group
+ });
+ });
+
+ // initialize the bundle group combo
+ $('#processor-bundle-group-combo').combo({
+ options: options,
+ select: applyFilter
+ });
+ }).fail(nfErrorHandler.handleAjaxError);
+
+//************* REPLICATED CODE---ENDS HERE------******************
+
+
+
+ // clear the selected tag cloud
+ $('#processor-tag-cloud').tagcloud('clearSelectedTags');
+
+ // reset the group combo
+ $('#processor-bundle-group-combo').combo('setSelectedOption', {
+ value: ''
+ });
+
+ // clear any filter strings
+ $('#processor-type-filter').val('');
+
+ // reapply the filter
+ applyFilter();
+
+ // clear the selected row
+ $('#processor-type-description').attr('title', '').text('');
+ $('#processor-type-name').attr('title', '').text('');
+ $('#processor-type-bundle').attr('title', '').text('');
+ $('#selected-processor-name').text('');
+ $('#selected-processor-type').text('').removeData('bundle');
+
+ // unselect any current selection
+ var processTypesGrid = $('#processor-types-table').data('gridInstance');
+ processTypesGrid.setSelectedRows([]);
+ processTypesGrid.resetActiveCell();
+ };
+
+ /**
+ * Create the processor and add to the graph.
+ *
+ * @argument {string} name The processor name.
+ * @argument {string} processorType The processor type.
+ * @argument {object} bundle The processor bundle.
+ * @argument {object} pt The point that the processor was dropped.
+ */
+ var createProcessor = function (name, processorType, bundle, pt) {
+ var processorEntity = {
+ 'revision': nfClient.getRevision({
+ 'revision': {
+ 'version': 0
+ }
+ }),
+ 'disconnectedNodeAcknowledged': nfStorage.isDisconnectionAcknowledged(),
+ 'component': {
+ 'type': processorType,
+ 'bundle': bundle,
+ 'name': name,
+ 'position': {
+ 'x': pt.x,
+ 'y': pt.y
+ }
+ }
+ };
+
+ // create a new processor of the defined type
+ $.ajax({
+ type: 'POST',
+ url: serviceProvider.headerCtrl.toolboxCtrl.config.urls.api + '/process-groups/' + encodeURIComponent(nfCanvasUtils.getGroupId()) + '/processors',
+ data: JSON.stringify(processorEntity),
+ dataType: 'json',
+ contentType: 'application/json'
+ }).done(function (response) {
+ // add the processor to the graph
+ nfGraph.add({
+ 'processors': [response]
+ }, {
+ 'selectAll': true
+ });
+
+ // update component visibility
+ nfGraph.updateVisibility();
+
+ // update the birdseye
+ nfBirdseye.refresh();
+ }).fail(nfErrorHandler.handleAjaxError);
+ };
+
+ /**
+ * Whether the specified item is selectable.
+ *
+ * @param item process type
+ */
+ var isSelectable = function (item) {
+ return item.restricted === false || nfCommon.canAccessComponentRestrictions(item.explicitRestrictions);
+ };
+
+ function ProcessorComponent() {
+
+ this.icon = 'icon icon-processor';
+
+ this.hoverIcon = 'icon icon-processor-add';
+
+ /**
+ * The processor component's modal.
+ */
+ this.modal = {
+
+ /**
+ * The processor component modal's filter.
+ */
+ filter: {
+
+ /**
+ * Initialize the filter.
+ */
+ init: function () {
+ // initialize the processor type table
+ var processorTypesColumns = [
+ {
+ id: 'type',
+ name: 'Type',
+ field: 'label',
+ formatter: nfCommon.typeFormatter,
+ sortable: true,
+ resizable: true
+ },
+ {
+ id: 'version',
+ name: 'Version',
+ field: 'version',
+ formatter: nfCommon.typeVersionFormatter,
+ sortable: true,
+ resizable: true
+ },
+ {
+ id: 'tags',
+ name: 'Tags',
+ field: 'tags',
+ sortable: true,
+ resizable: true,
+ formatter: nfCommon.genericValueFormatter
+ }
+ ];
+
+ var processorTypesOptions = {
+ forceFitColumns: true,
+ enableTextSelectionOnCells: true,
+ enableCellNavigation: true,
+ enableColumnReorder: false,
+ autoEdit: false,
+ multiSelect: false,
+ rowHeight: 24
+ };
+
+ // initialize the dataview
+ processorTypesData = new Slick.Data.DataView({
+ inlineFilters: false
+ });
+ processorTypesData.setItems([]);
+ processorTypesData.setFilterArgs({
+ searchString: getFilterText()
+ });
+ processorTypesData.setFilter(filter);
+
+ // initialize the sort
+ nfCommon.sortType({
+ columnId: 'type',
+ sortAsc: true
+ }, processorTypesData);
+
+ // initialize the grid
+ var processorTypesGrid = new Slick.Grid('#processor-types-table', processorTypesData, processorTypesColumns, processorTypesOptions);
+ processorTypesGrid.setSelectionModel(new Slick.RowSelectionModel());
+ processorTypesGrid.registerPlugin(new Slick.AutoTooltips());
+ processorTypesGrid.setSortColumn('type', true);
+ processorTypesGrid.onSort.subscribe(function (e, args) {
+ nfCommon.sortType({
+ columnId: args.sortCol.field,
+ sortAsc: args.sortAsc
+ }, processorTypesData);
+ });
+ processorTypesGrid.onSelectedRowsChanged.subscribe(function (e, args) {
+ if ($.isArray(args.rows) && args.rows.length === 1) {
+ var processorTypeIndex = args.rows[0];
+ var processorType = processorTypesGrid.getDataItem(processorTypeIndex);
+
+ // set the processor type description
+ if (nfCommon.isDefinedAndNotNull(processorType)) {
+ if (nfCommon.isBlank(processorType.description)) {
+ $('#processor-type-description')
+ .attr('title', '')
+ .html('<span class="unset">No description specified</span>');
+ } else {
+ $('#processor-type-description')
+ .width($('#processor-description-container').innerWidth() - 1)
+ .html(processorType.description)
+ .ellipsis();
+ }
+
+ var bundle = nfCommon.formatBundle(processorType.bundle);
+ var type = nfCommon.formatType(processorType);
+
+ // populate the dom
+ $('#processor-type-name').text(type).attr('title', type);
+ $('#processor-type-bundle').text(bundle).attr('title', bundle);
+ $('#selected-processor-name').text(processorType.label);
+ $('#selected-processor-type').text(processorType.type).data('bundle', processorType.bundle);
+
+ // refresh the buttons based on the current selection
+ $('#new-processor-dialog').modal('refreshButtons');
+ }
+ }
+ });
+ processorTypesGrid.onViewportChanged.subscribe(function (e, args) {
+ nfCommon.cleanUpTooltips($('#processor-types-table'), 'div.view-usage-restriction');
+ });
+
+ // wire up the dataview to the grid
+ processorTypesData.onRowCountChanged.subscribe(function (e, args) {
+ processorTypesGrid.updateRowCount();
+ processorTypesGrid.render();
+
+ // update the total number of displayed processors
+ $('#displayed-processor-types').text(args.current);
+ });
+ processorTypesData.onRowsChanged.subscribe(function (e, args) {
+ processorTypesGrid.invalidateRows(args.rows);
+ processorTypesGrid.render();
+ });
+ processorTypesData.syncGridSelection(processorTypesGrid, false);
+
+ // hold onto an instance of the grid
+ $('#processor-types-table').data('gridInstance', processorTypesGrid).on('mouseenter', 'div.slick-cell', function (e) {
+ var usageRestriction = $(this).find('div.view-usage-restriction');
+ if (usageRestriction.length && !usageRestriction.data('qtip')) {
+ var rowId = $(this).find('span.row-id').text();
+
+ // get the status item
+ var item = processorTypesData.getItemById(rowId);
+
+ // show the tooltip
+ if (item.restricted === true) {
+ var restrictionTip = $('<div></div>');
+
+ if (nfCommon.isBlank(item.usageRestriction)) {
+ restrictionTip.append($('<p style="margin-bottom: 3px;"></p>').text('Requires the following permissions:'));
+ } else {
+ restrictionTip.append($('<p style="margin-bottom: 3px;"></p>').text(item.usageRestriction + ' Requires the following permissions:'));
+ }
+
+ var restrictions = [];
+ if (nfCommon.isDefinedAndNotNull(item.explicitRestrictions)) {
+ $.each(item.explicitRestrictions, function (_, explicitRestriction) {
+ var requiredPermission = explicitRestriction.requiredPermission;
+ restrictions.push("'" + requiredPermission.label + "' - " + nfCommon.escapeHtml(explicitRestriction.explanation));
+ });
+ } else {
+ restrictions.push('Access to restricted components regardless of restrictions.');
+ }
+ restrictionTip.append(nfCommon.formatUnorderedList(restrictions));
+
+ usageRestriction.qtip($.extend({}, nfCommon.config.tooltipConfig, {
+ content: restrictionTip,
+ position: {
+ container: $('#summary'),
+ at: 'bottom right',
+ my: 'top left',
+ adjust: {
+ x: 4,
+ y: 4
+ }
+ }
+ }));
+ }
+ }
+ });
+
+ var generalRestriction = nfCommon.getPolicyTypeListing('restricted-components');
+
+ // load the available processor types, this select is shown in the
+ // new processor dialog when a processor is dragged onto the screen
+ $.ajax({
+ type: 'GET',
+ url:'../nifi-api/flow/processor-types',
+// url: serviceProvider.headerCtrl.toolboxCtrl.config.urls.processorTypes,
+ dataType: 'json'
+ }).done(function (response) {
+ console.log(response);
+ var tags = [];
+ var groups = d3.set();
+ var restrictedUsage = d3.map();
+ var requiredPermissions = d3.map();
+
+ // begin the update
+ processorTypesData.beginUpdate();
+
+ // go through each processor type
+ $.each(response.processorTypes, function (i, documentedType) {
+ var type = documentedType.type;
+
+ if (documentedType.restricted === true) {
+ if (nfCommon.isDefinedAndNotNull(documentedType.explicitRestrictions)) {
+ $.each(documentedType.explicitRestrictions, function (_, explicitRestriction) {
+ var requiredPermission = explicitRestriction.requiredPermission;
+
+ // update required permissions
+ if (!requiredPermissions.has(requiredPermission.id)) {
+ requiredPermissions.set(requiredPermission.id, requiredPermission.label);
+ }
+
+ // update component restrictions
+ if (!restrictedUsage.has(requiredPermission.id)) {
+ restrictedUsage.set(requiredPermission.id, []);
+ }
+
+ restrictedUsage.get(requiredPermission.id).push({
+ type: nfCommon.formatType(documentedType),
+ bundle: nfCommon.formatBundle(documentedType.bundle),
+ explanation: nfCommon.escapeHtml(explicitRestriction.explanation)
+ })
+ });
+ } else {
+ // update required permissions
+ if (!requiredPermissions.has(generalRestriction.value)) {
+ requiredPermissions.set(generalRestriction.value, generalRestriction.text);
+ }
+
+ // update component restrictions
+ if (!restrictedUsage.has(generalRestriction.value)) {
+ restrictedUsage.set(generalRestriction.value, []);
+ }
+
+ restrictedUsage.get(generalRestriction.value).push({
+ type: nfCommon.formatType(documentedType),
+ bundle: nfCommon.formatBundle(documentedType.bundle),
+ explanation: nfCommon.escapeHtml(documentedType.usageRestriction)
+ });
+ }
+ }
+
+ // record the group
+ groups.add(documentedType.bundle.group);
+
+ // create the row for the processor type
+ processorTypesData.addItem({
+ id: i,
+ label: nfCommon.substringAfterLast(type, '.'),
+ type: type,
+ bundle: documentedType.bundle,
+ description: nfCommon.escapeHtml(documentedType.description),
+ restricted: documentedType.restricted,
+ usageRestriction: nfCommon.escapeHtml(documentedType.usageRestriction),
+ explicitRestrictions: documentedType.explicitRestrictions,
+ tags: documentedType.tags.join(', ')
+ });
+
+ // count the frequency of each tag for this type
+ $.each(documentedType.tags, function (i, tag) {
+ tags.push(tag.toLowerCase());
+ });
+ });
+
+ // end the update
+ processorTypesData.endUpdate();
+
+ // resort
+ processorTypesData.reSort();
+ processorTypesGrid.invalidate();
+
+ // set the component restrictions and the corresponding required permissions
+ nfCanvasUtils.addComponentRestrictions(restrictedUsage, requiredPermissions);
+
+ // set the total number of processors
+ $('#total-processor-types, #displayed-processor-types').text(response.processorTypes.length);
+
+ // create the tag cloud
+ $('#processor-tag-cloud').tagcloud({
+ tags: tags,
+ select: applyFilter,
+ remove: applyFilter
+ });
+
+ // build the combo options
+ var options = [{
+ text: 'all groups',
+ value: ''
+ }];
+ groups.each(function (group) {
+ options.push({
+ text: group,
+ value: group
+ });
+ });
+
+ // initialize the bundle group combo
+ $('#processor-bundle-group-combo').combo({
+ options: options,
+ select: applyFilter
+ });
+ }).fail(nfErrorHandler.handleAjaxError);
+ }
+ },
+
+ /**
+ * Gets the modal element.
+ *
+ * @returns {*|jQuery|HTMLElement}
+ */
+ getElement: function () {
+ return $('#new-processor-dialog');
+ },
+
+ /**
+ * Initialize the modal.
+ */
+ init: function () {
+ this.filter.init();
+
+ // configure the new processor dialog
+ this.getElement().modal({
+ scrollableContentStyle: 'scrollable',
+ headerText: 'Add Processor',
+ handler: {
+ resize: function () {
+ $('#processor-type-description')
+ .width($('#processor-description-container').innerWidth() - 1)
+ .text($('#processor-type-description').attr('title'))
+ .ellipsis();
+ }
+ }
+ });
+ },
+
+ /**
+ * Updates the modal config.
+ *
+ * @param {string} name The name of the property to update.
+ * @param {object|array} config The config for the `name`.
+ */
+ update: function (name, config) {
+ this.getElement().modal(name, config);
+ },
+
+ /**
+ * Show the modal
+ */
+ show: function () {
+ this.getElement().modal('show');
+ },
+
+ /**
+ * Hide the modal
+ */
+ hide: function () {
+ this.getElement().modal('hide');
+ }
+ };
+ }
+
+ ProcessorComponent.prototype = {
+ constructor: ProcessorComponent,
+
+ /**
+ * Gets the component.
+ *
+ * @returns {*|jQuery|HTMLElement}
+ */
+ getElement: function () {
+ return $('#processor-component');
+ },
+
+ /**
+ * Enable the component.
+ */
+ enabled: function () {
+ this.getElement().attr('disabled', false);
+ },
+
+ /**
+ * Disable the component.
+ */
+ disabled: function () {
+ this.getElement().attr('disabled', true);
+ },
+
+ /**
+ * Handler function for when component is dropped on the canvas.
+ *
+ * @argument {object} pt The point that the component was dropped
+ */
+ dropHandler: function (pt) {
+ this.promptForProcessorType(pt);
+ },
+
+ /**
+ * The drag icon for the toolbox component.
+ *
+ * @param event
+ * @returns {*|jQuery|HTMLElement}
+ */
+ dragIcon: function (event) {
+ return $('<div class="icon icon-processor-add"></div>');
+ },
+
+ /**
+ * Prompts the user to select the type of new processor to create.
+ *
+ * @argument {object} pt The point that the processor was dropped
+ */
+ promptForProcessorType: function (pt) {
+ var processorComponent = this;
+
+ // handles adding the selected processor at the specified point
+ var addProcessor = function () {
+ // get the type of processor currently selected
+ var name = $('#selected-processor-name').text();
+ var processorType = $('#selected-processor-type').text();
+ var bundle = $('#selected-processor-type').data('bundle');
+
+ // ensure something was selected
+ if (name === '' || processorType === '') {
+ nfDialog.showOkDialog({
+ headerText: 'Add Processor',
+ dialogContent: 'The type of processor to create must be selected.'
+ });
+ } else {
+ // create the new processor
+ createProcessor(name, processorType, bundle, pt);
+ }
+
+ // hide the dialog
+ processorComponent.modal.hide();
+ };
+
+ // get the grid reference
+ var grid = $('#processor-types-table').data('gridInstance');
+ var dataview = grid.getData();
+
+ // add the processor when its double clicked in the table
+ var gridDoubleClick = function (e, args) {
+ var processorType = grid.getDataItem(args.row);
+
+ if (isSelectable(processorType)) {
+ $('#selected-processor-name').text(processorType.label);
+ $('#selected-processor-type').text(processorType.type).data('bundle', processorType.bundle);
+
+ addProcessor();
+ }
+ };
+
+ // register a handler for double click events
+ grid.onDblClick.subscribe(gridDoubleClick);
+
+ // update the button model
+ this.modal.update('setButtonModel', [{
+ buttonText: 'Add',
+ color: {
+ base: '#728E9B',
+ hover: '#004849',
+ text: '#ffffff'
+ },
+ disabled: function () {
+ var selected = grid.getSelectedRows();
+
+ if (selected.length > 0) {
+ // grid configured with multi-select = false
+ var item = grid.getDataItem(selected[0]);
+ return isSelectable(item) === false;
+ } else {
+ return dataview.getLength() === 0;
+ }
+ },
+ handler: {
+ click: addProcessor
+ }
+ },
+ {
+ buttonText: 'Cancel',
+ color: {
+ base: '#E3E8EB',
+ hover: '#C7D2D7',
+ text: '#004849'
+ },
+ handler: {
+ click: function () {
+ $('#new-processor-dialog').modal('hide');
+ }
+ }
+ }]);
+
+ // set a new handler for closing the the dialog
+ this.modal.update('setCloseHandler', function () {
+ // remove the handler
+ grid.onDblClick.unsubscribe(gridDoubleClick);
+
+ // clear the current filters
+ resetProcessorDialog();
+ });
+
+ // show the dialog
+ this.modal.show();
+
+ var navigationKeys = [$.ui.keyCode.UP, $.ui.keyCode.PAGE_UP, $.ui.keyCode.DOWN, $.ui.keyCode.PAGE_DOWN];
+
+ // setup the filter
+ $('#processor-type-filter').off('keyup').on('keyup', function (e) {
+ var code = e.keyCode ? e.keyCode : e.which;
+
+ // ignore navigation keys
+ if ($.inArray(code, navigationKeys) !== -1) {
+ return;
+ }
+
+ if (code === $.ui.keyCode.ENTER) {
+ var selected = grid.getSelectedRows();
+
+ if (selected.length > 0) {
+ // grid configured with multi-select = false
+ var item = grid.getDataItem(selected[0]);
+ if (isSelectable(item)) {
+ addProcessor();
+ }
+ }
+ } else {
+ applyFilter();
+ }
+ });
+
+ // setup row navigation
+ nfFilteredDialogCommon.addKeydownListener('#processor-type-filter', grid, dataview);
+
+ // adjust the grid canvas now that its been rendered
+ grid.resizeCanvas();
+
+ // auto select the first row if possible
+ if (dataview.getLength() > 0) {
+ nfFilteredDialogCommon.choseFirstRow(grid);
+ }
+
+ // set the initial focus
+ $('#processor-type-filter').focus()
+ }
+ };
+
+ var processorComponent = new ProcessorComponent();
+ return processorComponent;
+ };
+}));
diff --git a/mod/designtool/designtool-web/src/main/webapp/js/nf/canvas/nf-connection-configuration.js b/mod/designtool/designtool-web/src/main/webapp/js/nf/canvas/nf-connection-configuration.js
new file mode 100644
index 0000000..0cdb1a1
--- /dev/null
+++ b/mod/designtool/designtool-web/src/main/webapp/js/nf/canvas/nf-connection-configuration.js
@@ -0,0 +1,1587 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Modifications to the original nifi code for the ONAP project are made
+ * available under the Apache License, Version 2.0
+ */
+
+/* global define, module, require, exports */
+
+(function (root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ define(['jquery',
+ 'd3',
+ 'nf.ErrorHandler',
+ 'nf.Common',
+ 'nf.Dialog',
+ 'nf.Storage',
+ 'nf.Client',
+ 'nf.CanvasUtils',
+ 'nf.Connection'],
+ function ($, d3, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfCanvasUtils, nfConnection) {
+ return (nf.ConnectionConfiguration = factory($, d3, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfCanvasUtils, nfConnection));
+ });
+ } else if (typeof exports === 'object' && typeof module === 'object') {
+ module.exports = (nf.ConnectionConfiguration =
+ factory(require('jquery'),
+ require('d3'),
+ require('nf.ErrorHandler'),
+ require('nf.Common'),
+ require('nf.Dialog'),
+ require('nf.Storage'),
+ require('nf.Client'),
+ require('nf.CanvasUtils'),
+ require('nf.Connection')));
+ } else {
+ nf.ConnectionConfiguration = factory(root.$,
+ root.d3,
+ root.nf.ErrorHandler,
+ root.nf.Common,
+ root.nf.Dialog,
+ root.nf.Storage,
+ root.nf.Client,
+ root.nf.CanvasUtils,
+ root.nf.Connection);
+ }
+}(this, function ($, d3, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfCanvasUtils, nfConnection) {
+ 'use strict';
+
+ var nfBirdseye;
+ var nfGraph;
+
+ var defaultBackPressureObjectThreshold;
+ var defaultBackPressureDataSizeThreshold;
+
+ var CONNECTION_OFFSET_Y_INCREMENT = 75;
+ var CONNECTION_OFFSET_X_INCREMENT = 200;
+
+ var config = {
+ urls: {
+ api: '../nifi-api',
+ prioritizers: '../nifi-api/flow/prioritizers'
+ }
+ };
+
+ /**
+ * Removes the temporary if necessary.
+ */
+ var removeTempEdge = function () {
+ d3.select('path.connector').remove();
+ };
+
+ /**
+ * Activates dialog's button model refresh on a connection relationships change.
+ */
+ var addDialogRelationshipsChangeListener = function() {
+ // refresh button model when a relationship selection changes
+ $('div.available-relationship').bind('change', function() {
+ $('#connection-configuration').modal('refreshButtons');
+ });
+ }
+
+ /**
+ * Initializes the source in the new connection dialog.
+ *
+ * @argument {selection} source The source
+ */
+ var initializeSourceNewConnectionDialog = function (source) {
+ // handle the selected source
+ if (nfCanvasUtils.isProcessor(source)) {
+ return $.Deferred(function (deferred) {
+ // initialize the source processor
+ initializeSourceProcessor(source).done(function (processor) {
+ if (!nfCommon.isEmpty(processor.relationships)) {
+ // populate the available connections
+ $.each(processor.relationships, function (i, relationship) {
+ createRelationshipOption(relationship.name);
+ });
+
+ // resolve the deferred
+ deferred.resolve();
+ } else {
+ // there are no relationships for this processor
+ nfDialog.showOkDialog({
+ headerText: 'Connection Configuration',
+ dialogContent: '\'' + nfCommon.escapeHtml(processor.name) + '\' does not support any relationships.'
+ });
+
+ // reset the dialog
+ resetDialog();
+
+ deferred.reject();
+ }
+ }).fail(function () {
+ deferred.reject();
+ });
+ }).promise();
+ } else {
+ return $.Deferred(function (deferred) {
+ // determine how to initialize the source
+ var connectionSourceDeferred;
+ if (nfCanvasUtils.isInputPort(source)) {
+ connectionSourceDeferred = initializeSourceInputPort(source);
+ } else if (nfCanvasUtils.isRemoteProcessGroup(source)) {
+ connectionSourceDeferred = initializeSourceRemoteProcessGroup(source);
+ } else if (nfCanvasUtils.isProcessGroup(source)) {
+ connectionSourceDeferred = initializeSourceProcessGroup(source);
+ } else {
+ connectionSourceDeferred = initializeSourceFunnel(source);
+ }
+
+ // finish initialization when appropriate
+ connectionSourceDeferred.done(function () {
+ deferred.resolve();
+ }).fail(function () {
+ deferred.reject();
+ });
+ }).promise();
+ }
+ };
+
+ /**
+ * Initializes the source when the source is an input port.
+ *
+ * @argument {selection} source The source
+ */
+ var initializeSourceInputPort = function (source) {
+ return $.Deferred(function (deferred) {
+ // get the input port data
+ var inputPortData = source.datum();
+ var inputPortName = inputPortData.permissions.canRead ? inputPortData.component.name : inputPortData.id;
+
+ // populate the port information
+ $('#input-port-source').show();
+ $('#input-port-source-name').text(inputPortName).attr('title', inputPortName);
+
+ // populate the connection source details
+ $('#connection-source-id').val(inputPortData.id);
+ $('#connection-source-component-id').val(inputPortData.id);
+
+ // populate the group details
+ $('#connection-source-group-id').val(nfCanvasUtils.getGroupId());
+ $('#connection-source-group-name').text(nfCanvasUtils.getGroupName());
+
+ // resolve the deferred
+ deferred.resolve();
+ }).promise();
+ };
+
+ /**
+ * Initializes the source when the source is an input port.
+ *
+ * @argument {selection} source The source
+ */
+ var initializeSourceFunnel = function (source) {
+ return $.Deferred(function (deferred) {
+ // get the funnel data
+ var funnelData = source.datum();
+
+ // populate the port information
+ $('#funnel-source').show();
+
+ // populate the connection source details
+ $('#connection-source-id').val(funnelData.id);
+ $('#connection-source-component-id').val(funnelData.id);
+
+ // populate the group details
+ $('#connection-source-group-id').val(nfCanvasUtils.getGroupId());
+ $('#connection-source-group-name').text(nfCanvasUtils.getGroupName());
+
+ // resolve the deferred
+ deferred.resolve();
+ }).promise();
+ };
+
+ /**
+ * Initializes the source when the source is a processor.
+ *
+ * @argument {selection} source The source
+ */
+ var initializeSourceProcessor = function (source) {
+ return $.Deferred(function (deferred) {
+ // get the processor data
+ var processorData = source.datum();
+ var processorName = processorData.permissions.canRead ? processorData.component.name : processorData.id;
+ var processorType = processorData.permissions.canRead ? nfCommon.substringAfterLast(processorData.component.type, '.') : 'Processor';
+
+ // populate the source processor information
+ $('#processor-source').show();
+ $('#processor-source-name').text(processorName).attr('title', processorName);
+ $('#processor-source-type').text(processorType).attr('title', processorType);
+
+ // populate the connection source details
+ $('#connection-source-id').val(processorData.id);
+ $('#connection-source-component-id').val(processorData.id);
+
+ // populate the group details
+ $('#connection-source-group-id').val(nfCanvasUtils.getGroupId());
+ $('#connection-source-group-name').text(nfCanvasUtils.getGroupName());
+
+ // show the available relationships
+ $('#relationship-names-container').show();
+
+ deferred.resolve(processorData.component);
+ });
+ };
+
+ /**
+ * Initializes the source when the source is a process group.
+ *
+ * @argument {selection} source The source
+ */
+ var initializeSourceProcessGroup = function (source) {
+ return $.Deferred(function (deferred) {
+ // get the process group data
+ var processGroupData = source.datum();
+
+ $.ajax({
+ type: 'GET',
+ url: config.urls.api + '/flow/process-groups/' + encodeURIComponent(processGroupData.id),
+ dataType: 'json'
+ }).done(function (response) {
+ var processGroup = response.processGroupFlow;
+ var processGroupName = response.permissions.canRead ? processGroup.breadcrumb.breadcrumb.name : processGroup.id;
+ var processGroupContents = processGroup.flow;
+
+ // show the output port options
+ var options = [];
+ $.each(processGroupContents.outputPorts, function (i, outputPort) {
+ // require explicit access to the output port as it's the source of the connection
+ if (outputPort.permissions.canRead && outputPort.permissions.canWrite) {
+ var component = outputPort.component;
+ options.push({
+ text: component.name,
+ value: component.id,
+ description: nfCommon.escapeHtml(component.comments)
+ });
+ }
+ });
+
+ // only proceed if there are output ports
+ if (!nfCommon.isEmpty(options)) {
+ $('#output-port-source').show();
+
+ // sort the options
+ options.sort(function (a, b) {
+ return a.text.localeCompare(b.text);
+ });
+
+ // create the combo
+ $('#output-port-options').combo({
+ options: options,
+ maxHeight: 300,
+ select: function (option) {
+ $('#connection-source-id').val(option.value);
+ }
+ });
+
+ // populate the connection details
+ $('#connection-source-component-id').val(processGroup.id);
+
+ // populate the group details
+ $('#connection-source-group-id').val(processGroup.id);
+ $('#connection-source-group-name').text(processGroupName);
+
+ deferred.resolve();
+ } else {
+ var message = '\'' + nfCommon.escapeHtml(processGroupName) + '\' does not have any output ports.';
+ if (nfCommon.isEmpty(processGroupContents.outputPorts) === false) {
+ message = 'Not authorized for any output ports in \'' + nfCommon.escapeHtml(processGroupName) + '\'.';
+ }
+
+ // there are no output ports for this process group
+ nfDialog.showOkDialog({
+ headerText: 'Connection Configuration',
+ dialogContent: message
+ });
+
+ // reset the dialog
+ resetDialog();
+
+ deferred.reject();
+ }
+ }).fail(function (xhr, status, error) {
+ // handle the error
+ nfErrorHandler.handleAjaxError(xhr, status, error);
+
+ deferred.reject();
+ });
+ }).promise();
+ };
+
+ /**
+ * Initializes the source when the source is a remote process group.
+ *
+ * @argument {selection} source The source
+ */
+ var initializeSourceRemoteProcessGroup = function (source) {
+ return $.Deferred(function (deferred) {
+ // get the remote process group data
+ var remoteProcessGroupData = source.datum();
+
+ $.ajax({
+ type: 'GET',
+ url: remoteProcessGroupData.uri,
+ dataType: 'json'
+ }).done(function (response) {
+ var remoteProcessGroup = response.component;
+ var remoteProcessGroupContents = remoteProcessGroup.contents;
+
+ // only proceed if there are output ports
+ if (!nfCommon.isEmpty(remoteProcessGroupContents.outputPorts)) {
+ $('#output-port-source').show();
+
+ // show the output port options
+ var options = [];
+ $.each(remoteProcessGroupContents.outputPorts, function (i, outputPort) {
+ options.push({
+ text: outputPort.name,
+ value: outputPort.id,
+ disabled: outputPort.exists === false,
+ description: nfCommon.escapeHtml(outputPort.comments)
+ });
+ });
+
+ // sort the options
+ options.sort(function (a, b) {
+ return a.text.localeCompare(b.text);
+ });
+
+ // create the combo
+ $('#output-port-options').combo({
+ options: options,
+ maxHeight: 300,
+ select: function (option) {
+ $('#connection-source-id').val(option.value);
+ }
+ });
+
+ // populate the connection details
+ $('#connection-source-component-id').val(remoteProcessGroup.id);
+
+ // populate the group details
+ $('#connection-source-group-id').val(remoteProcessGroup.id);
+ $('#connection-source-group-name').text(remoteProcessGroup.name);
+
+ deferred.resolve();
+ } else {
+ // there are no relationships for this processor
+ nfDialog.showOkDialog({
+ headerText: 'Connection Configuration',
+ dialogContent: '\'' + nfCommon.escapeHtml(remoteProcessGroup.name) + '\' does not have any output ports.'
+ });
+
+ // reset the dialog
+ resetDialog();
+
+ deferred.reject();
+ }
+ }).fail(function (xhr, status, error) {
+ // handle the error
+ nfErrorHandler.handleAjaxError(xhr, status, error);
+
+ deferred.reject();
+ });
+ }).promise();
+ };
+
+ var initializeDestinationNewConnectionDialog = function (destination) {
+ if (nfCanvasUtils.isOutputPort(destination)) {
+ return initializeDestinationOutputPort(destination);
+ } else if (nfCanvasUtils.isProcessor(destination)) {
+ return $.Deferred(function (deferred) {
+ initializeDestinationProcessor(destination).done(function (processor) {
+ // Need to add the destination relationships because we need to
+ // provide this to wire up the publishers and subscribers correctly
+ // for a given connection since processors can have multiple
+ // relationships
+ $.each(processor.relationships, function (i, relationship) {
+ createRelationshipOption(relationship.name);
+ });
+
+ deferred.resolve();
+ }).fail(function () {
+ deferred.reject();
+ });
+ }).promise();
+ } else if (nfCanvasUtils.isRemoteProcessGroup(destination)) {
+ return initializeDestinationRemoteProcessGroup(destination);
+ } else if (nfCanvasUtils.isFunnel(destination)) {
+ return initializeDestinationFunnel(destination);
+ } else {
+ return initializeDestinationProcessGroup(destination);
+ }
+ };
+
+ var initializeDestinationOutputPort = function (destination) {
+ return $.Deferred(function (deferred) {
+ var outputPortData = destination.datum();
+ var outputPortName = outputPortData.permissions.canRead ? outputPortData.component.name : outputPortData.id;
+
+ $('#output-port-destination').show();
+ $('#output-port-destination-name').text(outputPortName).attr('title', outputPortName);
+
+ // populate the connection destination details
+ $('#connection-destination-id').val(outputPortData.id);
+ $('#connection-destination-component-id').val(outputPortData.id);
+
+ // populate the group details
+ $('#connection-destination-group-id').val(nfCanvasUtils.getGroupId());
+ $('#connection-destination-group-name').text(nfCanvasUtils.getGroupName());
+
+ deferred.resolve();
+ }).promise();
+ };
+
+ var initializeDestinationFunnel = function (destination) {
+ return $.Deferred(function (deferred) {
+ var funnelData = destination.datum();
+
+ $('#funnel-destination').show();
+
+ // populate the connection destination details
+ $('#connection-destination-id').val(funnelData.id);
+ $('#connection-destination-component-id').val(funnelData.id);
+
+ // populate the group details
+ $('#connection-destination-group-id').val(nfCanvasUtils.getGroupId());
+ $('#connection-destination-group-name').text(nfCanvasUtils.getGroupName());
+
+ deferred.resolve();
+ }).promise();
+ };
+
+ var initializeDestinationProcessor = function (destination) {
+ return $.Deferred(function (deferred) {
+ var processorData = destination.datum();
+ var processorName = processorData.permissions.canRead ? processorData.component.name : processorData.id;
+ var processorType = processorData.permissions.canRead ? nfCommon.substringAfterLast(processorData.component.type, '.') : 'Processor';
+
+ $('#processor-destination').show();
+ $('#processor-destination-name').text(processorName).attr('title', processorName);
+ $('#processor-destination-type').text(processorType).attr('title', processorType);
+
+ // populate the connection destination details
+ $('#connection-destination-id').val(processorData.id);
+ $('#connection-destination-component-id').val(processorData.id);
+
+ // populate the group details
+ $('#connection-destination-group-id').val(nfCanvasUtils.getGroupId());
+ $('#connection-destination-group-name').text(nfCanvasUtils.getGroupName());
+
+ deferred.resolve(processorData.component);
+ }).promise();
+ };
+
+ /**
+ * Initializes the destination when the destination is a process group.
+ *
+ * @argument {selection} destination The destination
+ */
+ var initializeDestinationProcessGroup = function (destination) {
+ return $.Deferred(function (deferred) {
+ var processGroupData = destination.datum();
+
+ $.ajax({
+ type: 'GET',
+ url: config.urls.api + '/flow/process-groups/' + encodeURIComponent(processGroupData.id),
+ dataType: 'json'
+ }).done(function (response) {
+ var processGroup = response.processGroupFlow;
+ var processGroupName = response.permissions.canRead ? processGroup.breadcrumb.breadcrumb.name : processGroup.id;
+ var processGroupContents = processGroup.flow;
+
+ // show the input port options
+ var options = [];
+ $.each(processGroupContents.inputPorts, function (i, inputPort) {
+ options.push({
+ text: inputPort.permissions.canRead ? inputPort.component.name : inputPort.id,
+ value: inputPort.id,
+ description: inputPort.permissions.canRead ? nfCommon.escapeHtml(inputPort.component.comments) : null
+ });
+ });
+
+ // only proceed if there are output ports
+ if (!nfCommon.isEmpty(options)) {
+ $('#input-port-destination').show();
+
+ // sort the options
+ options.sort(function (a, b) {
+ return a.text.localeCompare(b.text);
+ });
+
+ // create the combo
+ $('#input-port-options').combo({
+ options: options,
+ maxHeight: 300,
+ select: function (option) {
+ $('#connection-destination-id').val(option.value);
+ }
+ });
+
+ // populate the connection details
+ $('#connection-destination-component-id').val(processGroup.id);
+
+ // populate the group details
+ $('#connection-destination-group-id').val(processGroup.id);
+ $('#connection-destination-group-name').text(processGroupName);
+
+ deferred.resolve();
+ } else {
+ // there are no relationships for this processor
+ nfDialog.showOkDialog({
+ headerText: 'Connection Configuration',
+ dialogContent: '\'' + nfCommon.escapeHtml(processGroupName) + '\' does not have any input ports.'
+ });
+
+ // reset the dialog
+ resetDialog();
+
+ deferred.reject();
+ }
+ }).fail(function (xhr, status, error) {
+ // handle the error
+ nfErrorHandler.handleAjaxError(xhr, status, error);
+
+ deferred.reject();
+ });
+ }).promise();
+ };
+
+ /**
+ * Initializes the source when the source is a remote process group.
+ *
+ * @argument {selection} destination The destination
+ * @argument {object} connectionDestination The connection destination object
+ */
+ var initializeDestinationRemoteProcessGroup = function (destination, connectionDestination) {
+ return $.Deferred(function (deferred) {
+ var remoteProcessGroupData = destination.datum();
+
+ $.ajax({
+ type: 'GET',
+ url: remoteProcessGroupData.uri,
+ dataType: 'json'
+ }).done(function (response) {
+ var remoteProcessGroup = response.component;
+ var remoteProcessGroupContents = remoteProcessGroup.contents;
+
+ // only proceed if there are output ports
+ if (!nfCommon.isEmpty(remoteProcessGroupContents.inputPorts)) {
+ $('#input-port-destination').show();
+
+ // show the input port options
+ var options = [];
+ $.each(remoteProcessGroupContents.inputPorts, function (i, inputPort) {
+ options.push({
+ text: inputPort.name,
+ value: inputPort.id,
+ disabled: inputPort.exists === false,
+ description: nfCommon.escapeHtml(inputPort.comments)
+ });
+ });
+
+ // sort the options
+ options.sort(function (a, b) {
+ return a.text.localeCompare(b.text);
+ });
+
+ // create the combo
+ $('#input-port-options').combo({
+ options: options,
+ maxHeight: 300,
+ select: function (option) {
+ $('#connection-destination-id').val(option.value);
+ }
+ });
+
+ // populate the connection details
+ $('#connection-destination-component-id').val(remoteProcessGroup.id);
+
+ // populate the group details
+ $('#connection-destination-group-id').val(remoteProcessGroup.id);
+ $('#connection-destination-group-name').text(remoteProcessGroup.name);
+
+ deferred.resolve();
+ } else {
+ // there are no relationships for this processor
+ nfDialog.showOkDialog({
+ headerText: 'Connection Configuration',
+ dialogContent: '\'' + nfCommon.escapeHtml(remoteProcessGroup.name) + '\' does not have any input ports.'
+ });
+
+ // reset the dialog
+ resetDialog();
+
+ deferred.reject();
+ }
+ }).fail(function (xhr, status, error) {
+ // handle the error
+ nfErrorHandler.handleAjaxError(xhr, status, error);
+
+ deferred.reject();
+ });
+ }).promise();
+ };
+
+ /**
+ * Initializes the source panel for groups.
+ *
+ * @argument {selection} source The source of the connection
+ */
+ var initializeSourceReadOnlyGroup = function (source) {
+ return $.Deferred(function (deferred) {
+ var sourceData = source.datum();
+ var sourceName = sourceData.permissions.canRead ? sourceData.component.name : sourceData.id;
+
+ // populate the port information
+ $('#read-only-output-port-source').show();
+
+ // populate the component information
+ $('#connection-source-component-id').val(sourceData.id);
+
+ // populate the group details
+ $('#connection-source-group-id').val(sourceData.id);
+ $('#connection-source-group-name').text(sourceName);
+
+ // resolve the deferred
+ deferred.resolve();
+ }).promise();
+ };
+
+ /**
+ * Initializes the source in the existing connection dialog.
+ *
+ * @argument {selection} source The source
+ */
+ var initializeSourceEditConnectionDialog = function (source) {
+ if (nfCanvasUtils.isProcessor(source)) {
+ return initializeSourceProcessor(source);
+ } else if (nfCanvasUtils.isInputPort(source)) {
+ return initializeSourceInputPort(source);
+ } else if (nfCanvasUtils.isFunnel(source)) {
+ return initializeSourceFunnel(source);
+ } else {
+ return initializeSourceReadOnlyGroup(source);
+ }
+ };
+
+ /**
+ * Initializes the destination in the existing connection dialog.
+ *
+ * @argument {selection} destination The destination
+ * @argument {object} connectionDestination The connection destination object
+ */
+ var initializeDestinationEditConnectionDialog = function (destination, connectionDestination) {
+ if (nfCanvasUtils.isProcessor(destination)) {
+ return initializeDestinationProcessor(destination);
+ } else if (nfCanvasUtils.isOutputPort(destination)) {
+ return initializeDestinationOutputPort(destination);
+ } else if (nfCanvasUtils.isRemoteProcessGroup(destination)) {
+ return initializeDestinationRemoteProcessGroup(destination, connectionDestination);
+ } else if (nfCanvasUtils.isFunnel(destination)) {
+ return initializeDestinationFunnel(destination);
+ } else {
+ return initializeDestinationProcessGroup(destination);
+ }
+ };
+
+ /**
+ * Creates an option for the specified relationship name.
+ *
+ * @argument {string} name The relationship name
+ */
+ var createRelationshipOption = function (name) {
+ var nameSplit = name.split(":");
+ var nameLabel = name;
+
+ if (nameSplit.length > 1) {
+ // Example: publishes:data_transformation_format:1.0.0:message_router:stream_publish_url
+ var pubSub = nameSplit[0];
+ pubSub = pubSub.charAt(0).toUpperCase() + pubSub.slice(1);
+ nameLabel = pubSub + " " + nameSplit[1] + "/" + nameSplit[2] + " on " + nameSplit[4];
+ }
+
+ var relationshipLabel = $('<div class="relationship-name nf-checkbox-label ellipsis"></div>').text(nameLabel);
+ var relationshipValue = $('<span class="relationship-name-value hidden"></span>').text(name);
+ return $('<div class="available-relationship-container"><div class="available-relationship nf-checkbox checkbox-unchecked"></div>' +
+ '</div>').append(relationshipLabel).append(relationshipValue).appendTo('#relationship-names');
+ };
+
+ /**
+ * Adds a new connection.
+ *
+ * @argument {array} selectedRelationships The selected relationships
+ */
+ var addConnection = function (selectedRelationships) {
+ // get the connection details
+ var sourceId = $('#connection-source-id').val();
+ var destinationId = $('#connection-destination-id').val();
+
+ // get the selection components
+ var sourceComponentId = $('#connection-source-component-id').val();
+ var source = d3.select('#id-' + sourceComponentId);
+ var destinationComponentId = $('#connection-destination-component-id').val();
+ var destination = d3.select('#id-' + destinationComponentId);
+
+ // get the source/destination data
+ var sourceData = source.datum();
+ var destinationData = destination.datum();
+
+ // add bend points if we're dealing with a self loop
+ var bends = [];
+ if (sourceComponentId === destinationComponentId) {
+ var rightCenter = {
+ x: sourceData.position.x + (sourceData.dimensions.width),
+ y: sourceData.position.y + (sourceData.dimensions.height / 2)
+ };
+
+ var xOffset = nfConnection.config.selfLoopXOffset;
+ var yOffset = nfConnection.config.selfLoopYOffset;
+ bends.push({
+ 'x': (rightCenter.x + xOffset),
+ 'y': (rightCenter.y - yOffset)
+ });
+ bends.push({
+ 'x': (rightCenter.x + xOffset),
+ 'y': (rightCenter.y + yOffset)
+ });
+ } else {
+ var existingConnections = [];
+
+ // get all connections for the source component
+ var connectionsForSourceComponent = nfConnection.getComponentConnections(sourceComponentId);
+ $.each(connectionsForSourceComponent, function (_, connectionForSourceComponent) {
+ // get the id for the source/destination component
+ var connectionSourceComponentId = nfCanvasUtils.getConnectionSourceComponentId(connectionForSourceComponent);
+ var connectionDestinationComponentId = nfCanvasUtils.getConnectionDestinationComponentId(connectionForSourceComponent);
+
+ // if the connection is between these same components, consider it for collisions
+ if ((connectionSourceComponentId === sourceComponentId && connectionDestinationComponentId === destinationComponentId) ||
+ (connectionDestinationComponentId === sourceComponentId && connectionSourceComponentId === destinationComponentId)) {
+
+ // record all connections between these two components in question
+ existingConnections.push(connectionForSourceComponent);
+ }
+ });
+
+ // if there are existing connections between these components, ensure the new connection won't collide
+ if (existingConnections.length > 0) {
+ var avoidCollision = false;
+ $.each(existingConnections, function (_, existingConnection) {
+ // only consider multiple connections with no bend points a collision, the existance of
+ // bend points suggests that the user has placed the connection into a desired location
+ if (nfCommon.isEmpty(existingConnection.bends)) {
+ avoidCollision = true;
+ return false;
+ }
+ });
+
+ // if we need to avoid a collision
+ if (avoidCollision === true) {
+ // determine the middle of the source/destination components
+ var sourceMiddle = [sourceData.position.x + (sourceData.dimensions.width / 2), sourceData.position.y + (sourceData.dimensions.height / 2)];
+ var destinationMiddle = [destinationData.position.x + (destinationData.dimensions.width / 2), destinationData.position.y + (destinationData.dimensions.height / 2)];
+
+ // detect if the line is more horizontal or vertical
+ var slope = ((sourceMiddle[1] - destinationMiddle[1]) / (sourceMiddle[0] - destinationMiddle[0]));
+ var isMoreHorizontal = slope <= 1 && slope >= -1;
+
+ // determines if the specified coordinate collides with another connection
+ var collides = function (x, y) {
+ var collides = false;
+ $.each(existingConnections, function (_, existingConnection) {
+ if (!nfCommon.isEmpty(existingConnection.bends)) {
+ if (isMoreHorizontal) {
+ // horizontal lines are adjusted in the y space
+ if (existingConnection.bends[0].y === y) {
+ collides = true;
+ return false;
+ }
+ } else {
+ // vertical lines are adjusted in the x space
+ if (existingConnection.bends[0].x === x) {
+ collides = true;
+ return false;
+ }
+ }
+ }
+ });
+ return collides;
+ };
+
+ // find the mid point on the connection
+ var xCandidate = (sourceMiddle[0] + destinationMiddle[0]) / 2;
+ var yCandidate = (sourceMiddle[1] + destinationMiddle[1]) / 2;
+
+ // attempt to position this connection so it doesn't collide
+ var xStep = isMoreHorizontal ? 0 : CONNECTION_OFFSET_X_INCREMENT;
+ var yStep = isMoreHorizontal ? CONNECTION_OFFSET_Y_INCREMENT : 0;
+ var positioned = false;
+ while (positioned === false) {
+ // consider above and below, then increment and try again (if necessary)
+ if (collides(xCandidate - xStep, yCandidate - yStep) === false) {
+ bends.push({
+ 'x': (xCandidate - xStep),
+ 'y': (yCandidate - yStep)
+ });
+ positioned = true;
+ } else if (collides(xCandidate + xStep, yCandidate + yStep) === false) {
+ bends.push({
+ 'x': (xCandidate + xStep),
+ 'y': (yCandidate + yStep)
+ });
+ positioned = true;
+ }
+
+ if (isMoreHorizontal) {
+ yStep += CONNECTION_OFFSET_Y_INCREMENT;
+ } else {
+ xStep += CONNECTION_OFFSET_X_INCREMENT;
+ }
+ }
+ }
+ }
+ }
+
+ // determine the source group id
+ var sourceGroupId = $('#connection-source-group-id').val();
+ var destinationGroupId = $('#connection-destination-group-id').val();
+
+ // determine the source and destination types
+ var sourceType = nfCanvasUtils.getConnectableTypeForSource(source);
+ var destinationType = nfCanvasUtils.getConnectableTypeForDestination(destination);
+
+ // get the settings
+ var connectionName = $('#connection-name').val();
+ var flowFileExpiration = $('#flow-file-expiration').val();
+ var backPressureObjectThreshold = $('#back-pressure-object-threshold').val();
+ var backPressureDataSizeThreshold = $('#back-pressure-data-size-threshold').val();
+ var prioritizers = $('#prioritizer-selected').sortable('toArray');
+ var loadBalanceStrategy = $('#load-balance-strategy-combo').combo('getSelectedOption').value;
+ var shouldLoadBalance = 'DO_NOT_LOAD_BALANCE' !== loadBalanceStrategy;
+ var loadBalancePartitionAttribute = shouldLoadBalance && 'PARTITION_BY_ATTRIBUTE' === loadBalanceStrategy ? $('#load-balance-partition-attribute').val() : '';
+ var loadBalanceCompression = shouldLoadBalance ? $('#load-balance-compression-combo').combo('getSelectedOption').value : 'DO_NOT_COMPRESS';
+
+ if (validateSettings()) {
+ var connectionEntity = {
+ 'revision': nfClient.getRevision({
+ 'revision': {
+ 'version': 0
+ }
+ }),
+ 'disconnectedNodeAcknowledged': nfStorage.isDisconnectionAcknowledged(),
+ 'component': {
+ 'name': connectionName,
+ 'source': {
+ 'id': sourceId,
+ 'groupId': sourceGroupId,
+ 'type': sourceType
+ },
+ 'destination': {
+ 'id': destinationId,
+ 'groupId': destinationGroupId,
+ 'type': destinationType
+ },
+ 'selectedRelationships': selectedRelationships,
+ 'flowFileExpiration': flowFileExpiration,
+ 'backPressureDataSizeThreshold': backPressureDataSizeThreshold,
+ 'backPressureObjectThreshold': backPressureObjectThreshold,
+ 'bends': bends,
+ 'prioritizers': prioritizers,
+ 'loadBalanceStrategy': loadBalanceStrategy,
+ 'loadBalancePartitionAttribute': loadBalancePartitionAttribute,
+ 'loadBalanceCompression': loadBalanceCompression
+ }
+ };
+
+ // create the new connection
+ $.ajax({
+ type: 'POST',
+ url: config.urls.api + '/process-groups/' + encodeURIComponent(nfCanvasUtils.getGroupId()) + '/connections',
+ data: JSON.stringify(connectionEntity),
+ dataType: 'json',
+ contentType: 'application/json'
+ }).done(function (response) {
+ // add the connection
+ nfGraph.add({
+ 'connections': [response]
+ }, {
+ 'selectAll': true
+ });
+
+ // reload the connections source/destination components
+ nfCanvasUtils.reloadConnectionSourceAndDestination(sourceComponentId, destinationComponentId);
+
+ // update component visibility
+ nfGraph.updateVisibility();
+
+ // update the birdseye
+ nfBirdseye.refresh();
+ }).fail(function (xhr, status, error) {
+ // handle the error
+ nfErrorHandler.handleAjaxError(xhr, status, error);
+ });
+ }
+ };
+
+ /**
+ * Updates an existing connection.
+ *
+ * @argument {array} selectedRelationships The selected relationships
+ */
+ var updateConnection = function (selectedRelationships) {
+ // get the connection details
+ var connectionId = $('#connection-id').text();
+ var connectionUri = $('#connection-uri').val();
+
+ // get the source details
+ var sourceComponentId = $('#connection-source-component-id').val();
+
+ // get the destination details
+ var destinationComponentId = $('#connection-destination-component-id').val();
+ var destination = d3.select('#id-' + destinationComponentId);
+ var destinationType = nfCanvasUtils.getConnectableTypeForDestination(destination);
+
+ // get the destination details
+ var destinationId = $('#connection-destination-id').val();
+ var destinationGroupId = $('#connection-destination-group-id').val();
+
+ // get the settings
+ var connectionName = $('#connection-name').val();
+ var flowFileExpiration = $('#flow-file-expiration').val();
+ var backPressureObjectThreshold = $('#back-pressure-object-threshold').val();
+ var backPressureDataSizeThreshold = $('#back-pressure-data-size-threshold').val();
+ var prioritizers = $('#prioritizer-selected').sortable('toArray');
+ var loadBalanceStrategy = $('#load-balance-strategy-combo').combo('getSelectedOption').value;
+ var shouldLoadBalance = 'DO_NOT_LOAD_BALANCE' !== loadBalanceStrategy;
+ var loadBalancePartitionAttribute = shouldLoadBalance && 'PARTITION_BY_ATTRIBUTE' === loadBalanceStrategy ? $('#load-balance-partition-attribute').val() : '';
+ var loadBalanceCompression = shouldLoadBalance ? $('#load-balance-compression-combo').combo('getSelectedOption').value : 'DO_NOT_COMPRESS';
+
+ if (validateSettings()) {
+ var d = nfConnection.get(connectionId);
+ var connectionEntity = {
+ 'revision': nfClient.getRevision(d),
+ 'disconnectedNodeAcknowledged': nfStorage.isDisconnectionAcknowledged(),
+ 'component': {
+ 'id': connectionId,
+ 'name': connectionName,
+ 'destination': {
+ 'id': destinationId,
+ 'groupId': destinationGroupId,
+ 'type': destinationType
+ },
+ 'selectedRelationships': selectedRelationships,
+ 'flowFileExpiration': flowFileExpiration,
+ 'backPressureDataSizeThreshold': backPressureDataSizeThreshold,
+ 'backPressureObjectThreshold': backPressureObjectThreshold,
+ 'prioritizers': prioritizers,
+ 'loadBalanceStrategy': loadBalanceStrategy,
+ 'loadBalancePartitionAttribute': loadBalancePartitionAttribute,
+ 'loadBalanceCompression': loadBalanceCompression
+ }
+ };
+
+ // update the connection
+ return $.ajax({
+ type: 'PUT',
+ url: connectionUri,
+ data: JSON.stringify(connectionEntity),
+ dataType: 'json',
+ contentType: 'application/json'
+ }).done(function (response) {
+ // update this connection
+ nfConnection.set(response);
+
+ // reload the connections source/destination components
+ nfCanvasUtils.reloadConnectionSourceAndDestination(sourceComponentId, destinationComponentId);
+ }).fail(function (xhr, status, error) {
+ if (xhr.status === 400 || xhr.status === 404 || xhr.status === 409) {
+ nfDialog.showOkDialog({
+ headerText: 'Connection Configuration',
+ dialogContent: nfCommon.escapeHtml(xhr.responseText),
+ });
+ } else {
+ nfErrorHandler.handleAjaxError(xhr, status, error);
+ }
+ });
+ } else {
+ return $.Deferred(function (deferred) {
+ deferred.reject();
+ }).promise();
+ }
+ };
+
+ /**
+ * Returns an array of selected relationship names.
+ */
+ var getSelectedRelationships = function () {
+ // get all available relationships
+ var availableRelationships = $('#relationship-names');
+ var selectedRelationships = [];
+
+ // go through each relationship to determine which are selected
+ $.each(availableRelationships.children(), function (i, relationshipElement) {
+ var relationship = $(relationshipElement);
+
+ // get each relationship and its corresponding checkbox
+ var relationshipCheck = relationship.children('div.available-relationship');
+
+ // see if this relationship has been selected
+ if (relationshipCheck.hasClass('checkbox-checked')) {
+ selectedRelationships.push(relationship.children('span.relationship-name-value').text());
+ }
+ });
+
+ return selectedRelationships;
+ };
+
+ /**
+ * Validates the specified settings.
+ */
+ var validateSettings = function () {
+ var errors = [];
+
+ // validate the settings
+ if (nfCommon.isBlank($('#flow-file-expiration').val())) {
+ errors.push('File expiration must be specified');
+ }
+ if (!$.isNumeric($('#back-pressure-object-threshold').val())) {
+ errors.push('Back pressure object threshold must be an integer value');
+ }
+ if (nfCommon.isBlank($('#back-pressure-data-size-threshold').val())) {
+ errors.push('Back pressure data size threshold must be specified');
+ }
+ if ($('#load-balance-strategy-combo').combo('getSelectedOption').value === 'PARTITION_BY_ATTRIBUTE'
+ && nfCommon.isBlank($('#load-balance-partition-attribute').val())) {
+ errors.push('Cannot set Load Balance Strategy to "Partition by attribute" without providing a partitioning "Attribute Name"');
+ }
+
+ if (errors.length > 0) {
+ nfDialog.showOkDialog({
+ headerText: 'Connection Configuration',
+ dialogContent: nfCommon.formatUnorderedList(errors)
+ });
+ return false;
+ } else {
+ return true;
+ }
+ };
+
+ /**
+ * Resets the dialog.
+ */
+ var resetDialog = function () {
+ // reset the prioritizers
+ var selectedList = $('#prioritizer-selected');
+ var availableList = $('#prioritizer-available');
+ selectedList.children().detach().appendTo(availableList);
+
+ // sort the available list
+ var listItems = availableList.children('li').get();
+ listItems.sort(function (a, b) {
+ var compA = $(a).text().toUpperCase();
+ var compB = $(b).text().toUpperCase();
+ return (compA < compB) ? -1 : (compA > compB) ? 1 : 0;
+ });
+
+ // clear the available list and re-insert each list item
+ $.each(listItems, function () {
+ $(this).detach();
+ });
+ $.each(listItems, function () {
+ $(this).appendTo(availableList);
+ });
+
+ // reset the fields
+ $('#connection-name').val('');
+ $('#relationship-names').css('border-width', '0').empty();
+ $('#relationship-names-container').show();
+
+ // clear the id field
+ nfCommon.clearField('connection-id');
+
+ // hide all the connection source panels
+ $('#processor-source').hide();
+ $('#input-port-source').hide();
+ $('#output-port-source').hide();
+ $('#read-only-output-port-source').hide();
+ $('#funnel-source').hide();
+
+ // hide all the connection destination panels
+ $('#processor-destination').hide();
+ $('#input-port-destination').hide();
+ $('#output-port-destination').hide();
+ $('#funnel-destination').hide();
+
+ // clear and destination details
+ $('#connection-source-id').val('');
+ $('#connection-source-component-id').val('');
+ $('#connection-source-group-id').val('');
+
+ // clear any destination details
+ $('#connection-destination-id').val('');
+ $('#connection-destination-component-id').val('');
+ $('#connection-destination-group-id').val('');
+
+ // clear any ports
+ $('#output-port-options').empty();
+ $('#input-port-options').empty();
+
+ // clear load balance settings
+ $('#load-balance-strategy-combo').combo('setSelectedOption', nfCommon.loadBalanceStrategyOptions[0]);
+ $('#load-balance-partition-attribute').val('');
+ $('#load-balance-compression-combo').combo('setSelectedOption', nfCommon.loadBalanceCompressionOptions[0]);
+
+ // see if the temp edge needs to be removed
+ removeTempEdge();
+ };
+
+ var nfConnectionConfiguration = {
+
+ /**
+ * Initialize the connection configuration.
+ *
+ * @param nfBirdseyeRef The nfBirdseye module.
+ * @param nfGraphRef The nfGraph module.
+ */
+ init: function (nfBirdseyeRef, nfGraphRef, defaultBackPressureObjectThresholdRef, defaultBackPressureDataSizeThresholdRef) {
+ nfBirdseye = nfBirdseyeRef;
+ nfGraph = nfGraphRef;
+
+ defaultBackPressureObjectThreshold = defaultBackPressureObjectThresholdRef;
+ defaultBackPressureDataSizeThreshold = defaultBackPressureDataSizeThresholdRef;
+
+ // initially hide the relationship names container
+ $('#relationship-names-container').show();
+
+ // initialize the configure connection dialog
+ $('#connection-configuration').modal({
+ scrollableContentStyle: 'scrollable',
+ headerText: 'Configure Connection',
+ handler: {
+ close: function () {
+ // reset the dialog on close
+ resetDialog();
+ },
+ open: function () {
+ nfCommon.toggleScrollable($('#' + this.find('.tab-container').attr('id') + '-content').get(0));
+ }
+ }
+ });
+
+ // initialize the properties tabs
+ $('#connection-configuration-tabs').tabbs({
+ tabStyle: 'tab',
+ selectedTabStyle: 'selected-tab',
+ scrollableTabContentStyle: 'scrollable',
+ tabs: [{
+ name: 'Details',
+ tabContentId: 'connection-details-tab-content'
+ }, {
+ name: 'Settings',
+ tabContentId: 'connection-settings-tab-content'
+ }]
+ });
+
+ // initialize the load balance strategy combo
+ $('#load-balance-strategy-combo').combo({
+ options: nfCommon.loadBalanceStrategyOptions,
+ select: function (selectedOption) {
+ // Show the appropriate configurations
+ if (selectedOption.value === 'PARTITION_BY_ATTRIBUTE') {
+ $('#load-balance-partition-attribute-setting-separator').show();
+ $('#load-balance-partition-attribute-setting').show();
+ } else {
+ $('#load-balance-partition-attribute-setting-separator').hide();
+ $('#load-balance-partition-attribute-setting').hide();
+ }
+ if (selectedOption.value === 'DO_NOT_LOAD_BALANCE') {
+ $('#load-balance-compression-setting').hide();
+ } else {
+ $('#load-balance-compression-setting').show();
+ }
+ }
+ });
+
+
+ // initialize the load balance compression combo
+ $('#load-balance-compression-combo').combo({
+ options: nfCommon.loadBalanceCompressionOptions
+ });
+
+ // load the processor prioritizers
+ $.ajax({
+ type: 'GET',
+ url: config.urls.prioritizers,
+ dataType: 'json'
+ }).done(function (response) {
+ // create an element for each available prioritizer
+ $.each(response.prioritizerTypes, function (i, documentedType) {
+ nfConnectionConfiguration.addAvailablePrioritizer('#prioritizer-available', documentedType);
+ });
+
+ // make the prioritizer containers sortable
+ $('#prioritizer-available, #prioritizer-selected').sortable({
+ containment: $('#connection-settings-tab-content').find('.settings-right'),
+ connectWith: 'ul',
+ placeholder: 'ui-state-highlight',
+ scroll: true,
+ opacity: 0.6
+ });
+ $('#prioritizer-available, #prioritizer-selected').disableSelection();
+ }).fail(nfErrorHandler.handleAjaxError);
+ },
+
+ /**
+ * Adds the specified prioritizer to the specified container.
+ *
+ * @argument {string} prioritizerContainer The dom Id of the prioritizer container
+ * @argument {object} prioritizerType The type of prioritizer
+ */
+ addAvailablePrioritizer: function (prioritizerContainer, prioritizerType) {
+ var type = prioritizerType.type;
+ var name = nfCommon.substringAfterLast(type, '.');
+
+ // add the prioritizers to the available list
+ var prioritizerList = $(prioritizerContainer);
+ var prioritizer = $('<li></li>').append($('<span style="float: left;"></span>').text(name)).attr('id', type).addClass('ui-state-default').appendTo(prioritizerList);
+
+ // add the description if applicable
+ if (nfCommon.isDefinedAndNotNull(prioritizerType.description)) {
+ $('<div class="fa fa-question-circle"></div>').appendTo(prioritizer).qtip($.extend({
+ content: nfCommon.escapeHtml(prioritizerType.description)
+ }, nfCommon.config.tooltipConfig));
+ }
+ },
+
+ /**
+ * Shows the dialog for creating a new connection.
+ *
+ * @argument {string} sourceId The source id
+ * @argument {string} destinationId The destination id
+ */
+ createConnection: function (sourceId, destinationId) {
+ // select the source and destination
+ var source = d3.select('#id-' + sourceId);
+ var destination = d3.select('#id-' + destinationId);
+
+ if (source.empty() || destination.empty()) {
+ return;
+ }
+
+ // initialize the connection dialog
+ $.when(initializeSourceNewConnectionDialog(source), initializeDestinationNewConnectionDialog(destination)).done(function () {
+
+ if (nfCanvasUtils.isProcessor(source) || nfCanvasUtils.isProcessor(destination)) {
+ addDialogRelationshipsChangeListener();
+
+ // if there is a single relationship auto select
+ var relationships = $('#relationship-names').children('div');
+ if (relationships.length === 1) {
+ relationships.children('div.available-relationship').removeClass('checkbox-unchecked').addClass('checkbox-checked');
+ }
+
+ // configure the button model
+ $('#connection-configuration').modal('setButtonModel', [{
+ buttonText: 'Add',
+ color: {
+ base: '#728E9B',
+ hover: '#004849',
+ text: '#ffffff'
+ },
+ disabled: function () {
+ // ensure some relationships were selected
+ return getSelectedRelationships().length === 0;
+ },
+ handler: {
+ click: function () {
+ addConnection(getSelectedRelationships());
+
+ // close the dialog
+ $('#connection-configuration').modal('hide');
+ }
+ }
+ },
+ {
+ buttonText: 'Cancel',
+ color: {
+ base: '#E3E8EB',
+ hover: '#C7D2D7',
+ text: '#004849'
+ },
+ handler: {
+ click: function () {
+ $('#connection-configuration').modal('hide');
+ }
+ }
+ }]);
+ } else {
+ // configure the button model
+ $('#connection-configuration').modal('setButtonModel', [{
+ buttonText: 'Add',
+ color: {
+ base: '#728E9B',
+ hover: '#004849',
+ text: '#ffffff'
+ },
+ handler: {
+ click: function () {
+ // add the connection
+ addConnection();
+
+ // close the dialog
+ $('#connection-configuration').modal('hide');
+ }
+ }
+ },
+ {
+ buttonText: 'Cancel',
+ color: {
+ base: '#E3E8EB',
+ hover: '#C7D2D7',
+ text: '#004849'
+ },
+ handler: {
+ click: function () {
+ $('#connection-configuration').modal('hide');
+ }
+ }
+ }]);
+ }
+
+ // set the default values
+ $('#flow-file-expiration').val('0 sec');
+ $('#back-pressure-object-threshold').val(defaultBackPressureObjectThreshold);
+ $('#back-pressure-data-size-threshold').val(defaultBackPressureDataSizeThreshold);
+
+ // select the first tab
+ $('#connection-configuration-tabs').find('li:first').click();
+
+ // configure the header and show the dialog
+ $('#connection-configuration').modal('setHeaderText', 'Create Connection').modal('show');
+
+ // add the ellipsis if necessary
+ $('#connection-configuration div.relationship-name').ellipsis();
+
+ // fill in the connection id
+ nfCommon.populateField('connection-id', null);
+
+ // show the border if necessary
+ var relationshipNames = $('#relationship-names');
+ if (relationshipNames.is(':visible') && relationshipNames.get(0).scrollHeight > Math.round(relationshipNames.innerHeight())) {
+ relationshipNames.css('border-width', '1px');
+ }
+ }).fail(function () {
+ // see if the temp edge needs to be removed
+ removeTempEdge();
+ });
+ },
+
+ /**
+ * Shows the configuration for the specified connection. If a destination is
+ * specified it will be considered a new destination.
+ *
+ * @argument {selection} selection The connection entry
+ * @argument {selection} destination Optional new destination
+ */
+ showConfiguration: function (selection, destination) {
+ return $.Deferred(function (deferred) {
+ var connectionEntry = selection.datum();
+ var connection = connectionEntry.component;
+
+ // identify the source component
+ var sourceComponentId = nfCanvasUtils.getConnectionSourceComponentId(connectionEntry);
+ var source = d3.select('#id-' + sourceComponentId);
+
+ // identify the destination component
+ if (nfCommon.isUndefinedOrNull(destination)) {
+ var destinationComponentId = nfCanvasUtils.getConnectionDestinationComponentId(connectionEntry);
+ destination = d3.select('#id-' + destinationComponentId);
+ }
+
+ // initialize the connection dialog
+ $.when(initializeSourceEditConnectionDialog(source), initializeDestinationEditConnectionDialog(destination, connection.destination)).done(function () {
+ var availableRelationships = connection.availableRelationships;
+ var selectedRelationships = connection.selectedRelationships;
+
+ // Added this block to force add destination relationships to
+ // get blueprint generation working
+ if (nfCanvasUtils.isProcessor(destination)) {
+ if (availableRelationships == undefined) {
+ // When the source is a port, this could be null or
+ // undefined since the backend the attribute doesn't
+ // exist
+ availableRelationships = [];
+ }
+
+ var processorData = destination.datum();
+ $.each(processorData.component.relationships, function (i, relationship) {
+ availableRelationships.push(relationship.name);
+ });
+ }
+
+ // show the available relationship if applicable
+ if (nfCommon.isDefinedAndNotNull(availableRelationships) || nfCommon.isDefinedAndNotNull(selectedRelationships)) {
+ // populate the available connections
+ $.each(availableRelationships, function (i, name) {
+ createRelationshipOption(name);
+ });
+
+ addDialogRelationshipsChangeListener();
+
+ // ensure all selected relationships are present
+ // (may be undefined) and selected
+ $.each(selectedRelationships, function (i, name) {
+ // mark undefined relationships accordingly
+ if ($.inArray(name, availableRelationships) === -1) {
+ var option = createRelationshipOption(name);
+ $(option).children('div.relationship-name').addClass('undefined');
+ }
+
+ // ensure all selected relationships are checked
+ var relationships = $('#relationship-names').children('div');
+ $.each(relationships, function (i, relationship) {
+ var relationshipName = $(relationship).children('span.relationship-name-value');
+ if (relationshipName.text() === name) {
+ $(relationship).children('div.available-relationship').removeClass('checkbox-unchecked').addClass('checkbox-checked');
+ }
+ });
+ });
+ }
+
+ // if the source is a process group or remote process group, select the appropriate port if applicable
+ if (nfCanvasUtils.isProcessGroup(source) || nfCanvasUtils.isRemoteProcessGroup(source)) {
+ // populate the connection source details
+ $('#connection-source-id').val(connection.source.id);
+ $('#read-only-output-port-name').text(connection.source.name).attr('title', connection.source.name);
+ }
+
+ // if the destination is a process gorup or remote process group, select the appropriate port if applicable
+ if (nfCanvasUtils.isProcessGroup(destination) || nfCanvasUtils.isRemoteProcessGroup(destination)) {
+ var destinationData = destination.datum();
+
+ // when the group ids differ, its a new destination component so we don't want to preselect any port
+ if (connection.destination.groupId === destinationData.id) {
+ $('#input-port-options').combo('setSelectedOption', {
+ value: connection.destination.id
+ });
+ }
+ }
+
+ // set the connection settings
+ $('#connection-name').val(connection.name);
+ $('#flow-file-expiration').val(connection.flowFileExpiration);
+ $('#back-pressure-object-threshold').val(connection.backPressureObjectThreshold);
+ $('#back-pressure-data-size-threshold').val(connection.backPressureDataSizeThreshold);
+
+ // select the load balance combos
+ $('#load-balance-strategy-combo').combo('setSelectedOption', {
+ value: connection.loadBalanceStrategy
+ });
+ $('#load-balance-compression-combo').combo('setSelectedOption', {
+ value: connection.loadBalanceCompression
+ });
+ $('#load-balance-partition-attribute').val(connection.loadBalancePartitionAttribute);
+
+ // format the connection id
+ nfCommon.populateField('connection-id', connection.id);
+
+ // handle each prioritizer
+ $.each(connection.prioritizers, function (i, type) {
+ $('#prioritizer-available').children('li[id="' + type + '"]').detach().appendTo('#prioritizer-selected');
+ });
+
+ // store the connection details
+ $('#connection-uri').val(connectionEntry.uri);
+
+ // configure the button model
+ $('#connection-configuration').modal('setButtonModel', [{
+ buttonText: 'Apply',
+ color: {
+ base: '#728E9B',
+ hover: '#004849',
+ text: '#ffffff'
+ },
+ disabled: function () {
+ // ensure some relationships were selected with a processor as the source
+ if (nfCanvasUtils.isProcessor(source) || nfCanvasUtils.isProcessor(destination)) {
+ return getSelectedRelationships().length === 0;
+ }
+ return false;
+ },
+ handler: {
+ click: function () {
+ // see if we're working with a processor as the source
+ if (nfCanvasUtils.isProcessor(source) || nfCanvasUtils.isProcessor(destination)) {
+ // update the selected relationships
+ updateConnection(getSelectedRelationships()).done(function () {
+ deferred.resolve();
+ }).fail(function () {
+ deferred.reject();
+ });
+ } else {
+ // there are no relationships, but the source wasn't a processor, so update anyway
+ updateConnection(undefined).done(function () {
+ deferred.resolve();
+ }).fail(function () {
+ deferred.reject();
+ });
+ }
+
+ // close the dialog
+ $('#connection-configuration').modal('hide');
+ }
+ }
+ },
+ {
+ buttonText: 'Cancel',
+ color: {
+ base: '#E3E8EB',
+ hover: '#C7D2D7',
+ text: '#004849'
+ },
+ handler: {
+ click: function () {
+ // hide the dialog
+ $('#connection-configuration').modal('hide');
+
+ // reject the deferred
+ deferred.reject();
+ }
+ }
+ }]);
+
+ // show the details dialog
+ $('#connection-configuration').modal('setHeaderText', 'Configure Connection').modal('show');
+
+ // add the ellipsis if necessary
+ $('#connection-configuration div.relationship-name').ellipsis();
+
+ // show the border if necessary
+ var relationshipNames = $('#relationship-names');
+ if (relationshipNames.is(':visible') && relationshipNames.get(0).scrollHeight > Math.round(relationshipNames.innerHeight())) {
+ relationshipNames.css('border-width', '1px');
+ }
+ }).fail(function () {
+ deferred.reject();
+ });
+ }).promise();
+ }
+ };
+
+ return nfConnectionConfiguration;
+}));
diff --git a/mod/designtool/designtool-web/src/main/webapp/js/nf/canvas/nf-flow-version.js b/mod/designtool/designtool-web/src/main/webapp/js/nf/canvas/nf-flow-version.js
new file mode 100644
index 0000000..3c595ca
--- /dev/null
+++ b/mod/designtool/designtool-web/src/main/webapp/js/nf/canvas/nf-flow-version.js
@@ -0,0 +1,1990 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Modifications to the original nifi code for the ONAP project are made
+ * available under the Apache License, Version 2.0
+ */
+
+/* global define, module, require, exports */
+
+/**
+ * Handles versioning.
+ */
+(function (root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ define(['jquery',
+ 'nf.ng.Bridge',
+ 'nf.ErrorHandler',
+ 'nf.Dialog',
+ 'nf.Storage',
+ 'nf.Common',
+ 'nf.Client',
+ 'nf.CanvasUtils',
+ 'nf.ProcessGroup',
+ 'nf.ProcessGroupConfiguration',
+ 'nf.Graph',
+ 'nf.Birdseye'],
+ function ($, nfNgBridge, nfErrorHandler, nfDialog, nfStorage, nfCommon, nfClient, nfCanvasUtils, nfProcessGroup, nfProcessGroupConfiguration, nfGraph, nfBirdseye) {
+ return (nf.FlowVersion = factory($, nfNgBridge, nfErrorHandler, nfDialog, nfStorage, nfCommon, nfClient, nfCanvasUtils, nfProcessGroup, nfProcessGroupConfiguration, nfGraph, nfBirdseye));
+ });
+ } else if (typeof exports === 'object' && typeof module === 'object') {
+ module.exports = (nf.FlowVerison =
+ factory(require('jquery'),
+ require('nf.ng.Bridge'),
+ require('nf.ErrorHandler'),
+ require('nf.Dialog'),
+ require('nf.Storage'),
+ require('nf.Common'),
+ require('nf.Client'),
+ require('nf.CanvasUtils'),
+ require('nf.ProcessGroup'),
+ require('nf.ProcessGroupConfiguration'),
+ require('nf.Graph'),
+ require('nf.Birdseye')));
+ } else {
+ nf.FlowVersion = factory(root.$,
+ root.nf.ng.Bridge,
+ root.nf.ErrorHandler,
+ root.nf.Dialog,
+ root.nf.Storage,
+ root.nf.Common,
+ root.nf.Client,
+ root.nf.CanvasUtils,
+ root.nf.ProcessGroup,
+ root.nf.ProcessGroupConfiguration,
+ root.nf.Graph,
+ root.nf.Birdseye);
+ }
+}(this, function ($, nfNgBridge, nfErrorHandler, nfDialog, nfStorage, nfCommon, nfClient, nfCanvasUtils, nfProcessGroup, nfProcessGroupConfiguration, nfGraph, nfBirdseye) {
+ 'use strict';
+
+ var serverTimeOffset = null;
+
+ var gridOptions = {
+ forceFitColumns: true,
+ enableTextSelectionOnCells: true,
+ enableCellNavigation: true,
+ enableColumnReorder: false,
+ autoEdit: false,
+ multiSelect: false,
+ rowHeight: 24
+ };
+
+ /**
+ * Reset the save flow version dialog.
+ */
+ var resetSaveFlowVersionDialog = function () {
+ $('#save-flow-version-registry-combo').combo('destroy').hide();
+ $('#save-flow-version-bucket-combo').combo('destroy').hide();
+
+ $('#save-flow-version-label').text('');
+
+ $('#save-flow-version-registry').text('').hide();
+ $('#save-flow-version-bucket').text('').hide();
+
+ $('#save-flow-version-name').text('').hide();
+ $('#save-flow-version-description').removeClass('unset blank').text('').hide();
+
+ $('#save-flow-version-name-field').val('').hide();
+ $('#save-flow-version-description-field').val('').hide();
+ $('#save-flow-version-change-comments').val('');
+
+ $('#save-flow-version-process-group-id').removeData('versionControlInformation').removeData('revision').text('');
+ };
+
+ /**
+ * Reset the revert local changes dialog.
+ */
+ var resetRevertLocalChangesDialog = function () {
+ $('#revert-local-changes-process-group-id').text('');
+
+ clearLocalChangesGrid($('#revert-local-changes-table'), $('#revert-local-changes-filter'), $('#displayed-revert-local-changes-entries'), $('#total-revert-local-changes-entries'));
+ };
+
+ /**
+ * Reset the show local changes dialog.
+ */
+ var resetShowLocalChangesDialog = function () {
+ clearLocalChangesGrid($('#show-local-changes-table'), $('#show-local-changes-filter'), $('#displayed-show-local-changes-entries'), $('#total-show-local-changes-entries'));
+ };
+
+ /**
+ * Clears the local changes grid.
+ */
+ var clearLocalChangesGrid = function (localChangesTable, filterInput, displayedLabel, totalLabel) {
+ var localChangesGrid = localChangesTable.data('gridInstance');
+ if (nfCommon.isDefinedAndNotNull(localChangesGrid)) {
+ localChangesGrid.setSelectedRows([]);
+ localChangesGrid.resetActiveCell();
+
+ var localChangesData = localChangesGrid.getData();
+ localChangesData.setItems([]);
+ localChangesData.setFilterArgs({
+ searchString: ''
+ });
+ }
+
+ filterInput.val('');
+
+ displayedLabel.text('0');
+ totalLabel.text('0');
+ };
+
+ /**
+ * Clears the version grid
+ */
+ var clearFlowVersionsGrid = function () {
+ var importFlowVersionGrid = $('#import-flow-version-table').data('gridInstance');
+ if (nfCommon.isDefinedAndNotNull(importFlowVersionGrid)) {
+ importFlowVersionGrid.setSelectedRows([]);
+ importFlowVersionGrid.resetActiveCell();
+
+ var importFlowVersionData = importFlowVersionGrid.getData();
+ importFlowVersionData.setItems([]);
+ }
+ };
+
+ /**
+ * Reset the import flow version dialog.
+ */
+ var resetImportFlowVersionDialog = function () {
+ $('#import-flow-version-dialog').removeData('pt');
+
+ $('#import-flow-version-registry-combo').combo('destroy').hide();
+ $('#import-flow-version-bucket-combo').combo('destroy').hide();
+ $('#import-flow-version-name-combo').combo('destroy').hide();
+
+ $('#import-flow-version-registry').text('').hide();
+ $('#import-flow-version-bucket').text('').hide();
+ $('#import-flow-version-name').text('').hide();
+
+ clearFlowVersionsGrid();
+
+ $('#import-flow-version-process-group-id').removeData('versionControlInformation').removeData('revision').text('');
+
+ $('#import-flow-version-container').hide();
+ $('#import-flow-version-label').text('');
+ };
+
+ /**
+ * Loads the registries into the specified registry combo.
+ *
+ * @param dialog
+ * @param registryCombo
+ * @param bucketCombo
+ * @param flowCombo
+ * @param selectBucket
+ * @param bucketCheck
+ * @returns {deferred}
+ */
+ var loadRegistries = function (dialog, registryCombo, bucketCombo, flowCombo, selectBucket, bucketCheck) {
+ return $.ajax({
+ type: 'GET',
+ url: '../nifi-api/flow/registries',
+ dataType: 'json'
+ }).done(function (registriesResponse) {
+ var registries = [];
+
+ if (nfCommon.isDefinedAndNotNull(registriesResponse.registries) && registriesResponse.registries.length > 0) {
+ registriesResponse.registries.sort(function (a, b) {
+ return a.registry.name > b.registry.name;
+ });
+
+ $.each(registriesResponse.registries, function (_, registryEntity) {
+ var registry = registryEntity.registry;
+ registries.push({
+ text: registry.name,
+ value: registry.id,
+ description: nfCommon.escapeHtml(registry.description)
+ });
+ });
+ } else {
+ registries.push({
+ text: 'No available registries',
+ value: null,
+ optionClass: 'unset',
+ disabled: true
+ });
+ }
+
+ // load the registries
+ registryCombo.combo({
+ options: registries,
+ select: function (selectedOption) {
+ selectRegistry(dialog, selectedOption, bucketCombo, flowCombo, selectBucket, bucketCheck)
+ }
+ });
+ }).fail(nfErrorHandler.handleAjaxError);
+ };
+
+ /**
+ * Loads the buckets for the specified registryIdentifier for the current user.
+ *
+ * @param registryIdentifier
+ * @param bucketCombo
+ * @param flowCombo
+ * @param selectBucket
+ * @param bucketCheck
+ * @returns {*}
+ */
+ var loadBuckets = function (registryIdentifier, bucketCombo, flowCombo, selectBucket, bucketCheck) {
+ return $.ajax({
+ type: 'GET',
+ url: '../nifi-api/flow/registries/' + encodeURIComponent(registryIdentifier) + '/buckets',
+ dataType: 'json'
+ }).done(function (response) {
+ var buckets = [];
+
+ if (nfCommon.isDefinedAndNotNull(response.buckets) && response.buckets.length > 0) {
+ response.buckets.sort(function (a, b) {
+ if (a.permissions.canRead === false && b.permissions.canRead === false) {
+ return 0;
+ } else if (a.permissions.canRead === false) {
+ return -1;
+ } else if (b.permissions.canRead === false) {
+ return 1;
+ }
+
+ return a.bucket.name > b.bucket.name;
+ });
+
+ $.each(response.buckets, function (_, bucketEntity) {
+ if (bucketEntity.permissions.canRead === true) {
+ var bucket = bucketEntity.bucket;
+
+ if (bucketCheck(bucketEntity)) {
+ buckets.push({
+ text: bucket.name,
+ value: bucket.id,
+ description: nfCommon.escapeHtml(bucket.description)
+ });
+ }
+ }
+ });
+ }
+
+ if (buckets.length === 0) {
+ buckets.push({
+ text: 'No available buckets',
+ value: null,
+ optionClass: 'unset',
+ disabled: true
+ });
+
+ if (nfCommon.isDefinedAndNotNull(flowCombo)) {
+ flowCombo.combo('destroy').combo({
+ options: [{
+ text: 'No available flows',
+ value: null,
+ optionClass: 'unset',
+ disabled: true
+ }]
+ });
+ }
+ }
+
+ // load the buckets
+ bucketCombo.combo('destroy').combo({
+ options: buckets,
+ select: selectBucket
+ });
+ }).fail(nfErrorHandler.handleAjaxError);
+ };
+
+ /**
+ * Select handler for the registries combo.
+ *
+ * @param dialog
+ * @param selectedOption
+ * @param bucketCombo
+ * @param flowCombo
+ * @param selectBucket
+ * @param bucketCheck
+ */
+ var selectRegistry = function (dialog, selectedOption, bucketCombo, flowCombo, selectBucket, bucketCheck) {
+ var showNoBucketsAvailable = function () {
+ bucketCombo.combo('destroy').combo({
+ options: [{
+ text: 'No available buckets',
+ value: null,
+ optionClass: 'unset',
+ disabled: true
+ }]
+ });
+
+ if (nfCommon.isDefinedAndNotNull(flowCombo)) {
+ flowCombo.combo('destroy').combo({
+ options: [{
+ text: 'No available flows',
+ value: null,
+ optionClass: 'unset',
+ disabled: true
+ }]
+ });
+ }
+
+ dialog.modal('refreshButtons');
+ };
+
+ if (selectedOption.disabled === true) {
+ showNoBucketsAvailable();
+ } else {
+ bucketCombo.combo('destroy').combo({
+ options: [{
+ text: 'Loading buckets...',
+ value: null,
+ optionClass: 'unset',
+ disabled: true
+ }]
+ });
+
+ if (nfCommon.isDefinedAndNotNull(flowCombo)) {
+ flowCombo.combo('destroy').combo({
+ options: [{
+ text: 'Loading flows...',
+ value: null,
+ optionClass: 'unset',
+ disabled: true
+ }]
+ });
+
+ clearFlowVersionsGrid();
+ }
+
+ loadBuckets(selectedOption.value, bucketCombo, flowCombo, selectBucket, bucketCheck).fail(function () {
+ showNoBucketsAvailable();
+ });
+ }
+ };
+
+ /**
+ * Select handler for the buckets combo.
+ *
+ * @param selectedOption
+ */
+ var selectBucketSaveFlowVersion = function (selectedOption) {
+ $('#save-flow-version-dialog').modal('refreshButtons');
+ };
+
+ /**
+ * Saves a flow version.
+ * @author: Renu
+ * @desc for lines 390-396: when a dflow is committed, then environment dropdown selection is enabled.
+ * If Env is pre-selected and enabled =>submit button is enabled
+ * @returns {*}
+ */
+ var saveFlowVersion = function () {
+ var processGroupId = $('#save-flow-version-process-group-id').text();
+ var processGroupRevision = $('#save-flow-version-process-group-id').data('revision');
+
+ $('#environmentType').prop('disabled', false);
+ console.log("test submit btn..... ");
+
+ if($('#environmentType').val() && !$('#environmentType').prop("disabled")){
+ $('#operate-submit-btn').prop('disabled', false);
+ console.log("button is enabled bcz env is already selected and not disabled");
+ }
+
+ var saveFlowVersionRequest = {
+ processGroupRevision: nfClient.getRevision({
+ revision: {
+ version: processGroupRevision.version
+ }
+ }),
+ 'disconnectedNodeAcknowledged': nfStorage.isDisconnectionAcknowledged()
+ };
+
+ var versionControlInformation = $('#save-flow-version-process-group-id').data('versionControlInformation');
+ if (nfCommon.isDefinedAndNotNull(versionControlInformation)) {
+ saveFlowVersionRequest['versionedFlow'] = {
+ registryId: versionControlInformation.registryId,
+ bucketId: versionControlInformation.bucketId,
+ flowId: versionControlInformation.flowId,
+ comments: $('#save-flow-version-change-comments').val()
+ }
+ } else {
+ var selectedRegistry = $('#save-flow-version-registry-combo').combo('getSelectedOption');
+ var selectedBucket = $('#save-flow-version-bucket-combo').combo('getSelectedOption');
+
+ saveFlowVersionRequest['versionedFlow'] = {
+ registryId: selectedRegistry.value,
+ bucketId: selectedBucket.value,
+ flowName: $('#save-flow-version-name-field').val(),
+ description: $('#save-flow-version-description-field').val(),
+ comments: $('#save-flow-version-change-comments').val()
+ };
+ }
+
+ return $.ajax({
+ type: 'POST',
+ data: JSON.stringify(saveFlowVersionRequest),
+ url: '../nifi-api/versions/process-groups/' + encodeURIComponent(processGroupId),
+ dataType: 'json',
+ contentType: 'application/json'
+ }).fail(nfErrorHandler.handleAjaxError)
+
+
+ };
+
+ /**
+ * Sorts the specified data using the specified sort details.
+ *
+ * @param {object} sortDetails
+ * @param {object} data
+ */
+ var sort = function (sortDetails, data) {
+ // defines a function for sorting
+ var comparer = function (a, b) {
+ var aIsBlank = nfCommon.isBlank(a[sortDetails.columnId]);
+ var bIsBlank = nfCommon.isBlank(b[sortDetails.columnId]);
+
+ if (aIsBlank && bIsBlank) {
+ return 0;
+ } else if (aIsBlank) {
+ return 1;
+ } else if (bIsBlank) {
+ return -1;
+ }
+
+ return a[sortDetails.columnId] === b[sortDetails.columnId] ? 0 : a[sortDetails.columnId] > b[sortDetails.columnId] ? 1 : -1;
+ };
+
+ // perform the sort
+ data.sort(comparer, sortDetails.sortAsc);
+ };
+
+ var initImportFlowVersionTable = function () {
+ var importFlowVersionTable = $('#import-flow-version-table');
+
+ var valueFormatter = function (row, cell, value, columnDef, dataContext) {
+ return nfCommon.escapeHtml(value);
+ };
+
+ var timestampFormatter = function (row, cell, value, columnDef, dataContext) {
+ // get the current user time to properly convert the server time
+ var now = new Date();
+
+ // convert the user offset to millis
+ var userTimeOffset = now.getTimezoneOffset() * 60 * 1000;
+
+ // create the proper date by adjusting by the offsets
+ var date = new Date(dataContext.timestamp + userTimeOffset + serverTimeOffset);
+ return nfCommon.formatDateTime(date);
+ };
+
+ // define the column model for flow versions
+ var importFlowVersionColumns = [
+ {
+ id: 'version',
+ name: 'Version',
+ field: 'version',
+ formatter: valueFormatter,
+ sortable: true,
+ resizable: true,
+ width: 75,
+ maxWidth: 75
+ },
+ {
+ id: 'timestamp',
+ name: 'Created',
+ field: 'timestamp',
+ formatter: timestampFormatter,
+ sortable: true,
+ resizable: true,
+ width: 175,
+ maxWidth: 175
+ },
+ {
+ id: 'changeComments',
+ name: 'Comments',
+ field: 'comments',
+ sortable: true,
+ resizable: true,
+ formatter: valueFormatter
+ }
+ ];
+
+ // initialize the dataview
+ var importFlowVersionData = new Slick.Data.DataView({
+ inlineFilters: false
+ });
+
+ // initialize the sort
+ sort({
+ columnId: 'version',
+ sortAsc: false
+ }, importFlowVersionData);
+
+ // initialize the grid
+ var importFlowVersionGrid = new Slick.Grid(importFlowVersionTable, importFlowVersionData, importFlowVersionColumns, gridOptions);
+ importFlowVersionGrid.setSelectionModel(new Slick.RowSelectionModel());
+ importFlowVersionGrid.registerPlugin(new Slick.AutoTooltips());
+ importFlowVersionGrid.setSortColumn('version', false);
+ importFlowVersionGrid.onSort.subscribe(function (e, args) {
+ sort({
+ columnId: args.sortCol.id,
+ sortAsc: args.sortAsc
+ }, importFlowVersionData);
+ });
+ importFlowVersionGrid.onSelectedRowsChanged.subscribe(function (e, args) {
+ $('#import-flow-version-dialog').modal('refreshButtons');
+ });
+ importFlowVersionGrid.onDblClick.subscribe(function (e, args) {
+ if ($('#import-flow-version-label').is(':visible')) {
+ changeFlowVersion();
+ } else {
+ importFlowVersion().always(function () {
+ $('#import-flow-version-dialog').modal('hide');
+ });
+ }
+ });
+
+ // wire up the dataview to the grid
+ importFlowVersionData.onRowCountChanged.subscribe(function (e, args) {
+ importFlowVersionGrid.updateRowCount();
+ importFlowVersionGrid.render();
+ });
+ importFlowVersionData.onRowsChanged.subscribe(function (e, args) {
+ importFlowVersionGrid.invalidateRows(args.rows);
+ importFlowVersionGrid.render();
+ });
+ importFlowVersionData.syncGridSelection(importFlowVersionGrid, true);
+
+ // hold onto an instance of the grid
+ importFlowVersionTable.data('gridInstance', importFlowVersionGrid);
+ };
+
+ /**
+ * Initializes the specified local changes table.
+ *
+ * @param localChangesTable
+ * @param filterInput
+ * @param displayedLabel
+ * @param totalLabel
+ */
+ var initLocalChangesTable = function (localChangesTable, filterInput, displayedLabel, totalLabel) {
+
+ var getFilterText = function () {
+ return filterInput.val();
+ };
+
+ var applyFilter = function () {
+ // get the dataview
+ var localChangesGrid = localChangesTable.data('gridInstance');
+
+ // ensure the grid has been initialized
+ if (nfCommon.isDefinedAndNotNull(localChangesGrid)) {
+ var localChangesData = localChangesGrid.getData();
+
+ // update the search criteria
+ localChangesData.setFilterArgs({
+ searchString: getFilterText()
+ });
+ localChangesData.refresh();
+ }
+ };
+
+ var filter = function (item, args) {
+ if (args.searchString === '') {
+ return true;
+ }
+
+ try {
+ // perform the row filtering
+ var filterExp = new RegExp(args.searchString, 'i');
+ } catch (e) {
+ // invalid regex
+ return false;
+ }
+
+ // determine if the item matches the filter
+ var matchesId = item['componentId'].search(filterExp) >= 0;
+ var matchesDifferenceType = item['differenceType'].search(filterExp) >= 0;
+ var matchesDifference = item['difference'].search(filterExp) >= 0;
+
+ // conditionally consider the component name
+ var matchesComponentName = false;
+ if (nfCommon.isDefinedAndNotNull(item['componentName'])) {
+ matchesComponentName = item['componentName'].search(filterExp) >= 0;
+ }
+
+ return matchesId || matchesComponentName || matchesDifferenceType || matchesDifference;
+ };
+
+ // initialize the component state filter
+ filterInput.on('keyup', function () {
+ applyFilter();
+ });
+
+ var valueFormatter = function (row, cell, value, columnDef, dataContext) {
+ return nfCommon.escapeHtml(value);
+ };
+
+ var actionsFormatter = function (row, cell, value, columnDef, dataContext) {
+ var markup = '';
+
+ if (dataContext.differenceType !== 'Component Removed' && nfCommon.isDefinedAndNotNull(dataContext.processGroupId)) {
+ markup += '<div class="pointer go-to-component fa fa-long-arrow-right" title="Go To"></div>';
+ }
+
+ return markup;
+ };
+
+ // define the column model for local changes
+ var localChangesColumns = [
+ {
+ id: 'componentName',
+ name: 'Component Name',
+ field: 'componentName',
+ formatter: valueFormatter,
+ sortable: true,
+ resizable: true
+ },
+ {
+ id: 'differenceType',
+ name: 'Change Type',
+ field: 'differenceType',
+ formatter: valueFormatter,
+ sortable: true,
+ resizable: true
+ },
+ {
+ id: 'difference',
+ name: 'Difference',
+ field: 'difference',
+ formatter: valueFormatter,
+ sortable: true,
+ resizable: true
+ },
+ {
+ id: 'actions',
+ name: '&nbsp;',
+ formatter: actionsFormatter,
+ sortable: false,
+ resizable: false,
+ width: 25
+ }
+ ];
+
+ // initialize the dataview
+ var localChangesData = new Slick.Data.DataView({
+ inlineFilters: false
+ });
+ localChangesData.setFilterArgs({
+ searchString: getFilterText()
+ });
+ localChangesData.setFilter(filter);
+
+ // initialize the sort
+ sort({
+ columnId: 'componentName',
+ sortAsc: true
+ }, localChangesData);
+
+ // initialize the grid
+ var localChangesGrid = new Slick.Grid(localChangesTable, localChangesData, localChangesColumns, gridOptions);
+ localChangesGrid.setSelectionModel(new Slick.RowSelectionModel());
+ localChangesGrid.registerPlugin(new Slick.AutoTooltips());
+ localChangesGrid.setSortColumn('componentName', true);
+ localChangesGrid.onSort.subscribe(function (e, args) {
+ sort({
+ columnId: args.sortCol.id,
+ sortAsc: args.sortAsc
+ }, localChangesData);
+ });
+
+ // configure a click listener
+ localChangesGrid.onClick.subscribe(function (e, args) {
+ var target = $(e.target);
+
+ // get the node at this row
+ var componentDifference = localChangesData.getItem(args.row);
+
+ // determine the desired action
+ if (localChangesGrid.getColumns()[args.cell].id === 'actions') {
+ if (target.hasClass('go-to-component')) {
+ if (componentDifference.componentType === 'Controller Service') {
+ nfProcessGroupConfiguration.showConfiguration(componentDifference.processGroupId).done(function () {
+ nfProcessGroupConfiguration.selectControllerService(componentDifference.componentId);
+
+ localChangesTable.closest('.large-dialog').modal('hide');
+ });
+ } else {
+ nfCanvasUtils.showComponent(componentDifference.processGroupId, componentDifference.componentId).done(function () {
+ localChangesTable.closest('.large-dialog').modal('hide');
+ });
+ }
+ }
+ }
+ });
+
+ // wire up the dataview to the grid
+ localChangesData.onRowCountChanged.subscribe(function (e, args) {
+ localChangesGrid.updateRowCount();
+ localChangesGrid.render();
+
+ // update the total number of displayed items
+ displayedLabel.text(nfCommon.formatInteger(args.current));
+ });
+ localChangesData.onRowsChanged.subscribe(function (e, args) {
+ localChangesGrid.invalidateRows(args.rows);
+ localChangesGrid.render();
+ });
+ localChangesData.syncGridSelection(localChangesGrid, true);
+
+ // hold onto an instance of the grid
+ localChangesTable.data('gridInstance', localChangesGrid);
+
+ // initialize the number of display items
+ displayedLabel.text('0');
+ totalLabel.text('0');
+ };
+
+ /**
+ * Shows the import flow version dialog.
+ */
+ var showImportFlowVersionDialog = function () {
+ var pt = $('#new-process-group-dialog').data('pt');
+ $('#import-flow-version-dialog').data('pt', pt);
+
+ // update the registry and bucket visibility
+ var registryCombo = $('#import-flow-version-registry-combo').combo('destroy').combo({
+ options: [{
+ text: 'Loading registries...',
+ value: null,
+ optionClass: 'unset',
+ disabled: true
+ }]
+ }).show();
+ var bucketCombo = $('#import-flow-version-bucket-combo').combo('destroy').combo({
+ options: [{
+ text: 'Loading buckets...',
+ value: null,
+ optionClass: 'unset',
+ disabled: true
+ }]
+ }).show();
+ var flowCombo = $('#import-flow-version-name-combo').combo('destroy').combo({
+ options: [{
+ text: 'Loading flows...',
+ value: null,
+ optionClass: 'unset',
+ disabled: true
+ }]
+ }).show();
+
+ loadRegistries($('#import-flow-version-dialog'), registryCombo, bucketCombo, flowCombo, selectBucketImportVersion, function (bucketEntity) {
+ return true;
+ }).done(function () {
+ // show the import dialog
+ $('#import-flow-version-dialog').modal('setHeaderText', 'Import Version').modal('setButtonModel', [{
+ buttonText: 'Import',
+ color: {
+ base: '#728E9B',
+ hover: '#004849',
+ text: '#ffffff'
+ },
+ disabled: disableImportOrChangeButton,
+ handler: {
+ click: function () {
+ importFlowVersion().always(function () {
+ $('#import-flow-version-dialog').modal('hide');
+ });
+ }
+ }
+ }, {
+ buttonText: 'Cancel',
+ color: {
+ base: '#E3E8EB',
+ hover: '#C7D2D7',
+ text: '#004849'
+ },
+ handler: {
+ click: function () {
+ $(this).modal('hide');
+ }
+ }
+ }]).modal('show');
+
+ // hide the new process group dialog
+ $('#new-process-group-dialog').modal('hide');
+ });
+ };
+
+ /**
+ * Loads the flow versions for the specified registry, bucket, and flow.
+ *
+ * @param registryIdentifier
+ * @param bucketIdentifier
+ * @param flowIdentifier
+ * @returns deferred
+ */
+ var loadFlowVersions = function (registryIdentifier, bucketIdentifier, flowIdentifier) {
+ var importFlowVersionGrid = $('#import-flow-version-table').data('gridInstance');
+ var importFlowVersionData = importFlowVersionGrid.getData();
+
+ // begin the update
+ importFlowVersionData.beginUpdate();
+
+ // remove the current versions
+ importFlowVersionGrid.setSelectedRows([]);
+ importFlowVersionGrid.resetActiveCell();
+ importFlowVersionData.setItems([]);
+
+ return $.ajax({
+ type: 'GET',
+ url: '../nifi-api/flow/registries/' + encodeURIComponent(registryIdentifier) + '/buckets/' + encodeURIComponent(bucketIdentifier) + '/flows/' + encodeURIComponent(flowIdentifier) + '/versions',
+ dataType: 'json'
+ }).done(function (response) {
+ if (nfCommon.isDefinedAndNotNull(response.versionedFlowSnapshotMetadataSet) && response.versionedFlowSnapshotMetadataSet.length > 0) {
+ $.each(response.versionedFlowSnapshotMetadataSet, function (_, entity) {
+ importFlowVersionData.addItem($.extend({
+ id: entity.versionedFlowSnapshotMetadata.version
+ }, entity.versionedFlowSnapshotMetadata));
+ });
+ } else {
+ nfDialog.showOkDialog({
+ headerText: 'Flow Versions',
+ dialogContent: 'This flow does not have any versions available.'
+ });
+ }
+ }).fail(nfErrorHandler.handleAjaxError).always(function () {
+ // end the update
+ importFlowVersionData.endUpdate();
+
+ // resort
+ importFlowVersionData.reSort();
+ importFlowVersionGrid.invalidate();
+ });
+ };
+
+ /**
+ * Loads the versioned flows from the specified registry and bucket.
+ *
+ * @param registryIdentifier
+ * @param bucketIdentifier
+ * @param selectFlow
+ * @returns deferred
+ */
+ var loadFlows = function (registryIdentifier, bucketIdentifier, selectFlow) {
+ return $.ajax({
+ type: 'GET',
+ url: '../nifi-api/flow/registries/' + encodeURIComponent(registryIdentifier) + '/buckets/' + encodeURIComponent(bucketIdentifier) + '/flows',
+ dataType: 'json'
+ }).done(function (response) {
+ var versionedFlows = [];
+
+ if (nfCommon.isDefinedAndNotNull(response.versionedFlows) && response.versionedFlows.length > 0) {
+ response.versionedFlows.sort(function (a, b) {
+ return a.versionedFlow.flowName > b.versionedFlow.flowName;
+ });
+
+ $.each(response.versionedFlows, function (_, versionedFlowEntity) {
+ var versionedFlow = versionedFlowEntity.versionedFlow;
+ versionedFlows.push({
+ text: versionedFlow.flowName,
+ value: versionedFlow.flowId,
+ description: nfCommon.escapeHtml(versionedFlow.description)
+ });
+ });
+ } else {
+ versionedFlows.push({
+ text: 'No available flows',
+ value: null,
+ optionClass: 'unset',
+ disabled: true
+ });
+ }
+
+ // load the buckets
+ $('#import-flow-version-name-combo').combo('destroy').combo({
+ options: versionedFlows,
+ select: function (selectedFlow) {
+ if (nfCommon.isDefinedAndNotNull(selectedFlow.value)) {
+ selectFlow(registryIdentifier, bucketIdentifier, selectedFlow.value)
+ } else {
+ var importFlowVersionGrid = $('#import-flow-version-table').data('gridInstance');
+ var importFlowVersionData = importFlowVersionGrid.getData();
+
+ // clear the current values
+ importFlowVersionData.beginUpdate();
+ importFlowVersionData.setItems([]);
+ importFlowVersionData.endUpdate();
+ }
+ }
+ });
+ }).fail(nfErrorHandler.handleAjaxError);
+ };
+
+ /**
+ * Handler when a versioned flow is selected.
+ *
+ * @param registryIdentifier
+ * @param bucketIdentifier
+ * @param flowIdentifier
+ */
+ var selectVersionedFlow = function (registryIdentifier, bucketIdentifier, flowIdentifier) {
+ loadFlowVersions(registryIdentifier, bucketIdentifier, flowIdentifier).done(function () {
+ $('#import-flow-version-dialog').modal('refreshButtons');
+ });
+ };
+
+ /**
+ * Handler when a bucket is selected.
+ *
+ * @param selectedBucket
+ */
+ var selectBucketImportVersion = function (selectedBucket) {
+ // clear the flow versions grid
+ clearFlowVersionsGrid();
+
+ if (nfCommon.isDefinedAndNotNull(selectedBucket.value)) {
+ // mark the flows as loading
+ $('#import-flow-version-name-combo').combo('destroy').combo({
+ options: [{
+ text: 'Loading flows...',
+ value: null,
+ optionClass: 'unset',
+ disabled: true
+ }]
+ });
+
+ var selectedRegistry = $('#import-flow-version-registry-combo').combo('getSelectedOption');
+
+ // load the flows for the currently selected registry and bucket
+ loadFlows(selectedRegistry.value, selectedBucket.value, selectVersionedFlow);
+ } else {
+ // mark no flows available
+ $('#import-flow-version-name-combo').combo('destroy').combo({
+ options: [{
+ text: 'No available flows',
+ value: null,
+ optionClass: 'unset',
+ disabled: true
+ }]
+ });
+ }
+ };
+
+ /**
+ * Imports the selected flow version.
+ */
+ var importFlowVersion = function () {
+ var pt = $('#import-flow-version-dialog').data('pt');
+
+ var selectedRegistry = $('#import-flow-version-registry-combo').combo('getSelectedOption');
+ var selectedBucket = $('#import-flow-version-bucket-combo').combo('getSelectedOption');
+ var selectedFlow = $('#import-flow-version-name-combo').combo('getSelectedOption');
+
+ var importFlowVersionGrid = $('#import-flow-version-table').data('gridInstance');
+ var selectedVersionIndex = importFlowVersionGrid.getSelectedRows();
+ var selectedVersion = importFlowVersionGrid.getDataItem(selectedVersionIndex[0]);
+
+ var processGroupEntity = {
+ 'revision': nfClient.getRevision({
+ 'revision': {
+ 'version': 0
+ }
+ }),
+ 'disconnectedNodeAcknowledged': nfStorage.isDisconnectionAcknowledged(),
+ 'component': {
+ 'position': {
+ 'x': pt.x,
+ 'y': pt.y
+ },
+ 'versionControlInformation': {
+ 'registryId': selectedRegistry.value,
+ 'bucketId': selectedBucket.value,
+ 'flowId': selectedFlow.value,
+ 'version': selectedVersion.version
+ }
+ }
+ };
+
+ return $.ajax({
+ type: 'POST',
+ data: JSON.stringify(processGroupEntity),
+ url: '../nifi-api/process-groups/' + encodeURIComponent(nfCanvasUtils.getGroupId()) + '/process-groups',
+ dataType: 'json',
+ contentType: 'application/json'
+ }).done(function (response) {
+ // add the process group to the graph
+ nfGraph.add({
+ 'processGroups': [response]
+ }, {
+ 'selectAll': true
+ });
+
+ // update component visibility
+ nfGraph.updateVisibility();
+
+ // update the birdseye
+ nfBirdseye.refresh();
+ }).fail(nfErrorHandler.handleAjaxError);
+ };
+
+ /**
+ * Determines whether the import/change button is disabled.
+ *
+ * @returns {boolean}
+ */
+ var disableImportOrChangeButton = function () {
+ var importFlowVersionGrid = $('#import-flow-version-table').data('gridInstance');
+ if (nfCommon.isDefinedAndNotNull(importFlowVersionGrid)) {
+ var selected = importFlowVersionGrid.getSelectedRows();
+
+ // if the version label is visible, this is a change version request so disable when
+ // the version that represents the current version is selected
+ if ($('#import-flow-version-label').is(':visible')) {
+ if (selected.length === 1) {
+ var selectedFlow = importFlowVersionGrid.getDataItem(selected[0]);
+
+ var currentVersion = parseInt($('#import-flow-version-label').text(), 10);
+ return currentVersion === selectedFlow.version;
+ } else {
+ return true;
+ }
+ } else {
+ // if importing, enable when a single row is selecting
+ return selected.length !== 1;
+ }
+ } else {
+ return true;
+ }
+ };
+
+ /**
+ * Changes the flow version for the currently selected Process Group.
+ *
+ * @returns {deferred}
+ */
+ var changeFlowVersion = function () {
+ var changeTimer = null;
+ var changeRequest = null;
+ var cancelled = false;
+
+ var processGroupId = $('#import-flow-version-process-group-id').text();
+ var processGroupRevision = $('#import-flow-version-process-group-id').data('revision');
+ var versionControlInformation = $('#import-flow-version-process-group-id').data('versionControlInformation');
+
+ var importFlowVersionGrid = $('#import-flow-version-table').data('gridInstance');
+ var selectedVersionIndex = importFlowVersionGrid.getSelectedRows();
+ var selectedVersion = importFlowVersionGrid.getDataItem(selectedVersionIndex[0]);
+
+ // update the button model of the change version status dialog
+ $('#change-version-status-dialog').modal('setButtonModel', [{
+ buttonText: 'Stop',
+ color: {
+ base: '#728E9B',
+ hover: '#004849',
+ text: '#ffffff'
+ },
+ handler: {
+ click: function () {
+ cancelled = true;
+
+ $('#change-version-status-dialog').modal('setButtonModel', []);
+
+ // we are waiting for the next poll attempt
+ if (changeTimer !== null) {
+ // cancel it
+ clearTimeout(changeTimer);
+
+ // cancel the change request
+ completeChangeRequest();
+ }
+ }
+ }
+ }]);
+
+ // hide the import dialog immediately
+ $('#import-flow-version-dialog').modal('hide');
+
+ var submitChangeRequest = function () {
+ var changeVersionRequest = {
+ 'processGroupRevision': nfClient.getRevision({
+ 'revision': {
+ 'version': processGroupRevision.version
+ }
+ }),
+ 'disconnectedNodeAcknowledged': nfStorage.isDisconnectionAcknowledged(),
+ 'versionControlInformation': {
+ 'groupId': processGroupId,
+ 'registryId': versionControlInformation.registryId,
+ 'bucketId': versionControlInformation.bucketId,
+ 'flowId': versionControlInformation.flowId,
+ 'version': selectedVersion.version
+ }
+ };
+
+ return $.ajax({
+ type: 'POST',
+ data: JSON.stringify(changeVersionRequest),
+ url: '../nifi-api/versions/update-requests/process-groups/' + encodeURIComponent(processGroupId),
+ dataType: 'json',
+ contentType: 'application/json'
+ }).done(function () {
+ // initialize the progress bar value
+ updateProgress(0);
+
+ // show the progress dialog
+ $('#change-version-status-dialog').modal('show');
+ }).fail(nfErrorHandler.handleAjaxError);
+ };
+
+ var pollChangeRequest = function () {
+ getChangeRequest().done(processChangeResponse);
+ };
+
+ var getChangeRequest = function () {
+ return $.ajax({
+ type: 'GET',
+ url: changeRequest.uri,
+ dataType: 'json'
+ }).fail(completeChangeRequest).fail(nfErrorHandler.handleAjaxError);
+ };
+
+ var completeChangeRequest = function () {
+ if (cancelled === true) {
+ // update the message to indicate successful completion
+ $('#change-version-status-message').text('The change version request has been cancelled.');
+
+ // update the button model
+ $('#change-version-status-dialog').modal('setButtonModel', [{
+ buttonText: 'Close',
+ color: {
+ base: '#728E9B',
+ hover: '#004849',
+ text: '#ffffff'
+ },
+ handler: {
+ click: function () {
+ $(this).modal('hide');
+ }
+ }
+ }]);
+ }
+
+ if (nfCommon.isDefinedAndNotNull(changeRequest)) {
+ $.ajax({
+ type: 'DELETE',
+ url: changeRequest.uri + '?' + $.param({
+ 'disconnectedNodeAcknowledged': nfStorage.isDisconnectionAcknowledged()
+ }),
+ dataType: 'json'
+ }).done(function (response) {
+ changeRequest = response.request;
+
+ // update the component that was changing
+ updateProcessGroup(processGroupId);
+
+ if (nfCommon.isDefinedAndNotNull(changeRequest.failureReason)) {
+ // hide the progress dialog
+ $('#change-version-status-dialog').modal('hide');
+
+ nfDialog.showOkDialog({
+ headerText: 'Change Version',
+ dialogContent: nfCommon.escapeHtml(changeRequest.failureReason)
+ });
+ } else {
+ // update the percent complete
+ updateProgress(changeRequest.percentCompleted);
+
+ // update the message to indicate successful completion
+ $('#change-version-status-message').text('This Process Group version has changed.');
+
+ // update the button model
+ $('#change-version-status-dialog').modal('setButtonModel', [{
+ buttonText: 'Close',
+ color: {
+ base: '#728E9B',
+ hover: '#004849',
+ text: '#ffffff'
+ },
+ handler: {
+ click: function () {
+ $(this).modal('hide');
+ }
+ }
+ }]);
+ }
+ });
+ }
+ };
+
+ var processChangeResponse = function (response) {
+ changeRequest = response.request;
+
+ if (changeRequest.complete === true || cancelled === true) {
+ completeChangeRequest();
+ } else {
+ // update the percent complete
+ updateProgress(changeRequest.percentCompleted);
+
+ // update the status of the listing request
+ $('#change-version-status-message').text(changeRequest.state);
+
+ changeTimer = setTimeout(function () {
+ // clear the timer since we've been invoked
+ changeTimer = null;
+
+ // poll revert request
+ pollChangeRequest();
+ }, 2000);
+ }
+ };
+
+ submitChangeRequest().done(processChangeResponse);
+ };
+
+ /**
+ * Gets the version control information for the specified process group id.
+ *
+ * @param processGroupId
+ * @return {deferred}
+ */
+ var getVersionControlInformation = function (processGroupId) {
+ return $.Deferred(function (deferred) {
+ if (processGroupId === nfCanvasUtils.getGroupId()) {
+ $.ajax({
+ type: 'GET',
+ url: '../nifi-api/versions/process-groups/' + encodeURIComponent(processGroupId),
+ dataType: 'json'
+ }).done(function (response) {
+ deferred.resolve(response);
+ }).fail(function () {
+ deferred.reject();
+ });
+ } else {
+ var processGroup = nfProcessGroup.get(processGroupId);
+ if (processGroup.permissions.canRead === true && processGroup.permissions.canWrite === true) {
+ deferred.resolve({
+ 'processGroupRevision': processGroup.revision,
+ 'versionControlInformation': processGroup.component.versionControlInformation
+ });
+ } else {
+ deferred.reject();
+ }
+ }
+ }).promise();
+ };
+
+ /**
+ * Updates the specified process group with the specified version control information.
+ *
+ * @param processGroupId
+ * @param versionControlInformation
+ */
+ var updateVersionControlInformation = function (processGroupId, versionControlInformation) {
+ // refresh either selected PG or bread crumb to reflect connected/tracking status
+ if (nfCanvasUtils.getGroupId() === processGroupId) {
+ nfNgBridge.injector.get('breadcrumbsCtrl').updateVersionControlInformation(processGroupId, versionControlInformation);
+ nfNgBridge.digest();
+ } else {
+ nfProcessGroup.reload(processGroupId);
+ }
+ };
+
+ /**
+ * Updates the specified process group following an operation that may change it's contents.
+ *
+ * @param processGroupId
+ */
+ var updateProcessGroup = function (processGroupId) {
+ if (nfCanvasUtils.getGroupId() === processGroupId) {
+ // if reverting/changing current PG... reload/refresh this group/canvas
+
+ $.ajax({
+ type: 'GET',
+ url: '../nifi-api/flow/process-groups/' + encodeURIComponent(processGroupId),
+ dataType: 'json'
+ }).done(function (response) {
+ // update the graph components
+ nfGraph.set(response.processGroupFlow.flow);
+
+ // update the component visibility
+ nfGraph.updateVisibility();
+
+ // update the breadcrumbs
+ var breadcrumbsCtrl = nfNgBridge.injector.get('breadcrumbsCtrl');
+ breadcrumbsCtrl.resetBreadcrumbs();
+ breadcrumbsCtrl.generateBreadcrumbs(response.processGroupFlow.breadcrumb);
+
+ // inform Angular app values have changed
+ nfNgBridge.digest();
+ }).fail(nfErrorHandler.handleAjaxError);
+ } else {
+ // if reverting selected PG... reload selected PG to update counts, etc
+ nfProcessGroup.reload(processGroupId);
+ }
+ };
+
+ /**
+ * Updates the progress bar to the specified percent complete.
+ *
+ * @param percentComplete
+ */
+ var updateProgress = function (percentComplete) {
+ // remove existing labels
+ var progressBar = $('#change-version-percent-complete');
+ progressBar.find('div.progress-label').remove();
+ progressBar.find('md-progress-linear').remove();
+
+ // update the progress
+ var label = $('<div class="progress-label"></div>').text(percentComplete + '%');
+ (nfNgBridge.injector.get('$compile')($('<md-progress-linear ng-cloak ng-value="' + percentComplete + '" class="md-hue-2" md-mode="determinate" aria-label="Searching Queue"></md-progress-linear>'))(nfNgBridge.rootScope)).appendTo(progressBar);
+ progressBar.append(label);
+ };
+
+ /**
+ * Shows local changes for the specified process group.
+ *
+ * @param processGroupId
+ * @param localChangesMessage
+ * @param localChangesTable
+ * @param totalLabel
+ */
+ var loadLocalChanges = function (processGroupId, localChangesMessage, localChangesTable, totalLabel) {
+ var localChangesGrid = localChangesTable.data('gridInstance');
+ var localChangesData = localChangesGrid.getData();
+
+ // begin the update
+ localChangesData.beginUpdate();
+
+ // remove the current versions
+ localChangesGrid.setSelectedRows([]);
+ localChangesGrid.resetActiveCell();
+ localChangesData.setItems([]);
+
+ // load the necessary details
+ var loadMessage = getVersionControlInformation(processGroupId).done(function (response) {
+ if (nfCommon.isDefinedAndNotNull(response.versionControlInformation)) {
+ var vci = response.versionControlInformation;
+ localChangesMessage.text('The following changes have been made to ' + vci.flowName + ' (Version ' + vci.version + ').');
+ } else {
+ nfDialog.showOkDialog({
+ headerText: 'Change Version',
+ dialogContent: 'This Process Group is not currently under version control.'
+ });
+ }
+ });
+ var loadChanges = $.ajax({
+ type: 'GET',
+ url: '../nifi-api/process-groups/' + encodeURIComponent(processGroupId) + '/local-modifications',
+ dataType: 'json'
+ }).done(function (response) {
+ if (nfCommon.isDefinedAndNotNull(response.componentDifferences) && response.componentDifferences.length > 0) {
+ var totalDifferences = 0;
+ $.each(response.componentDifferences, function (_, componentDifference) {
+ $.each(componentDifference.differences, function (_, difference) {
+ localChangesData.addItem({
+ id: totalDifferences++,
+ componentId: componentDifference.componentId,
+ componentName: componentDifference.componentName,
+ componentType: componentDifference.componentType,
+ processGroupId: componentDifference.processGroupId,
+ differenceType: difference.differenceType,
+ difference: difference.difference
+ });
+ });
+ });
+
+ // end the update
+ localChangesData.endUpdate();
+
+ // resort
+ localChangesData.reSort();
+ localChangesGrid.invalidate();
+
+ // update the total displayed
+ totalLabel.text(nfCommon.formatInteger(totalDifferences));
+ } else {
+ nfDialog.showOkDialog({
+ headerText: 'Local Changes',
+ dialogContent: 'This Process Group does not have any local changes.'
+ });
+ }
+ }).fail(nfErrorHandler.handleAjaxError);
+
+ return $.when(loadMessage, loadChanges);
+ };
+
+ /**
+ * Revert local changes for the specified process group.
+ *
+ * @param processGroupId
+ */
+ var revertLocalChanges = function (processGroupId) {
+ getVersionControlInformation(processGroupId).done(function (response) {
+ if (nfCommon.isDefinedAndNotNull(response.versionControlInformation)) {
+ var revertTimer = null;
+ var revertRequest = null;
+ var cancelled = false;
+
+ // update the button model of the revert status dialog
+ $('#change-version-status-dialog').modal('setButtonModel', [{
+ buttonText: 'Stop',
+ color: {
+ base: '#728E9B',
+ hover: '#004849',
+ text: '#ffffff'
+ },
+ handler: {
+ click: function () {
+ cancelled = true;
+
+ $('#change-version-status-dialog').modal('setButtonModel', []);
+
+ // we are waiting for the next poll attempt
+ if (revertTimer !== null) {
+ // cancel it
+ clearTimeout(revertTimer);
+
+ // cancel the revert request
+ completeRevertRequest();
+ }
+ }
+ }
+ }]);
+
+ // hide the import dialog immediately
+ $('#import-flow-version-dialog').modal('hide');
+
+ var submitRevertRequest = function () {
+ var revertFlowVersionRequest = {
+ 'processGroupRevision': nfClient.getRevision({
+ 'revision': {
+ 'version': response.processGroupRevision.version
+ }
+ }),
+ 'disconnectedNodeAcknowledged': nfStorage.isDisconnectionAcknowledged(),
+ 'versionControlInformation': response.versionControlInformation
+ };
+
+ return $.ajax({
+ type: 'POST',
+ data: JSON.stringify(revertFlowVersionRequest),
+ url: '../nifi-api/versions/revert-requests/process-groups/' + encodeURIComponent(processGroupId),
+ dataType: 'json',
+ contentType: 'application/json'
+ }).done(function () {
+ // initialize the progress bar value
+ updateProgress(0);
+
+ // show the progress dialog
+ $('#change-version-status-dialog').modal('show');
+ }).fail(nfErrorHandler.handleAjaxError);
+ };
+
+ var pollRevertRequest = function () {
+ getRevertRequest().done(processRevertResponse);
+ };
+
+ var getRevertRequest = function () {
+ return $.ajax({
+ type: 'GET',
+ url: revertRequest.uri,
+ dataType: 'json'
+ }).fail(completeRevertRequest).fail(nfErrorHandler.handleAjaxError);
+ };
+
+ var completeRevertRequest = function () {
+ if (cancelled === true) {
+ // update the message to indicate successful completion
+ $('#change-version-status-message').text('The revert request has been cancelled.');
+
+ // update the button model
+ $('#change-version-status-dialog').modal('setButtonModel', [{
+ buttonText: 'Close',
+ color: {
+ base: '#728E9B',
+ hover: '#004849',
+ text: '#ffffff'
+ },
+ handler: {
+ click: function () {
+ $(this).modal('hide');
+ }
+ }
+ }]);
+ }
+
+ if (nfCommon.isDefinedAndNotNull(revertRequest)) {
+ $.ajax({
+ type: 'DELETE',
+ url: revertRequest.uri + '?' + $.param({
+ 'disconnectedNodeAcknowledged': nfStorage.isDisconnectionAcknowledged()
+ }),
+ dataType: 'json'
+ }).done(function (response) {
+ revertRequest = response.request;
+
+ // update the component that was changing
+ updateProcessGroup(processGroupId);
+
+ if (nfCommon.isDefinedAndNotNull(revertRequest.failureReason)) {
+ // hide the progress dialog
+ $('#change-version-status-dialog').modal('hide');
+
+ nfDialog.showOkDialog({
+ headerText: 'Revert Local Changes',
+ dialogContent: nfCommon.escapeHtml(revertRequest.failureReason)
+ });
+ } else {
+ // update the percent complete
+ updateProgress(revertRequest.percentCompleted);
+
+ // update the message to indicate successful completion
+ $('#change-version-status-message').text('This Process Group version has changed.');
+
+ // update the button model
+ $('#change-version-status-dialog').modal('setButtonModel', [{
+ buttonText: 'Close',
+ color: {
+ base: '#728E9B',
+ hover: '#004849',
+ text: '#ffffff'
+ },
+ handler: {
+ click: function () {
+ $(this).modal('hide');
+ }
+ }
+ }]);
+ }
+ });
+ }
+ };
+
+ var processRevertResponse = function (response) {
+ revertRequest = response.request;
+
+ if (revertRequest.complete === true || cancelled === true) {
+ completeRevertRequest();
+ } else {
+ // update the percent complete
+ updateProgress(revertRequest.percentCompleted);
+
+ // update the status of the revert request
+ $('#change-version-status-message').text(revertRequest.state);
+
+ revertTimer = setTimeout(function () {
+ // clear the timer since we've been invoked
+ revertTimer = null;
+
+ // poll revert request
+ pollRevertRequest();
+ }, 2000);
+ }
+ };
+
+ submitRevertRequest().done(processRevertResponse);
+ } else {
+ nfDialog.showOkDialog({
+ headerText: 'Revert Changes',
+ dialogContent: 'This Process Group is not currently under version control.'
+ });
+ }
+ }).fail(nfErrorHandler.handleAjaxError);
+ };
+
+ return {
+ init: function (timeOffset) {
+ serverTimeOffset = timeOffset;
+
+ // initialize the flow version dialog
+ $('#save-flow-version-dialog').modal({
+ scrollableContentStyle: 'scrollable',
+ headerText: 'Save Flow Version',
+ buttons: [{
+ buttonText: 'Save',
+ color: {
+ base: '#728E9B',
+ hover: '#004849',
+ text: '#ffffff'
+ },
+ disabled: function () {
+ if ($('#save-flow-version-registry-combo').is(':visible')) {
+ var selectedRegistry = $('#save-flow-version-registry-combo').combo('getSelectedOption');
+ var selectedBucket = $('#save-flow-version-bucket-combo').combo('getSelectedOption');
+
+ if (nfCommon.isDefinedAndNotNull(selectedRegistry) && nfCommon.isDefinedAndNotNull(selectedBucket)) {
+ return selectedRegistry.disabled === true || selectedBucket.disabled === true;
+ } else {
+ return true;
+ }
+ } else {
+ return false;
+ }
+ },
+ handler: {
+ click: function () {
+ var processGroupId = $('#save-flow-version-process-group-id').text();
+ saveFlowVersion().done(function (response) {
+ updateVersionControlInformation(processGroupId, response.versionControlInformation);
+ });
+
+ $(this).modal('hide');
+ }
+ }
+ }, {
+ buttonText: 'Cancel',
+ color: {
+ base: '#E3E8EB',
+ hover: '#C7D2D7',
+ text: '#004849'
+ },
+ handler: {
+ click: function () {
+ $(this).modal('hide');
+ }
+ }
+ }],
+ handler: {
+ close: function () {
+ resetSaveFlowVersionDialog();
+ }
+ }
+ });
+
+ // initialize the import flow version dialog
+ $('#import-flow-version-dialog').modal({
+ scrollableContentStyle: 'scrollable',
+ handler: {
+ close: function () {
+ resetImportFlowVersionDialog();
+ }
+ }
+ });
+
+ // configure the drop request status dialog
+ $('#change-version-status-dialog').modal({
+ scrollableContentStyle: 'scrollable',
+ headerText: 'Change Flow Version',
+ handler: {
+ close: function () {
+ // clear the current button model
+ $('#change-version-status-dialog').modal('setButtonModel', []);
+ }
+ }
+ });
+
+ // init the revert local changes dialog
+ $('#revert-local-changes-dialog').modal({
+ scrollableContentStyle: 'scrollable',
+ headerText: 'Revert Local Changes',
+ buttons: [{
+ buttonText: 'Revert',
+ color: {
+ base: '#728E9B',
+ hover: '#004849',
+ text: '#ffffff'
+ },
+ handler: {
+ click: function () {
+ var processGroupId = $('#revert-local-changes-process-group-id').text();
+ revertLocalChanges(processGroupId);
+
+ $(this).modal('hide');
+ }
+ }
+ }, {
+ buttonText: 'Cancel',
+ color: {
+ base: '#E3E8EB',
+ hover: '#C7D2D7',
+ text: '#004849'
+ },
+ handler: {
+ click: function () {
+ $(this).modal('hide');
+ }
+ }
+ }],
+ handler: {
+ close: function () {
+ resetRevertLocalChangesDialog();
+ }
+ }
+ });
+
+ // init the show local changes dialog
+ $('#show-local-changes-dialog').modal({
+ scrollableContentStyle: 'scrollable',
+ headerText: 'Show Local Changes',
+ buttons: [{
+ buttonText: 'Close',
+ color: {
+ base: '#728E9B',
+ hover: '#004849',
+ text: '#ffffff'
+ },
+ handler: {
+ click: function () {
+ $(this).modal('hide');
+ }
+ }
+ }],
+ handler: {
+ close: function () {
+ resetShowLocalChangesDialog();
+ }
+ }
+ });
+
+ // handle the click for the process group import
+ $('#import-process-group-link').on('click', function() {
+ showImportFlowVersionDialog();
+ });
+
+ // initialize the import flow version table
+ initImportFlowVersionTable();
+ initLocalChangesTable($('#revert-local-changes-table'), $('#revert-local-changes-filter'), $('#displayed-revert-local-changes-entries'), $('#total-revert-local-changes-entries'));
+ initLocalChangesTable($('#show-local-changes-table'), $('#show-local-changes-filter'), $('#displayed-show-local-changes-entries'), $('#total-show-local-changes-entries'));
+ },
+
+ /**
+ * Shows the flow version dialog.
+ *
+ * @param processGroupId
+ */
+ showFlowVersionDialog: function (processGroupId) {
+ var focusName = true;
+
+ return $.Deferred(function (deferred) {
+ getVersionControlInformation(processGroupId).done(function (groupVersionControlInformation) {
+ if (nfCommon.isDefinedAndNotNull(groupVersionControlInformation.versionControlInformation)) {
+ var versionControlInformation = groupVersionControlInformation.versionControlInformation;
+
+ // update the registry and bucket visibility
+ $('#save-flow-version-registry').text(versionControlInformation.registryName).show();
+ $('#save-flow-version-bucket').text(versionControlInformation.bucketName).show();
+ $('#save-flow-version-label').text(versionControlInformation.version + 1);
+
+ $('#save-flow-version-name').text(versionControlInformation.flowName).show();
+ nfCommon.populateField('save-flow-version-description', versionControlInformation.flowDescription);
+ $('#save-flow-version-description').show();
+
+ // record the versionControlInformation
+ $('#save-flow-version-process-group-id').data('versionControlInformation', versionControlInformation);
+
+ // reposition the version label
+ $('#save-flow-version-label').css('margin-top', '-15px');
+
+ focusName = false;
+ deferred.resolve();
+ } else {
+ // update the registry and bucket visibility
+ var registryCombo = $('#save-flow-version-registry-combo').combo('destroy').combo({
+ options: [{
+ text: 'Loading registries...',
+ value: null,
+ optionClass: 'unset',
+ disabled: true
+ }]
+ }).show();
+ var bucketCombo = $('#save-flow-version-bucket-combo').combo('destroy').combo({
+ options: [{
+ text: 'Loading buckets...',
+ value: null,
+ optionClass: 'unset',
+ disabled: true
+ }]
+ }).show();
+
+ // set the initial version
+ $('#save-flow-version-label').text(1);
+
+ $('#save-flow-version-name-field').show();
+ $('#save-flow-version-description-field').show();
+
+ // reposition the version label
+ $('#save-flow-version-label').css('margin-top', '0');
+
+ loadRegistries($('#save-flow-version-dialog'), registryCombo, bucketCombo, null, selectBucketSaveFlowVersion, function (bucketEntity) {
+ return bucketEntity.permissions.canWrite === true;
+ }).done(function () {
+ deferred.resolve();
+ }).fail(function () {
+ deferred.reject();
+ });
+ }
+
+ // record the revision
+ $('#save-flow-version-process-group-id').data('revision', groupVersionControlInformation.processGroupRevision).text(processGroupId);
+ }).fail(nfErrorHandler.handleAjaxError);
+ }).done(function () {
+ $('#save-flow-version-dialog').modal('show');
+
+ if (focusName) {
+ $('#save-flow-version-name-field').focus();
+ } else {
+ $('#save-flow-version-change-comments').focus();
+ }
+ }).fail(function () {
+ $('#save-flow-version-dialog').modal('refreshButtons');
+ }).promise();
+ },
+
+ /**
+ * Reverts local changes for the specified Process Group.
+ *
+ * @param processGroupId
+ */
+ revertLocalChanges: function (processGroupId) {
+ loadLocalChanges(processGroupId, $('#revert-local-changes-message'), $('#revert-local-changes-table'), $('#total-revert-local-changes-entries')).done(function () {
+ $('#revert-local-changes-process-group-id').text(processGroupId);
+ $('#revert-local-changes-dialog').modal('show');
+ });
+ },
+
+ /**
+ * Shows local changes for the specified process group.
+ *
+ * @param processGroupId
+ */
+ showLocalChanges: function (processGroupId) {
+ loadLocalChanges(processGroupId, $('#show-local-changes-message'), $('#show-local-changes-table'), $('#total-show-local-changes-entries')).done(function () {
+ $('#show-local-changes-dialog').modal('show');
+ });
+ },
+
+ /**
+ * Shows the change flow version dialog.
+ *
+ * @param processGroupId
+ */
+ showChangeFlowVersionDialog: function (processGroupId) {
+ return $.Deferred(function (deferred) {
+ getVersionControlInformation(processGroupId).done(function (groupVersionControlInformation) {
+ if (nfCommon.isDefinedAndNotNull(groupVersionControlInformation.versionControlInformation)) {
+ var versionControlInformation = groupVersionControlInformation.versionControlInformation;
+
+ // update the registry and bucket visibility
+ $('#import-flow-version-registry').text(versionControlInformation.registryName).show();
+ $('#import-flow-version-bucket').text(versionControlInformation.bucketName).show();
+ $('#import-flow-version-name').text(versionControlInformation.flowName).show();
+
+ // show the current version information
+ $('#import-flow-version-container').show();
+ $('#import-flow-version-label').text(versionControlInformation.version);
+
+ // record the versionControlInformation
+ $('#import-flow-version-process-group-id').data('versionControlInformation', versionControlInformation).data('revision', groupVersionControlInformation.processGroupRevision).text(processGroupId);
+
+ // load the flow versions
+ loadFlowVersions(versionControlInformation.registryId, versionControlInformation.bucketId, versionControlInformation.flowId).done(function () {
+ deferred.resolve();
+ }).fail(function () {
+ nfDialog.showOkDialog({
+ headerText: 'Change Version',
+ dialogContent: 'Unable to load available versions for this Process Group.'
+ });
+
+ deferred.reject();
+ });
+ } else {
+ nfDialog.showOkDialog({
+ headerText: 'Change Version',
+ dialogContent: 'This Process Group is not currently under version control.'
+ });
+
+ deferred.reject();
+ }
+ }).fail(nfErrorHandler.handleAjaxError);
+ }).done(function () {
+ // show the dialog
+ $('#import-flow-version-dialog').modal('setHeaderText', 'Change Version').modal('setButtonModel', [{
+ buttonText: 'Change',
+ color: {
+ base: '#728E9B',
+ hover: '#004849',
+ text: '#ffffff'
+ },
+ disabled: disableImportOrChangeButton,
+ handler: {
+ click: function () {
+ changeFlowVersion();
+ }
+ }
+ }, {
+ buttonText: 'Cancel',
+ color: {
+ base: '#E3E8EB',
+ hover: '#C7D2D7',
+ text: '#004849'
+ },
+ handler: {
+ click: function () {
+ $(this).modal('hide');
+ }
+ }
+ }]).modal('show');
+ }).promise();
+ },
+
+ /**
+ * Stops version control for the specified Process Group.
+ *
+ * @param processGroupId
+ */
+ stopVersionControl: function (processGroupId) {
+ // prompt the user before disconnecting
+ nfDialog.showYesNoDialog({
+ headerText: 'Stop Version Control',
+ dialogContent: 'Are you sure you want to stop version control?',
+ noText: 'Cancel',
+ yesText: 'Disconnect',
+ yesHandler: function () {
+ $.ajax({
+ type: 'GET',
+ url: '../nifi-api/versions/process-groups/' + encodeURIComponent(processGroupId),
+ dataType: 'json'
+ }).done(function (response) {
+ if (nfCommon.isDefinedAndNotNull(response.versionControlInformation)) {
+ var revision = nfClient.getRevision({
+ revision: {
+ version: response.processGroupRevision.version
+ }
+ });
+
+ $.ajax({
+ type: 'DELETE',
+ url: '../nifi-api/versions/process-groups/' + encodeURIComponent(processGroupId) + '?' + $.param($.extend({
+ 'disconnectedNodeAcknowledged': nfStorage.isDisconnectionAcknowledged()
+ }, revision)),
+ dataType: 'json',
+ contentType: 'application/json'
+ }).done(function (response) {
+ updateVersionControlInformation(processGroupId, undefined);
+
+ nfDialog.showOkDialog({
+ headerText: 'Disconnect',
+ dialogContent: 'This Process Group is no longer under version control.'
+ });
+ }).fail(nfErrorHandler.handleAjaxError);
+ } else {
+ nfDialog.showOkDialog({
+ headerText: 'Disconnect',
+ dialogContent: 'This Process Group is not currently under version control.'
+ })
+ }
+ }).fail(nfErrorHandler.handleAjaxError);
+ }
+ });
+ }
+ };
+}));
diff --git a/mod/designtool/designtool-web/src/main/webapp/js/nf/canvas/nf-process-group.js b/mod/designtool/designtool-web/src/main/webapp/js/nf/canvas/nf-process-group.js
new file mode 100644
index 0000000..614472c
--- /dev/null
+++ b/mod/designtool/designtool-web/src/main/webapp/js/nf/canvas/nf-process-group.js
@@ -0,0 +1,1744 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Modifications to the original nifi code for the ONAP project are made
+ * available under the Apache License, Version 2.0
+ */
+
+/* global d3, define, module, require, exports */
+
+(function (root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ define(['jquery',
+ 'd3',
+ 'nf.Connection',
+ 'nf.Common',
+ 'nf.Client',
+ 'nf.CanvasUtils',
+ 'nf.Dialog'],
+ function ($, d3, nfConnection, nfCommon, nfClient, nfCanvasUtils, nfDialog) {
+ return (nf.ProcessGroup = factory($, d3, nfConnection, nfCommon, nfClient, nfCanvasUtils, nfDialog));
+ });
+ } else if (typeof exports === 'object' && typeof module === 'object') {
+ module.exports = (nf.ProcessGroup =
+ factory(require('jquery'),
+ require('d3'),
+ require('nf.Connection'),
+ require('nf.Common'),
+ require('nf.Client'),
+ require('nf.CanvasUtils'),
+ require('nf.Dialog')));
+ } else {
+ nf.ProcessGroup = factory(root.$,
+ root.d3,
+ root.nf.Connection,
+ root.nf.Common,
+ root.nf.Client,
+ root.nf.CanvasUtils,
+ root.nf.Dialog);
+ }
+}
+(this, function ($, d3, nfConnection, nfCommon, nfClient, nfCanvasUtils, nfDialog) {
+ 'use strict';
+
+ var nfConnectable;
+ var nfDraggable;
+ var nfSelectable;
+ var nfContextMenu;
+
+ var PREVIEW_NAME_LENGTH = 30;
+
+ var dimensions = {
+ width: 380,
+ height: 172
+ };
+
+ // ----------------------------
+ // process groups currently on the graph
+ // ----------------------------
+
+ var processGroupMap;
+
+ // -----------------------------------------------------------
+ // cache for components that are added/removed from the canvas
+ // -----------------------------------------------------------
+
+ var removedCache;
+ var addedCache;
+
+ // --------------------
+ // component containers
+ // --------------------
+
+ var processGroupContainer;
+
+ // --------------------------
+ // privately scoped functions
+ // --------------------------
+
+ /**
+ * Determines whether the specified process group is under version control.
+ *
+ * @param d
+ */
+ var isUnderVersionControl = function (d) {
+ return nfCommon.isDefinedAndNotNull(d.versionedFlowState);
+ };
+
+ /**
+ * Selects the process group elements against the current process group map.
+ */
+ var select = function () {
+ return processGroupContainer.selectAll('g.process-group').data(processGroupMap.values(), function (d) {
+ return d.id;
+ });
+ };
+
+
+ /**
+ * Renders the process groups in the specified selection.
+ *
+ * @param {selection} entered The selection of process groups to be rendered
+ * @param {boolean} selected Whether the process group should be selected
+ * @return the entered selection
+ */
+ var renderProcessGroups = function (entered, selected) {
+ if (entered.empty()) {
+ return entered;
+ }
+
+ var processGroup = entered.append('g')
+ .attrs({
+ 'id': function (d) {
+ return 'id-' + d.id;
+ },
+ 'class': 'process-group component'
+ })
+ .classed('selected', selected)
+ .call(nfCanvasUtils.position);
+
+ // ----
+ // body
+ // ----
+
+ // process group border
+ processGroup.append('rect')
+ .attrs({
+ 'class': 'border',
+ 'width': function (d) {
+ return d.dimensions.width;
+ },
+ 'height': function (d) {
+ return d.dimensions.height;
+ },
+ 'fill': 'transparent',
+ 'stroke': 'transparent'
+ });
+
+ // process group body
+ processGroup.append('rect')
+ .attrs({
+ 'class': 'body',
+ 'width': function (d) {
+ return d.dimensions.width;
+ },
+ 'height': function (d) {
+ return d.dimensions.height;
+ },
+ 'filter': 'url(#component-drop-shadow)',
+ 'stroke-width': 0
+ });
+
+ // process group name background
+ processGroup.append('rect')
+ .attrs({
+ 'width': function (d) {
+ return d.dimensions.width;
+ },
+ 'height': 32,
+ 'fill': '#b8c6cd'
+ });
+
+ // process group name
+ processGroup.append('text')
+ .attrs({
+ 'x': 10,
+ 'y': 20,
+ 'width': 300,
+ 'height': 16,
+ 'class': 'process-group-name'
+ });
+
+ // process group name
+ processGroup.append('text')
+ .attrs({
+ 'x': 10,
+ 'y': 21,
+ 'class': 'version-control'
+ });
+
+ console.log(processGroup);
+
+
+ // always support selecting and navigation
+ processGroup.on('dblclick', function (d) {
+ // enter this group on double click
+ nfProcessGroup.enterGroup(d.id);
+ })
+ .call(nfSelectable.activate).call(nfContextMenu.activate);
+
+ // only support dragging, connection, and drag and drop if appropriate
+ processGroup.filter(function (d) {
+ return d.permissions.canWrite && d.permissions.canRead;
+ })
+ .on('mouseover.drop', function (d) {
+ // Using mouseover/out to workaround chrome issue #122746
+
+ // get the target and ensure its not already been marked for drop
+ var target = d3.select(this);
+ if (!target.classed('drop')) {
+ var targetData = target.datum();
+
+ // see if there is a selection being dragged
+ var drag = d3.select('rect.drag-selection');
+ if (!drag.empty()) {
+ // filter the current selection by this group
+ var selection = nfCanvasUtils.getSelection().filter(function (d) {
+ return targetData.id === d.id;
+ });
+
+ // ensure this group isn't in the selection
+ if (selection.empty()) {
+ // mark that we are hovering over a drop area if appropriate
+ target.classed('drop', function () {
+ // get the current selection and ensure its disconnected
+ return nfConnection.isDisconnected(nfCanvasUtils.getSelection());
+ });
+ }
+ }
+ }
+ })
+ .on('mouseout.drop', function (d) {
+ // mark that we are no longer hovering over a drop area unconditionally
+ d3.select(this).classed('drop', false);
+ })
+ .call(nfDraggable.activate)
+ .call(nfConnectable.activate);
+
+ return processGroup;
+ };
+
+ // attempt of space between component count and icon for process group contents
+ var CONTENTS_SPACER = 10;
+ var CONTENTS_VALUE_SPACER = 5;
+
+ /**
+ * Updates the process groups in the specified selection.
+ *
+ * @param {selection} updated The process groups to be updated
+ */
+ var updateProcessGroups = function (updated) {
+ if (updated.empty()) {
+ return;
+ }
+
+ // process group border authorization
+ updated.select('rect.border')
+ .classed('unauthorized', function (d) {
+ return d.permissions.canRead === false;
+ });
+
+ // process group body authorization
+ updated.select('rect.body')
+ .classed('unauthorized', function (d) {
+ return d.permissions.canRead === false;
+ });
+
+ updated.each(function (processGroupData) {
+ var processGroup = d3.select(this);
+ var details = processGroup.select('g.process-group-details');
+
+ // update the component behavior as appropriate
+ nfCanvasUtils.editable(processGroup, nfConnectable, nfDraggable);
+
+ // if this processor is visible, render everything
+ if (processGroup.classed('visible')) {
+ if (details.empty()) {
+ details = processGroup.append('g').attr('class', 'process-group-details');
+
+ // -------------------
+ // contents background
+ // -------------------
+
+ details.append('rect')
+ .attrs({
+ 'x': 0,
+ 'y': 32,
+ 'width': function () {
+ return processGroupData.dimensions.width
+ },
+ 'height': 24,
+ 'fill': '#e3e8eb'
+ });
+
+ details.append('rect')
+ .attrs({
+ 'x': 0,
+ 'y': function () {
+ return processGroupData.dimensions.height - 24;
+ },
+ 'width': function () {
+ return processGroupData.dimensions.width;
+ },
+ 'height': 24,
+ 'fill': '#e3e8eb'
+ });
+
+ // --------
+ // contents
+ // --------
+
+ // transmitting icon
+// details.append('text')
+// .attrs({
+// 'x': 10,
+// 'y': 49,
+// 'class': 'process-group-transmitting process-group-contents-icon',
+// 'font-family': 'FontAwesome'
+// })
+// .text('\uf140')
+// .append("title")
+// .text("Transmitting Remote Process Groups");
+
+
+ // transmitting count
+// details.append('text')
+// .attrs({
+// 'y': 49,
+// 'class': 'process-group-transmitting-count process-group-contents-count'
+// });
+
+ // not transmitting icon
+// details.append('text')
+// .attrs({
+// 'y': 49,
+// 'class': 'process-group-not-transmitting process-group-contents-icon',
+// 'font-family': 'flowfont'
+// })
+// .text('\ue80a')
+// .append("title")
+// .text("Not Transmitting Remote Process Groups");
+
+ // not transmitting count
+// details.append('text')
+// .attrs({
+// 'y': 49,
+// 'class': 'process-group-not-transmitting-count process-group-contents-count'
+// });
+
+ // running icon
+// details.append('text')
+// .attrs({
+// 'y': 49,
+// 'class': 'process-group-running process-group-contents-icon',
+// 'font-family': 'FontAwesome'
+// })
+// .text('\uf04b')
+// .append("title")
+// .text("Running Components");
+
+ // running count
+// details.append('text')
+// .attrs({
+// 'y': 49,
+// 'class': 'process-group-running-count process-group-contents-count'
+// });
+
+ // stopped icon
+// details.append('text')
+// .attrs({
+// 'y': 49,
+// 'class': 'process-group-stopped process-group-contents-icon',
+// 'font-family': 'FontAwesome'
+// })
+// .text('\uf04d')
+// .append("title")
+// .text("Stopped Components");
+
+ // stopped count
+// details.append('text')
+// .attrs({
+// 'y': 49,
+// 'class': 'process-group-stopped-count process-group-contents-count'
+// });
+
+ // invalid icon
+// details.append('text')
+// .attrs({
+// 'y': 49,
+// 'class': 'process-group-invalid process-group-contents-icon',
+// 'font-family': 'FontAwesome'
+// })
+// .text('\uf071')
+// .append("title")
+// .text("Invalid Components");
+
+ // invalid count
+// details.append('text')
+// .attrs({
+// 'y': 49,
+// 'class': 'process-group-invalid-count process-group-contents-count'
+// });
+
+ // disabled icon
+// details.append('text')
+// .attrs({
+// 'y': 49,
+// 'class': 'process-group-disabled process-group-contents-icon',
+// 'font-family': 'flowfont'
+// })
+// .text('\ue802')
+// .append("title")
+// .text("Disabled Components");
+
+ // disabled count
+// details.append('text')
+// .attrs({
+// 'y': 49,
+// 'class': 'process-group-disabled-count process-group-contents-count'
+// });
+
+ // up to date icon
+ details.append('text')
+ .attrs({
+ 'x': 10,
+ 'y': function () {
+ return processGroupData.dimensions.height - 7;
+ },
+ 'class': 'process-group-up-to-date process-group-contents-icon',
+ 'font-family': 'FontAwesome'
+ })
+ .text('\uf00c')
+ .append("title")
+ .text("Up to date Versioned Process Groups");
+
+ // up to date count
+ details.append('text')
+ .attrs({
+ 'y': function () {
+ return processGroupData.dimensions.height - 7;
+ },
+ 'class': 'process-group-up-to-date-count process-group-contents-count'
+ });
+
+ // locally modified icon
+ details.append('text')
+ .attrs({
+ 'y': function () {
+ return processGroupData.dimensions.height - 7;
+ },
+ 'class': 'process-group-locally-modified process-group-contents-icon',
+ 'font-family': 'FontAwesome'
+ })
+ .text('\uf069')
+ .append("title")
+ .text("Locally modified Versioned Process Groups");
+
+ // locally modified count
+ details.append('text')
+ .attrs({
+ 'y': function () {
+ return processGroupData.dimensions.height - 7;
+ },
+ 'class': 'process-group-locally-modified-count process-group-contents-count'
+ });
+
+ // stale icon
+ details.append('text')
+ .attrs({
+ 'y': function () {
+ return processGroupData.dimensions.height - 7;
+ },
+ 'class': 'process-group-stale process-group-contents-icon',
+ 'font-family': 'FontAwesome'
+ })
+ .text('\uf0aa')
+ .append("title")
+ .text("Stale Versioned Process Groups");
+
+ // stale count
+ details.append('text')
+ .attrs({
+ 'y': function () {
+ return processGroupData.dimensions.height - 7;
+ },
+ 'class': 'process-group-stale-count process-group-contents-count'
+ });
+
+ // locally modified and stale icon
+ details.append('text')
+ .attrs({
+ 'y': function () {
+ return processGroupData.dimensions.height - 7;
+ },
+ 'class': 'process-group-locally-modified-and-stale process-group-contents-icon',
+ 'font-family': 'FontAwesome'
+ })
+ .text('\uf06a')
+ .append("title")
+ .text("Locally modified and stale Versioned Process Groups");
+
+ // locally modified and stale count
+ details.append('text')
+ .attrs({
+ 'y': function () {
+ return processGroupData.dimensions.height - 7;
+ },
+ 'class': 'process-group-locally-modified-and-stale-count process-group-contents-count'
+ });
+
+ // sync failure icon
+ details.append('text')
+ .attrs({
+ 'y': function () {
+ return processGroupData.dimensions.height - 7;
+ },
+ 'class': 'process-group-sync-failure process-group-contents-icon',
+ 'font-family': 'FontAwesome'
+ })
+ .text('\uf128')
+ .append("title")
+ .text("Sync failure Versioned Process Groups");
+
+ // sync failure count
+ details.append('text')
+ .attrs({
+ 'y': function () {
+ return processGroupData.dimensions.height - 7;
+ },
+ 'class': 'process-group-sync-failure-count process-group-contents-count'
+ });
+
+ // ----------------
+ // stats background
+ // ----------------
+
+ // queued
+ details.append('rect')
+ .attrs({
+ 'width': function () {
+ return processGroupData.dimensions.width;
+ },
+ 'height': 19,
+ 'x': 0,
+ 'y': 66,
+ 'fill': '#f4f6f7'
+ });
+
+ // border
+ details.append('rect')
+ .attrs({
+ 'width': function () {
+ return processGroupData.dimensions.width;
+ },
+ 'height': 1,
+ 'x': 0,
+ 'y': 84,
+ 'fill': '#c7d2d7'
+ });
+
+ // in
+ details.append('rect')
+ .attrs({
+ 'width': function () {
+ return processGroupData.dimensions.width;
+ },
+ 'height': 19,
+ 'x': 0,
+ 'y': 85,
+ 'fill': '#ffffff'
+ });
+
+ // border
+ details.append('rect')
+ .attrs({
+ 'width': function () {
+ return processGroupData.dimensions.width;
+ },
+ 'height': 1,
+ 'x': 0,
+ 'y': 103,
+ 'fill': '#c7d2d7'
+ });
+
+ // read/write
+ details.append('rect')
+ .attrs({
+ 'width': function () {
+ return processGroupData.dimensions.width;
+ },
+ 'height': 19,
+ 'x': 0,
+ 'y': 104,
+ 'fill': '#f4f6f7'
+ });
+
+ // border
+ details.append('rect')
+ .attrs({
+ 'width': function () {
+ return processGroupData.dimensions.width;
+ },
+ 'height': 1,
+ 'x': 0,
+ 'y': 122,
+ 'fill': '#c7d2d7'
+ });
+
+ // out
+ details.append('rect')
+ .attrs({
+ 'width': function () {
+ return processGroupData.dimensions.width;
+ },
+ 'height': 19,
+ 'x': 0,
+ 'y': 123,
+ 'fill': '#ffffff'
+ });
+
+ // -----
+ // stats
+ // -----
+
+ // stats label container
+ var processGroupStatsLabel = details.append('g')
+ .attrs({
+ 'transform': 'translate(6, 75)'
+ });
+
+ // queued label
+ processGroupStatsLabel.append('text')
+ .attrs({
+ 'width': 73,
+ 'height': 10,
+ 'x': 4,
+ 'y': 5,
+ 'class': 'stats-label'
+ })
+ .text('Queued');
+
+ // in label
+ processGroupStatsLabel.append('text')
+ .attrs({
+ 'width': 73,
+ 'height': 10,
+ 'x': 4,
+ 'y': 24,
+ 'class': 'stats-label'
+ })
+ .text('In');
+
+ // read/write label
+ processGroupStatsLabel.append('text')
+ .attrs({
+ 'width': 73,
+ 'height': 10,
+ 'x': 4,
+ 'y': 42,
+ 'class': 'stats-label'
+ })
+ .text('Read/Write');
+
+ // out label
+ processGroupStatsLabel.append('text')
+ .attrs({
+ 'width': 73,
+ 'height': 10,
+ 'x': 4,
+ 'y': 60,
+ 'class': 'stats-label'
+ })
+ .text('Out');
+
+ // stats value container
+ var processGroupStatsValue = details.append('g')
+ .attrs({
+ 'transform': 'translate(95, 75)'
+ });
+
+ // queued value
+ var queuedText = processGroupStatsValue.append('text')
+ .attrs({
+ 'width': 180,
+ 'height': 10,
+ 'x': 4,
+ 'y': 5,
+ 'class': 'process-group-queued stats-value'
+ });
+
+ // queued count
+ queuedText.append('tspan')
+ .attrs({
+ 'class': 'count'
+ });
+
+ // queued size
+ queuedText.append('tspan')
+ .attrs({
+ 'class': 'size'
+ });
+
+ // in value
+ var inText = processGroupStatsValue.append('text')
+ .attrs({
+ 'width': 180,
+ 'height': 10,
+ 'x': 4,
+ 'y': 24,
+ 'class': 'process-group-in stats-value'
+ });
+
+ // in count
+ inText.append('tspan')
+ .attrs({
+ 'class': 'count'
+ });
+
+ // in size
+ inText.append('tspan')
+ .attrs({
+ 'class': 'size'
+ });
+
+ // in
+ inText.append('tspan')
+ .attrs({
+ 'class': 'ports'
+ });
+
+ // read/write value
+ processGroupStatsValue.append('text')
+ .attrs({
+ 'width': 180,
+ 'height': 10,
+ 'x': 4,
+ 'y': 42,
+ 'class': 'process-group-read-write stats-value'
+ });
+
+ // out value
+ var outText = processGroupStatsValue.append('text')
+ .attrs({
+ 'width': 180,
+ 'height': 10,
+ 'x': 4,
+ 'y': 60,
+ 'class': 'process-group-out stats-value'
+ });
+
+ // out ports
+ outText.append('tspan')
+ .attrs({
+ 'class': 'ports'
+ });
+
+ // out count
+ outText.append('tspan')
+ .attrs({
+ 'class': 'count'
+ });
+
+ // out size
+ outText.append('tspan')
+ .attrs({
+ 'class': 'size'
+ });
+
+ // stats value container
+ var processGroupStatsInfo = details.append('g')
+ .attrs({
+ 'transform': 'translate(335, 75)'
+ });
+
+ // in info
+ processGroupStatsInfo.append('text')
+ .attrs({
+ 'width': 25,
+ 'height': 10,
+ 'x': 4,
+ 'y': 24,
+ 'class': 'stats-info'
+ })
+ .text('5 min');
+
+ // read/write info
+ processGroupStatsInfo.append('text')
+ .attrs({
+ 'width': 25,
+ 'height': 10,
+ 'x': 4,
+ 'y': 42,
+ 'class': 'stats-info'
+ })
+ .text('5 min');
+
+ // out info
+ processGroupStatsInfo.append('text')
+ .attrs({
+ 'width': 25,
+ 'height': 10,
+ 'x': 4,
+ 'y': 60,
+ 'class': 'stats-info'
+ })
+ .text('5 min');
+
+ // --------
+ // comments
+ // --------
+
+ details.append('path')
+ .attrs({
+ 'class': 'component-comments',
+ 'transform': 'translate(' + (processGroupData.dimensions.width - 2) + ', ' + (processGroupData.dimensions.height - 10) + ')',
+ 'd': 'm0,0 l0,8 l-8,0 z'
+ });
+
+ // -------------------
+ // active thread count
+ // -------------------
+
+ // active thread count
+ details.append('text')
+ .attrs({
+ 'class': 'active-thread-count-icon',
+ 'y': 20
+ })
+ .text('\ue83f');
+
+ // active thread icon
+ details.append('text')
+ .attrs({
+ 'class': 'active-thread-count',
+ 'y': 20
+ });
+
+ // ---------
+ // bulletins
+ // ---------
+
+ // bulletin background
+ details.append('rect')
+ .attrs({
+ 'class': 'bulletin-background',
+ 'x': function () {
+ return processGroupData.dimensions.width - 24;
+ },
+ 'y': 32,
+ 'width': 24,
+ 'height': 24
+ });
+
+ // bulletin icon
+ details.append('text')
+ .attrs({
+ 'class': 'bulletin-icon',
+ 'x': function () {
+ return processGroupData.dimensions.width - 17;
+ },
+ 'y': 49
+ })
+ .text('\uf24a');
+ }
+
+ // update transmitting
+ var transmitting = details.select('text.process-group-transmitting')
+ .classed('transmitting', function (d) {
+ return d.permissions.canRead && d.activeRemotePortCount > 0;
+ })
+ .classed('zero', function (d) {
+ return d.permissions.canRead && d.activeRemotePortCount === 0;
+ });
+ var transmittingCount = details.select('text.process-group-transmitting-count')
+ .attr('x', function () {
+ var transmittingCountX = parseInt(transmitting.attr('x'), 10);
+ return transmittingCountX + Math.round(transmitting.node().getComputedTextLength()) + CONTENTS_VALUE_SPACER;
+ })
+ .text(function (d) {
+ return d.activeRemotePortCount;
+ });
+ transmittingCount.append("title").text("Transmitting Remote Process Groups");
+
+ // update not transmitting
+ var notTransmitting = details.select('text.process-group-not-transmitting')
+ .classed('not-transmitting', function (d) {
+ return d.permissions.canRead && d.inactiveRemotePortCount > 0;
+ })
+ .classed('zero', function (d) {
+ return d.permissions.canRead && d.inactiveRemotePortCount === 0;
+ })
+ .attr('x', function () {
+ var transmittingX = parseInt(transmittingCount.attr('x'), 10);
+ return transmittingX + Math.round(transmittingCount.node().getComputedTextLength()) + CONTENTS_SPACER;
+ });
+ var notTransmittingCount = details.select('text.process-group-not-transmitting-count')
+ .attr('x', function () {
+ var notTransmittingCountX = parseInt(notTransmitting.attr('x'), 10);
+ return notTransmittingCountX + Math.round(notTransmitting.node().getComputedTextLength()) + CONTENTS_VALUE_SPACER;
+ })
+ .text(function (d) {
+ return d.inactiveRemotePortCount;
+ });
+ notTransmittingCount.append("title").text("Not transmitting Remote Process Groups")
+
+ // update running
+ var running = details.select('text.process-group-running')
+ .classed('running', function (d) {
+ return d.permissions.canRead && d.component.runningCount > 0;
+ })
+ .classed('zero', function (d) {
+ return d.permissions.canRead && d.component.runningCount === 0;
+ })
+ .attr('x', function () {
+ var notTransmittingX = parseInt(notTransmittingCount.attr('x'), 10);
+ return notTransmittingX + Math.round(notTransmittingCount.node().getComputedTextLength()) + CONTENTS_SPACER;
+ });
+ var runningCount = details.select('text.process-group-running-count')
+ .attr('x', function () {
+ var runningCountX = parseInt(running.attr('x'), 10);
+ return runningCountX + Math.round(running.node().getComputedTextLength()) + CONTENTS_VALUE_SPACER;
+ })
+ .text(function (d) {
+ return d.runningCount;
+ });
+ runningCount.append("title").text("Running Components");
+
+ // update stopped
+ var stopped = details.select('text.process-group-stopped')
+ .classed('stopped', function (d) {
+ return d.permissions.canRead && d.component.stoppedCount > 0;
+ })
+ .classed('zero', function (d) {
+ return d.permissions.canRead && d.component.stoppedCount === 0;
+ })
+ .attr('x', function () {
+ var runningX = parseInt(runningCount.attr('x'), 10);
+ return runningX + Math.round(runningCount.node().getComputedTextLength()) + CONTENTS_SPACER;
+ });
+ var stoppedCount = details.select('text.process-group-stopped-count')
+ .attr('x', function () {
+ var stoppedCountX = parseInt(stopped.attr('x'), 10);
+ return stoppedCountX + Math.round(stopped.node().getComputedTextLength()) + CONTENTS_VALUE_SPACER;
+ })
+ .text(function (d) {
+ return d.stoppedCount;
+ });
+ stoppedCount.append("title").text("Stopped Components");
+
+ // update invalid
+ var invalid = details.select('text.process-group-invalid')
+ .classed('invalid', function (d) {
+ return d.permissions.canRead && d.component.invalidCount > 0;
+ })
+ .classed('zero', function (d) {
+ return d.permissions.canRead && d.component.invalidCount === 0;
+ })
+ .attr('x', function () {
+ var stoppedX = parseInt(stoppedCount.attr('x'), 10);
+ return stoppedX + Math.round(stoppedCount.node().getComputedTextLength()) + CONTENTS_SPACER;
+ });
+ var invalidCount = details.select('text.process-group-invalid-count')
+ .attr('x', function () {
+ var invalidCountX = parseInt(invalid.attr('x'), 10);
+ return invalidCountX + Math.round(invalid.node().getComputedTextLength()) + CONTENTS_VALUE_SPACER;
+ })
+ .text(function (d) {
+ return d.invalidCount;
+ });
+ invalidCount.append("title").text("Invalid Components");
+
+ // update disabled
+ var disabled = details.select('text.process-group-disabled')
+ .classed('disabled', function (d) {
+ return d.permissions.canRead && d.component.disabledCount > 0;
+ })
+ .classed('zero', function (d) {
+ return d.permissions.canRead && d.component.disabledCount === 0;
+ })
+ .attr('x', function () {
+ var invalidX = parseInt(invalidCount.attr('x'), 10);
+ return invalidX + Math.round(invalidCount.node().getComputedTextLength()) + CONTENTS_SPACER;
+ });
+ var disabledCount = details.select('text.process-group-disabled-count')
+ .attr('x', function () {
+ var disabledCountX = parseInt(disabled.attr('x'), 10);
+ return disabledCountX + Math.round(disabled.node().getComputedTextLength()) + CONTENTS_VALUE_SPACER;
+ })
+ .text(function (d) {
+ return d.disabledCount;
+ });
+ disabledCount.append("title").text("Disabled Components");
+
+ // up to date current
+ var upToDate = details.select('text.process-group-up-to-date')
+ .classed('up-to-date', function (d) {
+ return d.permissions.canRead && d.component.upToDateCount > 0;
+ })
+ .classed('zero', function (d) {
+ return d.permissions.canRead && d.component.upToDateCount === 0;
+ });
+ var upToDateCount = details.select('text.process-group-up-to-date-count')
+ .attr('x', function () {
+ var updateToDateCountX = parseInt(upToDate.attr('x'), 10);
+ return updateToDateCountX + Math.round(upToDate.node().getComputedTextLength()) + CONTENTS_VALUE_SPACER;
+ })
+ .text(function (d) {
+ return d.upToDateCount;
+ });
+ upToDateCount.append("title").text("Up to date Versioned Process Groups");
+
+ // update locally modified
+ var locallyModified = details.select('text.process-group-locally-modified')
+ .classed('locally-modified', function (d) {
+ return d.permissions.canRead && d.component.locallyModifiedCount > 0;
+ })
+ .classed('zero', function (d) {
+ return d.permissions.canRead && d.component.locallyModifiedCount === 0;
+ })
+ .attr('x', function () {
+ var upToDateX = parseInt(upToDateCount.attr('x'), 10);
+ return upToDateX + Math.round(upToDateCount.node().getComputedTextLength()) + CONTENTS_SPACER;
+ });
+ var locallyModifiedCount = details.select('text.process-group-locally-modified-count')
+ .attr('x', function () {
+ var locallyModifiedCountX = parseInt(locallyModified.attr('x'), 10);
+ return locallyModifiedCountX + Math.round(locallyModified.node().getComputedTextLength()) + CONTENTS_VALUE_SPACER;
+ })
+ .text(function (d) {
+ return d.locallyModifiedCount;
+ });
+ locallyModifiedCount.append("title").text("Locally modified Versioned Process Groups");
+
+ // update stale
+ var stale = details.select('text.process-group-stale')
+ .classed('stale', function (d) {
+ return d.permissions.canRead && d.component.staleCount > 0;
+ })
+ .classed('zero', function (d) {
+ return d.permissions.canRead && d.component.staleCount === 0;
+ })
+ .attr('x', function () {
+ var locallyModifiedX = parseInt(locallyModifiedCount.attr('x'), 10);
+ return locallyModifiedX + Math.round(locallyModifiedCount.node().getComputedTextLength()) + CONTENTS_SPACER;
+ });
+ var staleCount = details.select('text.process-group-stale-count')
+ .attr('x', function () {
+ var staleCountX = parseInt(stale.attr('x'), 10);
+ return staleCountX + Math.round(stale.node().getComputedTextLength()) + CONTENTS_VALUE_SPACER;
+ })
+ .text(function (d) {
+ return d.staleCount;
+ });
+ staleCount.append("title").text("Stale Versioned Process Groups");
+
+ // update locally modified and stale
+ var locallyModifiedAndStale = details.select('text.process-group-locally-modified-and-stale')
+ .classed('locally-modified-and-stale', function (d) {
+ return d.permissions.canRead && d.component.locallyModifiedAndStaleCount > 0;
+ })
+ .classed('zero', function (d) {
+ return d.permissions.canRead && d.component.locallyModifiedAndStaleCount === 0;
+ })
+ .attr('x', function () {
+ var staleX = parseInt(staleCount.attr('x'), 10);
+ return staleX + Math.round(staleCount.node().getComputedTextLength()) + CONTENTS_SPACER;
+ });
+ var locallyModifiedAndStaleCount = details.select('text.process-group-locally-modified-and-stale-count')
+ .attr('x', function () {
+ var locallyModifiedAndStaleCountX = parseInt(locallyModifiedAndStale.attr('x'), 10);
+ return locallyModifiedAndStaleCountX + Math.round(locallyModifiedAndStale.node().getComputedTextLength()) + CONTENTS_VALUE_SPACER;
+ })
+ .text(function (d) {
+ return d.locallyModifiedAndStaleCount;
+ });
+ locallyModifiedAndStaleCount.append("title").text("Locally modified and stale Versioned Process Groups");
+
+ // update sync failure
+ var syncFailure = details.select('text.process-group-sync-failure')
+ .classed('sync-failure', function (d) {
+ return d.permissions.canRead && d.component.syncFailureCount > 0;
+ })
+ .classed('zero', function (d) {
+ return d.permissions.canRead && d.component.syncFailureCount === 0;
+ })
+ .attr('x', function () {
+ var syncFailureX = parseInt(locallyModifiedAndStaleCount.attr('x'), 10);
+ return syncFailureX + Math.round(locallyModifiedAndStaleCount.node().getComputedTextLength()) + CONTENTS_SPACER - 2;
+ });
+ var syncFailureCount = details.select('text.process-group-sync-failure-count')
+ .attr('x', function () {
+ var syncFailureCountX = parseInt(syncFailure.attr('x'), 10);
+ return syncFailureCountX + Math.round(syncFailure.node().getComputedTextLength()) + CONTENTS_VALUE_SPACER;
+ })
+ .text(function (d) {
+ return d.syncFailureCount;
+ });
+ syncFailureCount.append("title").text("Sync failure Versioned Process Groups");
+
+ /**
+ * update version control information
+ * @author: Renu
+ * @desc for lines 1110-1201: based on state of the process group, environment selection and submit button enable/disable
+ */
+ var versionControl = processGroup.select('text.version-control')
+ .styles({
+ 'visibility': isUnderVersionControl(processGroupData) ? 'visible' : 'hidden',
+ 'fill': function () {
+ if (isUnderVersionControl(processGroupData)) {
+ var vciState = processGroupData.versionedFlowState;
+ if (vciState === 'SYNC_FAILURE') {
+ $('#environmentType').prop('disabled', true);
+ if($('#environmentType').val() && !$('#environmentType').prop('disabled')){
+ $('#operate-submit-btn').prop('disabled', false);
+ }else{$('#operate-submit-btn').prop('disabled', true);}
+
+ return '#666666';
+ } else if (vciState === 'LOCALLY_MODIFIED_AND_STALE') {
+ console.log("locally but stale in style");
+ $('#environmentType').prop('disabled', true);
+ if($('#environmentType').val() && !$('#environmentType').prop('disabled')){
+ $('#operate-submit-btn').prop('disabled', false);
+ }else{$('#operate-submit-btn').prop('disabled', true);}
+
+ return '#BA554A';
+ } else if (vciState === 'STALE') {
+ console.log("stale in style");
+ $('#environmentType').prop('disabled', true);
+ if($('#environmentType').val() && !$('#environmentType').prop('disabled')){
+ $('#operate-submit-btn').prop('disabled', false);
+ }else{$('#operate-submit-btn').prop('disabled', true);}
+ return '#BA554A';
+ } else if (vciState === 'LOCALLY_MODIFIED') {
+ console.log("locally modified in style");
+ $('#environmentType').prop('disabled', true);
+ if($('#environmentType').val() && !$('#environmentType').prop('disabled')){
+ $('#operate-submit-btn').prop('disabled', false);
+ }else{$('#operate-submit-btn').prop('disabled', true);}
+
+ return '#666666';
+ } else {
+ return '#1A9964';
+ $('#environmentType').prop('disabled', false);
+ if($('#environmentType').val() && !$('#environmentType').prop('disabled')){
+ $('#operate-submit-btn').prop('disabled', false);
+ }else{$('#operate-submit-btn').prop('disabled', true);}
+ }
+ } else {
+ $('#environmentType').prop('disabled', true);
+ return '#000';
+ }
+ }
+ })
+ .text(function () {
+ if (isUnderVersionControl(processGroupData)) {
+ var vciState = processGroupData.versionedFlowState;
+ if (vciState === 'SYNC_FAILURE') {
+ $('#environmentType').prop('disabled', true);
+ if($('#environmentType').val() && !$('#environmentType').prop('disabled')){
+ $('#operate-submit-btn').prop('disabled', false);
+ }else{$('#operate-submit-btn').prop('disabled', true);}
+
+ return '\uf128'
+ } else if (vciState === 'LOCALLY_MODIFIED_AND_STALE') {
+ console.log("locally but stale in text");
+ $('#environmentType').prop('disabled', true);
+ if($('#environmentType').val() && !$('#environmentType').prop('disabled')){
+ $('#operate-submit-btn').prop('disabled', false);
+ }else{$('#operate-submit-btn').prop('disabled', true);}
+
+ return '\uf06a';
+ } else if (vciState === 'STALE') {
+ console.log("stale in text");
+ $('#environmentType').prop('disabled', true);
+ if($('#environmentType').val() && !$('#environmentType').prop('disabled')){
+ $('#operate-submit-btn').prop('disabled', false);
+ }else{$('#operate-submit-btn').prop('disabled', true);}
+ return '\uf0aa';
+ } else if (vciState === 'LOCALLY_MODIFIED') {
+ console.log("locally modified in text");
+ $('#environmentType').prop('disabled', true);
+ if($('#environmentType').val() && !$('#environmentType').prop('disabled')){
+ $('#operate-submit-btn').prop('disabled', false);
+ }else{$('#operate-submit-btn').prop('disabled', true);}
+ return '\uf069';
+ } else {
+ return '\uf00c';
+ $('#environmentType').prop('disabled', false);
+ if($('#environmentType').val() && !$('#environmentType').prop('disabled')){
+ $('#operate-submit-btn').prop('disabled', false);
+ }else{$('#operate-submit-btn').prop('disabled', true);}
+ }
+ } else {
+ $('#environmentType').prop('disabled', true);
+ return '';
+ }
+ });
+
+ if (processGroupData.permissions.canRead) {
+ // version control tooltip
+ versionControl.each(function () {
+ // get the tip
+ var tip = d3.select('#version-control-tip-' + processGroupData.id);
+
+ // if there are validation errors generate a tooltip
+ if (isUnderVersionControl(processGroupData)) {
+ // create the tip if necessary
+ if (tip.empty()) {
+ tip = d3.select('#process-group-tooltips').append('div')
+ .attr('id', function () {
+ return 'version-control-tip-' + processGroupData.id;
+ })
+ .attr('class', 'tooltip nifi-tooltip');
+ }
+
+ // update the tip
+ tip.html(function () {
+ var vci = processGroupData.component.versionControlInformation;
+ var versionControlTip = $('<div></div>').text('Tracking to "' + vci.flowName + '" version ' + vci.version + ' in "' + vci.registryName + ' - ' + vci.bucketName + '"');
+ var versionControlStateTip = $('<div></div>').text(nfCommon.getVersionControlTooltip(vci));
+ return $('<div></div>').append(versionControlTip).append('<br/>').append(versionControlStateTip).html();
+ });
+
+ // add the tooltip
+ nfCanvasUtils.canvasTooltip(tip, d3.select(this));
+ } else {
+ // remove the tip if necessary
+ if (!tip.empty()) {
+ tip.remove();
+ }
+ }
+ });
+
+ // update the process group comments
+ processGroup.select('path.component-comments')
+ .style('visibility', nfCommon.isBlank(processGroupData.component.comments) ? 'hidden' : 'visible')
+ .each(function () {
+ // get the tip
+ var tip = d3.select('#comments-tip-' + processGroupData.id);
+
+ // if there are validation errors generate a tooltip
+ if (nfCommon.isBlank(processGroupData.component.comments)) {
+ // remove the tip if necessary
+ if (!tip.empty()) {
+ tip.remove();
+ }
+ } else {
+ // create the tip if necessary
+ if (tip.empty()) {
+ tip = d3.select('#process-group-tooltips').append('div')
+ .attr('id', function () {
+ return 'comments-tip-' + processGroupData.id;
+ })
+ .attr('class', 'tooltip nifi-tooltip');
+ }
+
+ // update the tip
+ tip.text(processGroupData.component.comments);
+
+ // add the tooltip
+ nfCanvasUtils.canvasTooltip(tip, d3.select(this));
+ }
+ });
+
+ // update the process group name
+ processGroup.select('text.process-group-name')
+ .attrs({
+ 'x': function () {
+ if (isUnderVersionControl(processGroupData)) {
+ var versionControlX = parseInt(versionControl.attr('x'), 10);
+ return versionControlX + Math.round(versionControl.node().getComputedTextLength()) + CONTENTS_VALUE_SPACER;
+ } else {
+ return 10;
+ }
+ },
+ 'width': function () {
+ if (isUnderVersionControl(processGroupData)) {
+ var versionControlX = parseInt(versionControl.attr('x'), 10);
+ var processGroupNameX = parseInt(d3.select(this).attr('x'), 10);
+ return 300 - (processGroupNameX - versionControlX);
+ } else {
+ return 300;
+ }
+ }
+ })
+ .each(function (d) {
+ var processGroupName = d3.select(this);
+
+ // reset the process group name to handle any previous state
+ processGroupName.text(null).selectAll('title').remove();
+
+ // apply ellipsis to the process group name as necessary
+ nfCanvasUtils.ellipsis(processGroupName, d.component.name);
+ })
+ .append('title')
+ .text(function (d) {
+ return d.component.name;
+ });
+ } else {
+ // clear the process group comments
+ processGroup.select('path.component-comments').style('visibility', 'hidden');
+
+ // clear the process group name
+ processGroup.select('text.process-group-name')
+ .attrs({
+ 'x': 10,
+ 'width': 316
+ })
+ .text(null);
+
+ // clear tooltips
+ processGroup.call(removeTooltips);
+ }
+
+ // populate the stats
+ processGroup.call(updateProcessGroupStatus);
+ } else {
+ if (processGroupData.permissions.canRead) {
+ // update the process group name
+ processGroup.select('text.process-group-name')
+ .text(function (d) {
+ var name = d.component.name;
+ if (name.length > PREVIEW_NAME_LENGTH) {
+ return name.substring(0, PREVIEW_NAME_LENGTH) + String.fromCharCode(8230);
+ } else {
+ return name;
+ }
+ });
+ } else {
+ // clear the process group name
+ processGroup.select('text.process-group-name').text(null);
+ }
+
+ // remove the tooltips
+ processGroup.call(removeTooltips);
+
+ // remove the details if necessary
+ if (!details.empty()) {
+ details.remove();
+ }
+ }
+ });
+ };
+
+ /**
+ * Updates the process group status.
+ *
+ * @param {selection} updated The process groups to be updated
+ */
+ var updateProcessGroupStatus = function (updated) {
+ if (updated.empty()) {
+ return;
+ }
+
+ // queued count value
+ updated.select('text.process-group-queued tspan.count')
+ .text(function (d) {
+ return nfCommon.substringBeforeFirst(d.status.aggregateSnapshot.queued, ' ');
+ });
+
+ // queued size value
+ updated.select('text.process-group-queued tspan.size')
+ .text(function (d) {
+ return ' ' + nfCommon.substringAfterFirst(d.status.aggregateSnapshot.queued, ' ');
+ });
+
+ // in count value
+ updated.select('text.process-group-in tspan.count')
+ .text(function (d) {
+ return nfCommon.substringBeforeFirst(d.status.aggregateSnapshot.input, ' ');
+ });
+
+ // in size value
+ updated.select('text.process-group-in tspan.size')
+ .text(function (d) {
+ return ' ' + nfCommon.substringAfterFirst(d.status.aggregateSnapshot.input, ' ');
+ });
+
+ // in ports value
+ updated.select('text.process-group-in tspan.ports')
+ .text(function (d) {
+ return ' ' + String.fromCharCode(8594) + ' ' + d.inputPortCount;
+ });
+
+ // read/write value
+ updated.select('text.process-group-read-write')
+ .text(function (d) {
+ return d.status.aggregateSnapshot.read + ' / ' + d.status.aggregateSnapshot.written;
+ });
+
+ // out ports value
+ updated.select('text.process-group-out tspan.ports')
+ .text(function (d) {
+ return d.outputPortCount + ' ' + String.fromCharCode(8594) + ' ';
+ });
+
+ // out count value
+ updated.select('text.process-group-out tspan.count')
+ .text(function (d) {
+ return nfCommon.substringBeforeFirst(d.status.aggregateSnapshot.output, ' ');
+ });
+
+ // out size value
+ updated.select('text.process-group-out tspan.size')
+ .text(function (d) {
+ return ' ' + nfCommon.substringAfterFirst(d.status.aggregateSnapshot.output, ' ');
+ });
+
+ updated.each(function (d) {
+ var processGroup = d3.select(this);
+ var offset = 0;
+
+ // -------------------
+ // active thread count
+ // -------------------
+
+ nfCanvasUtils.activeThreadCount(processGroup, d, function (off) {
+ offset = off;
+ });
+
+ // ---------
+ // bulletins
+ // ---------
+
+ processGroup.select('rect.bulletin-background').classed('has-bulletins', function () {
+ return !nfCommon.isEmpty(d.status.aggregateSnapshot.bulletins);
+ });
+
+ nfCanvasUtils.bulletins(processGroup, d, function () {
+ return d3.select('#process-group-tooltips');
+ }, offset);
+ });
+ };
+
+ /**
+ * Removes the process groups in the specified selection.
+ *
+ * @param {selection} removed The process groups to be removed
+ */
+ var removeProcessGroups = function (removed) {
+ if (removed.empty()) {
+ return;
+ }
+
+ removed.call(removeTooltips).remove();
+ };
+
+ /**
+ * Removes the tooltips for the process groups in the specified selection.
+ *
+ * @param {selection} removed
+ */
+ var removeTooltips = function (removed) {
+ removed.each(function (d) {
+ // remove any associated tooltips
+ $('#bulletin-tip-' + d.id).remove();
+ $('#version-control-tip-' + d.id).remove();
+ $('#comments-tip-' + d.id).remove();
+ });
+ };
+
+ var nfProcessGroup = {
+ /**
+ * Initializes of the Process Group handler.
+ *
+ * @param nfConnectableRef The nfConnectable module.
+ * @param nfDraggableRef The nfDraggable module.
+ * @param nfSelectableRef The nfSelectable module.
+ * @param nfContextMenuRef The nfContextMenu module.
+ */
+ init: function (nfConnectableRef, nfDraggableRef, nfSelectableRef, nfContextMenuRef) {
+ nfConnectable = nfConnectableRef;
+ nfDraggable = nfDraggableRef;
+ nfSelectable = nfSelectableRef;
+ nfContextMenu = nfContextMenuRef;
+
+ processGroupMap = d3.map();
+ removedCache = d3.map();
+ addedCache = d3.map();
+
+ // create the process group container
+ processGroupContainer = d3.select('#canvas').append('g')
+ .attrs({
+ 'pointer-events': 'all',
+ 'class': 'process-groups'
+ });
+ },
+
+ /**
+ * Adds the specified process group entity.
+ *
+ * @param processGroupEntities The process group
+ * @param options Configuration options
+ */
+ add: function (processGroupEntities, options) {
+ var selectAll = false;
+ if (nfCommon.isDefinedAndNotNull(options)) {
+ selectAll = nfCommon.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
+ }
+
+ // get the current time
+ var now = new Date().getTime();
+
+ var add = function (processGroupEntity) {
+ addedCache.set(processGroupEntity.id, now);
+
+ // add the process group
+ processGroupMap.set(processGroupEntity.id, $.extend({
+ type: 'ProcessGroup',
+ dimensions: dimensions
+ }, processGroupEntity));
+ };
+
+ // determine how to handle the specified process groups
+ if ($.isArray(processGroupEntities)) {
+ $.each(processGroupEntities, function (_, processGroupEntity) {
+ add(processGroupEntity);
+ });
+ } else if (nfCommon.isDefinedAndNotNull(processGroupEntities)) {
+ add(processGroupEntities);
+ }
+
+ // select
+ var selection = select();
+
+ // enter
+ var entered = renderProcessGroups(selection.enter(), selectAll);
+
+ // update
+ updateProcessGroups(selection.merge(entered));
+ },
+
+ /**
+ * Populates the graph with the specified process groups.
+ *
+ * @argument {object | array} processGroupEntities The process groups to add
+ * @argument {object} options Configuration options
+ */
+ set: function (processGroupEntities, options) {
+ var selectAll = false;
+ var transition = false;
+ var overrideRevisionCheck = false;
+ if (nfCommon.isDefinedAndNotNull(options)) {
+ selectAll = nfCommon.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
+ transition = nfCommon.isDefinedAndNotNull(options.transition) ? options.transition : transition;
+ overrideRevisionCheck = nfCommon.isDefinedAndNotNull(options.overrideRevisionCheck) ? options.overrideRevisionCheck : overrideRevisionCheck;
+ }
+
+ var set = function (proposedProcessGroupEntity) {
+ var currentProcessGroupEntity = processGroupMap.get(proposedProcessGroupEntity.id);
+
+ // set the process group if appropriate due to revision and wasn't previously removed
+ if ((nfClient.isNewerRevision(currentProcessGroupEntity, proposedProcessGroupEntity) && !removedCache.has(proposedProcessGroupEntity.id)) || overrideRevisionCheck === true) {
+ processGroupMap.set(proposedProcessGroupEntity.id, $.extend({
+ type: 'ProcessGroup',
+ dimensions: dimensions
+ }, proposedProcessGroupEntity));
+ }
+ };
+
+ // determine how to handle the specified process groups
+ if ($.isArray(processGroupEntities)) {
+ $.each(processGroupMap.keys(), function (_, key) {
+ var currentProcessGroupEntity = processGroupMap.get(key);
+ var isPresent = $.grep(processGroupEntities, function (proposedProcessGroupEntity) {
+ return proposedProcessGroupEntity.id === currentProcessGroupEntity.id;
+ });
+
+ // if the current process group is not present and was not recently added, remove it
+ if (isPresent.length === 0 && !addedCache.has(key)) {
+ processGroupMap.remove(key);
+ }
+ });
+ $.each(processGroupEntities, function (_, processGroupEntity) {
+ set(processGroupEntity);
+ });
+ } else if (nfCommon.isDefinedAndNotNull(processGroupEntities)) {
+ set(processGroupEntities);
+ }
+
+ // select
+ var selection = select();
+
+ // enter
+ var entered = renderProcessGroups(selection.enter(), selectAll);
+
+ // update
+ var updated = selection.merge(entered);
+ updated.call(updateProcessGroups).call(nfCanvasUtils.position, transition);
+
+ // exit
+ selection.exit().call(removeProcessGroups);
+ },
+
+ /**
+ * If the process group id is specified it is returned. If no process group id
+ * specified, all process groups are returned.
+ *
+ * @param {string} id
+ */
+ get: function (id) {
+ if (nfCommon.isUndefined(id)) {
+ return processGroupMap.values();
+ } else {
+ return processGroupMap.get(id);
+ }
+ },
+
+ /**
+ * If the process group id is specified it is refresh according to the current
+ * state. If no process group id is specified, all process groups are refreshed.
+ *
+ * @param {string} id Optional
+ */
+ refresh: function (id) {
+ if (nfCommon.isDefinedAndNotNull(id)) {
+ d3.select('#id-' + id).call(updateProcessGroups);
+ } else {
+ d3.selectAll('g.process-group').call(updateProcessGroups);
+ }
+ },
+
+ /**
+ * Refreshes the components necessary after a pan event.
+ */
+ pan: function () {
+ d3.selectAll('g.process-group.entering, g.process-group.leaving').call(updateProcessGroups);
+ },
+
+ /**
+ * Reloads the process group state from the server and refreshes the UI.
+ * If the process group is currently unknown, this function reloads the canvas.
+ *
+ * @param {string} id The process group id
+ */
+ reload: function (id) {
+ if (processGroupMap.has(id)) {
+ var processGroupEntity = processGroupMap.get(id);
+ return $.ajax({
+ type: 'GET',
+ url: processGroupEntity.uri,
+ dataType: 'json'
+ }).done(function (response) {
+ nfProcessGroup.set(response);
+ });
+ }
+ },
+
+ /**
+ * Positions the component.
+ *
+ * @param {string} id The id
+ */
+ position: function (id) {
+ d3.select('#id-' + id).call(nfCanvasUtils.position);
+ },
+
+ /**
+ * Removes the specified process group.
+ *
+ * @param {string} processGroupIds The process group id(s)
+ */
+ remove: function (processGroupIds) {
+ var now = new Date().getTime();
+
+ if ($.isArray(processGroupIds)) {
+ $.each(processGroupIds, function (_, processGroupId) {
+ removedCache.set(processGroupId, now);
+ processGroupMap.remove(processGroupId);
+ });
+ } else {
+ removedCache.set(processGroupIds, now);
+ processGroupMap.remove(processGroupIds);
+ }
+
+ // apply the selection and handle all removed process groups
+ select().exit().call(removeProcessGroups);
+ },
+
+ /**
+ * Removes all process groups.
+ */
+ removeAll: function () {
+ nfProcessGroup.remove(processGroupMap.keys());
+ },
+
+ /**
+ * Expires the caches up to the specified timestamp.
+ *
+ * @param timestamp
+ */
+ expireCaches: function (timestamp) {
+ var expire = function (cache) {
+ cache.each(function (entryTimestamp, id) {
+ if (timestamp > entryTimestamp) {
+ cache.remove(id);
+ }
+ });
+ };
+
+ expire(addedCache);
+ expire(removedCache);
+ },
+
+ /**
+ * Enters the specified group.
+ *
+ * @param {string} groupId
+ */
+ enterGroup: function (groupId) {
+
+ // hide the context menu
+ nfContextMenu.hide();
+
+ // set the new group id
+ nfCanvasUtils.setGroupId(groupId);
+
+ // reload the graph
+ return nfCanvasUtils.reload().done(function () {
+
+ // attempt to restore the view
+ var viewRestored = nfCanvasUtils.restoreUserView();
+
+ // if the view was not restore attempt to fit
+ if (viewRestored === false) {
+ nfCanvasUtils.fitCanvas();
+ }
+
+ // update URL deep linking params
+ nfCanvasUtils.setURLParameters(groupId, d3.select());
+
+ }).fail(function () {
+ nfDialog.showOkDialog({
+ headerText: 'Process Group',
+ dialogContent: 'Unable to enter the selected group.'
+ });
+ });
+ }
+ };
+
+ return nfProcessGroup;
+}));
diff --git a/mod/designtool/designtool-web/src/main/webapp/js/nf/canvas/nf-settings.js b/mod/designtool/designtool-web/src/main/webapp/js/nf/canvas/nf-settings.js
new file mode 100644
index 0000000..8c61dac
--- /dev/null
+++ b/mod/designtool/designtool-web/src/main/webapp/js/nf/canvas/nf-settings.js
@@ -0,0 +1,2373 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Modifications to the original nifi code for the ONAP project are made
+ * available under the Apache License, Version 2.0
+ */
+
+/* global define, module, require, exports */
+
+(function (root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ define(['jquery',
+ 'Slick',
+ 'd3',
+ 'nf.Client',
+ 'nf.Dialog',
+ 'nf.Storage',
+ 'nf.Common',
+ 'nf.CanvasUtils',
+ 'nf.ControllerServices',
+ 'nf.ErrorHandler',
+ 'nf.FilteredDialogCommon',
+ 'nf.ReportingTask',
+ 'nf.Shell',
+ 'nf.ComponentState',
+ 'nf.ComponentVersion',
+ 'nf.PolicyManagement'],
+ function ($, Slick, d3, nfClient, nfDialog, nfStorage, nfCommon, nfCanvasUtils, nfControllerServices, nfErrorHandler, nfFilteredDialogCommon, nfReportingTask, nfShell, nfComponentState, nfComponentVersion, nfPolicyManagement) {
+ return (nf.Settings = factory($, Slick, d3, nfClient, nfDialog, nfStorage, nfCommon, nfCanvasUtils, nfControllerServices, nfErrorHandler, nfFilteredDialogCommon, nfReportingTask, nfShell, nfComponentState, nfComponentVersion, nfPolicyManagement));
+ });
+ } else if (typeof exports === 'object' && typeof module === 'object') {
+ module.exports = (nf.Settings =
+ factory(require('jquery'),
+ require('Slick'),
+ require('d3'),
+ require('nf.Client'),
+ require('nf.Dialog'),
+ require('nf.Storage'),
+ require('nf.Common'),
+ require('nf.CanvasUtils'),
+ require('nf.ControllerServices'),
+ require('nf.ErrorHandler'),
+ require('nf.FilteredDialogCommon'),
+ require('nf.ReportingTask'),
+ require('nf.Shell'),
+ require('nf.ComponentState'),
+ require('nf.ComponentVersion'),
+ require('nf.PolicyManagement')));
+ } else {
+ nf.Settings = factory(root.$,
+ root.Slick,
+ root.d3,
+ root.nf.Client,
+ root.nf.Dialog,
+ root.nf.Storage,
+ root.nf.Common,
+ root.nf.CanvasUtils,
+ root.nf.ControllerServices,
+ root.nf.ErrorHandler,
+ root.nf.FilteredDialogCommon,
+ root.nf.ReportingTask,
+ root.nf.Shell,
+ root.nf.ComponentState,
+ root.nf.ComponentVersion,
+ root.nf.PolicyManagement);
+ }
+}(this, function ($, Slick, d3, nfClient, nfDialog, nfStorage, nfCommon, nfCanvasUtils, nfControllerServices, nfErrorHandler, nfFilteredDialogCommon, nfReportingTask, nfShell, nfComponentState, nfComponentVersion, nfPolicyManagement) {
+ 'use strict';
+
+
+ var config = {
+ urls: {
+ api: '../nifi-api',
+ controllerConfig: '../nifi-api/controller/config',
+ reportingTaskTypes: '../nifi-api/flow/reporting-task-types',
+ createReportingTask: '../nifi-api/controller/reporting-tasks',
+ reportingTasks: '../nifi-api/flow/reporting-tasks',
+ registries: '../nifi-api/controller/registry-clients'
+ }
+ };
+
+ var gridOptions = {
+ forceFitColumns: true,
+ enableTextSelectionOnCells: true,
+ enableCellNavigation: true,
+ enableColumnReorder: false,
+ autoEdit: false,
+ multiSelect: false,
+ rowHeight: 24
+ };
+
+
+ var dcaeDistributorApiHostname;
+
+ //get hostname
+ $.ajax({
+ type: 'GET',
+ url: '../nifi-api/flow/config',
+ dataType: 'json',
+ contentType: 'application/json',
+ success: function(data){
+ dcaeDistributorApiHostname= data.flowConfiguration.dcaeDistributorApiHostname;
+ console.log(dcaeDistributorApiHostname);
+ }
+ });
+
+
+ /**
+ * Gets the controller services table.
+ *
+ * @returns {*|jQuery|HTMLElement}
+ */
+ var getDistributionEnvironmentsTable = function () {
+ return $('#distribution-environments-table');
+ };
+
+ /**
+ * Gets the controller services table.
+ *
+ * @returns {*|jQuery|HTMLElement}
+ */
+ var getControllerServicesTable = function () {
+ return $('#controller-services-table');
+ };
+
+ /**
+ * Saves the settings for the controller.
+ *
+ * @param version
+ */
+ var saveSettings = function (version) {
+ // marshal the configuration details
+ var configuration = marshalConfiguration();
+ var entity = {
+ 'revision': nfClient.getRevision({
+ 'revision': {
+ 'version': version
+ }
+ }),
+ 'disconnectedNodeAcknowledged': nfStorage.isDisconnectionAcknowledged(),
+ 'component': configuration
+ };
+
+ // save the new configuration details
+ $.ajax({
+ type: 'PUT',
+ url: config.urls.controllerConfig,
+ data: JSON.stringify(entity),
+ dataType: 'json',
+ contentType: 'application/json'
+ }).done(function (response) {
+ // close the settings dialog
+ nfDialog.showOkDialog({
+ headerText: 'Settings',
+ dialogContent: 'Settings successfully applied.'
+ });
+
+ // register the click listener for the save button
+ $('#settings-save').off('click').on('click', function () {
+ saveSettings(response.revision.version);
+ });
+ }).fail(nfErrorHandler.handleAjaxError);
+ }
+
+ /**
+ * Initializes the general tab.
+ */
+ var initGeneral = function () {
+ };
+
+ /**
+ * Marshals the details to include in the configuration request.
+ */
+ var marshalConfiguration = function () {
+ // create the configuration
+ var configuration = {};
+ configuration['maxTimerDrivenThreadCount'] = $('#maximum-timer-driven-thread-count-field').val();
+ configuration['maxEventDrivenThreadCount'] = $('#maximum-event-driven-thread-count-field').val();
+ return configuration;
+ };
+
+ /**
+ * Determines if the item matches the filter.
+ *
+ * @param {object} item The item to filter
+ * @param {object} args The filter criteria
+ * @returns {boolean} Whether the item matches the filter
+ */
+ var matchesRegex = function (item, args) {
+ if (args.searchString === '') {
+ return true;
+ }
+
+ try {
+ // perform the row filtering
+ var filterExp = new RegExp(args.searchString, 'i');
+ } catch (e) {
+ // invalid regex
+ return false;
+ }
+
+ // determine if the item matches the filter
+ var matchesLabel = item['label'].search(filterExp) >= 0;
+ var matchesTags = item['tags'].search(filterExp) >= 0;
+ return matchesLabel || matchesTags;
+ };
+
+ /**
+ * Determines if the specified tags match all the tags selected by the user.
+ *
+ * @argument {string[]} tagFilters The tag filters
+ * @argument {string} tags The tags to test
+ */
+ var matchesSelectedTags = function (tagFilters, tags) {
+ var selectedTags = [];
+ $.each(tagFilters, function (_, filter) {
+ selectedTags.push(filter);
+ });
+
+ // normalize the tags
+ var normalizedTags = tags.toLowerCase();
+
+ var matches = true;
+ $.each(selectedTags, function (i, selectedTag) {
+ if (normalizedTags.indexOf(selectedTag) === -1) {
+ matches = false;
+ return false;
+ }
+ });
+
+ return matches;
+ };
+
+ /**
+ * Whether the specified item is selectable.
+ *
+ * @param item reporting task type
+ */
+ var isSelectable = function (item) {
+ return item.restricted === false || nfCommon.canAccessComponentRestrictions(item.explicitRestrictions);
+ };
+
+ /**
+ * Formatter for the name column.
+ *
+ * @param {type} row
+ * @param {type} cell
+ * @param {type} value
+ * @param {type} columnDef
+ * @param {type} dataContext
+ * @returns {String}
+ */
+ var nameFormatter = function (row, cell, value, columnDef, dataContext) {
+ if (!dataContext.permissions.canRead) {
+ return '<span class="blank">' + nfCommon.escapeHtml(dataContext.id) + '</span>';
+ }
+
+ return nfCommon.escapeHtml(dataContext.component.name);
+ };
+
+ /**
+ * Sorts the specified data using the specified sort details.
+ *
+ * @param {object} sortDetails
+ * @param {object} data
+ */
+ var sort = function (sortDetails, data) {
+ // defines a function for sorting
+ var comparer = function (a, b) {
+ if (a.permissions.canRead && b.permissions.canRead) {
+ if (sortDetails.columnId === 'moreDetails') {
+ var aBulletins = 0;
+ if (!nfCommon.isEmpty(a.bulletins)) {
+ aBulletins = a.bulletins.length;
+ }
+ var bBulletins = 0;
+ if (!nfCommon.isEmpty(b.bulletins)) {
+ bBulletins = b.bulletins.length;
+ }
+ return aBulletins - bBulletins;
+ } else if (sortDetails.columnId === 'type') {
+ var aType = nfCommon.isDefinedAndNotNull(a.component[sortDetails.columnId]) ? nfCommon.substringAfterLast(a.component[sortDetails.columnId], '.') : '';
+ var bType = nfCommon.isDefinedAndNotNull(b.component[sortDetails.columnId]) ? nfCommon.substringAfterLast(b.component[sortDetails.columnId], '.') : '';
+ return aType === bType ? 0 : aType > bType ? 1 : -1;
+ } else if (sortDetails.columnId === 'state') {
+ var aState;
+ if (a.component.validationStatus === 'VALIDATING') {
+ aState = 'Validating';
+ } else if (a.component.validationStatus === 'INVALID') {
+ aState = 'Invalid';
+ } else {
+ aState = nfCommon.isDefinedAndNotNull(a.component[sortDetails.columnId]) ? a.component[sortDetails.columnId] : '';
+ }
+ var bState;
+ if (b.component.validationStatus === 'VALIDATING') {
+ bState = 'Validating';
+ } else if (b.component.validationStatus === 'INVALID') {
+ bState = 'Invalid';
+ } else {
+ bState = nfCommon.isDefinedAndNotNull(b.component[sortDetails.columnId]) ? b.component[sortDetails.columnId] : '';
+ }
+ return aState === bState ? 0 : aState > bState ? 1 : -1;
+ } else {
+ var aString = nfCommon.isDefinedAndNotNull(a.component[sortDetails.columnId]) ? a.component[sortDetails.columnId] : '';
+ var bString = nfCommon.isDefinedAndNotNull(b.component[sortDetails.columnId]) ? b.component[sortDetails.columnId] : '';
+ return aString === bString ? 0 : aString > bString ? 1 : -1;
+ }
+ } else {
+ if (!a.permissions.canRead && !b.permissions.canRead) {
+ return 0;
+ }
+ if (a.permissions.canRead) {
+ return 1;
+ } else {
+ return -1;
+ }
+ }
+ };
+
+ // perform the sort
+ data.sort(comparer, sortDetails.sortAsc);
+ };
+
+ /**
+ * Get the text out of the filter field. If the filter field doesn't
+ * have any text it will contain the text 'filter list' so this method
+ * accounts for that.
+ */
+ var getReportingTaskTypeFilterText = function () {
+ return $('#reporting-task-type-filter').val();
+ };
+
+ /**
+ * Filters the reporting task type table.
+ */
+ var applyReportingTaskTypeFilter = function () {
+ // get the dataview
+ var reportingTaskTypesGrid = $('#reporting-task-types-table').data('gridInstance');
+
+ // ensure the grid has been initialized
+ if (nfCommon.isDefinedAndNotNull(reportingTaskTypesGrid)) {
+ var reportingTaskTypesData = reportingTaskTypesGrid.getData();
+
+ // update the search criteria
+ reportingTaskTypesData.setFilterArgs({
+ searchString: getReportingTaskTypeFilterText()
+ });
+ reportingTaskTypesData.refresh();
+
+ // update the buttons to possibly trigger the disabled state
+ $('#new-reporting-task-dialog').modal('refreshButtons');
+
+ // update the selection if possible
+ if (reportingTaskTypesData.getLength() > 0) {
+ nfFilteredDialogCommon.choseFirstRow(reportingTaskTypesGrid);
+ }
+ }
+ };
+
+ /**
+ * Hides the selected reporting task.
+ */
+ var clearSelectedReportingTask = function () {
+ $('#reporting-task-type-description').attr('title', '').text('');
+ $('#reporting-task-type-name').attr('title', '').text('');
+ $('#reporting-task-type-bundle').attr('title', '').text('');
+ $('#selected-reporting-task-name').text('');
+ $('#selected-reporting-task-type').text('').removeData('bundle');
+ $('#reporting-task-description-container').hide();
+ };
+
+ /**
+ * Clears the selected reporting task type.
+ */
+ var clearReportingTaskSelection = function () {
+ // clear the selected row
+ clearSelectedReportingTask();
+
+ // clear the active cell the it can be reselected when its included
+ var reportingTaskTypesGrid = $('#reporting-task-types-table').data('gridInstance');
+ reportingTaskTypesGrid.resetActiveCell();
+ };
+
+ /**
+ * Performs the filtering.
+ *
+ * @param {object} item The item subject to filtering
+ * @param {object} args Filter arguments
+ * @returns {Boolean} Whether or not to include the item
+ */
+ var filterReportingTaskTypes = function (item, args) {
+ // determine if the item matches the filter
+ var matchesFilter = matchesRegex(item, args);
+
+ // determine if the row matches the selected tags
+ var matchesTags = true;
+ if (matchesFilter) {
+ var tagFilters = $('#reporting-task-tag-cloud').tagcloud('getSelectedTags');
+ var hasSelectedTags = tagFilters.length > 0;
+ if (hasSelectedTags) {
+ matchesTags = matchesSelectedTags(tagFilters, item['tags']);
+ }
+ }
+
+ // determine if the row matches the selected source group
+ var matchesGroup = true;
+ if (matchesFilter && matchesTags) {
+ var bundleGroup = $('#reporting-task-bundle-group-combo').combo('getSelectedOption');
+ if (nfCommon.isDefinedAndNotNull(bundleGroup) && bundleGroup.value !== '') {
+ matchesGroup = (item.bundle.group === bundleGroup.value);
+ }
+ }
+
+ // determine if this row should be visible
+ var matches = matchesFilter && matchesTags && matchesGroup;
+
+ // if this row is currently selected and its being filtered
+ if (matches === false && $('#selected-reporting-task-type').text() === item['type']) {
+ clearReportingTaskSelection();
+ }
+
+ return matches;
+ };
+
+ /**
+ * Adds the currently selected reporting task.
+ */
+ var addSelectedReportingTask = function () {
+ var selectedTaskType = $('#selected-reporting-task-type').text();
+ var selectedTaskBundle = $('#selected-reporting-task-type').data('bundle');
+
+ // ensure something was selected
+ if (selectedTaskType === '') {
+ nfDialog.showOkDialog({
+ headerText: 'Settings',
+ dialogContent: 'The type of reporting task to create must be selected.'
+ });
+ } else {
+ addReportingTask(selectedTaskType, selectedTaskBundle);
+ }
+ };
+
+ /**
+ * Adds a new reporting task of the specified type.
+ *
+ * @param {string} reportingTaskType
+ * @param {object} reportingTaskBundle
+ */
+ var addReportingTask = function (reportingTaskType, reportingTaskBundle) {
+ // build the reporting task entity
+ var reportingTaskEntity = {
+ 'revision': nfClient.getRevision({
+ 'revision': {
+ 'version': 0
+ }
+ }),
+ 'disconnectedNodeAcknowledged': nfStorage.isDisconnectionAcknowledged(),
+ 'component': {
+ 'type': reportingTaskType,
+ 'bundle': reportingTaskBundle
+ }
+ };
+
+ // add the new reporting task
+ var addTask = $.ajax({
+ type: 'POST',
+ url: config.urls.createReportingTask,
+ data: JSON.stringify(reportingTaskEntity),
+ dataType: 'json',
+ contentType: 'application/json'
+ }).done(function (reportingTaskEntity) {
+ // add the item
+ var reportingTaskGrid = $('#reporting-tasks-table').data('gridInstance');
+ var reportingTaskData = reportingTaskGrid.getData();
+ reportingTaskData.addItem($.extend({
+ type: 'ReportingTask',
+ bulletins: []
+ }, reportingTaskEntity));
+
+ // resort
+ reportingTaskData.reSort();
+ reportingTaskGrid.invalidate();
+
+ // select the new reporting task
+ var row = reportingTaskData.getRowById(reportingTaskEntity.id);
+ nfFilteredDialogCommon.choseRow(reportingTaskGrid, row);
+ reportingTaskGrid.scrollRowIntoView(row);
+ }).fail(nfErrorHandler.handleAjaxError);
+
+ // hide the dialog
+ $('#new-reporting-task-dialog').modal('hide');
+
+ return addTask;
+ };
+
+ /**
+ * Adds the specified entity.
+ */
+ var addRegistry = function () {
+ var registryEntity = {
+ 'revision': nfClient.getRevision({
+ 'revision': {
+ 'version': 0
+ }
+ }),
+ 'disconnectedNodeAcknowledged': nfStorage.isDisconnectionAcknowledged(),
+ 'component': {
+ 'name': $('#registry-name').val(),
+ 'uri': $('#registry-location').val(),
+ 'description': $('#registry-description').val()
+ }
+ };
+
+ // add the new registry
+ var addRegistry = $.ajax({
+ type: 'POST',
+ url: config.urls.registries,
+ data: JSON.stringify(registryEntity),
+ dataType: 'json',
+ contentType: 'application/json'
+ }).done(function (registryEntity) {
+ // add the item
+ var registriesGrid = $('#registries-table').data('gridInstance');
+ var registriesData = registriesGrid.getData();
+ registriesData.addItem($.extend({
+ type: 'Registry'
+ }, registryEntity));
+
+ // resort
+ registriesData.reSort();
+ registriesGrid.invalidate();
+
+ // select the new reporting task
+ var row = registriesData.getRowById(registryEntity.id);
+ nfFilteredDialogCommon.choseRow(registriesGrid, row);
+ registriesGrid.scrollRowIntoView(row);
+ }).fail(nfErrorHandler.handleAjaxError);
+
+ // hide the dialog
+ $('#registry-configuration-dialog').modal('hide');
+
+ return addRegistry;
+ };
+
+
+ /**
+ * Adds the specific environment.
+ */
+ var addDistributionEnvironment= function () {
+ var environmentEntity = {
+ 'name': $('#distribution-environment-name').val(),
+ 'runtimeApiUrl': $('#distribution-environment-location').val(),
+ 'description': $('#distribution-environment-description').val()
+// 'nextDistributionTargetId': $('#distribution-environment-nextDistributionTargetId').val()
+ };
+
+ console.log("before POST call ");
+ console.log(environmentEntity);
+
+ // add the new distribution environment
+ var addDistributionEnvironment= $.ajax({
+ type: 'POST',
+ url: dcaeDistributorApiHostname+'/distribution-targets',
+ data: JSON.stringify(environmentEntity),
+ dataType: 'json',
+ contentType: 'application/json'
+ }).done(function (environmentEntity) {
+ // add the item
+ console.log("after POST call in response ");
+ console.log(environmentEntity);
+ var environmentsGrid = $('#distribution-environments-table').data('gridInstance');
+ console.log(environmentsGrid);
+ var environmentsData = environmentsGrid.getData();
+ environmentsData.addItem($.extend({
+ type: 'Environment'
+ }, environmentEntity));
+
+
+ // resort
+ environmentsData.reSort();
+ environmentsGrid.invalidate();
+
+ // select the new distribution env.
+ var row = environmentsData.getRowById(environmentEntity.id);
+ nfFilteredDialogCommon.choseRow(environmentsGrid, row);
+ registriesGrid.scrollRowIntoView(row);
+ }).fail(nfErrorHandler.handleAjaxError);
+
+ // hide the dialog
+ $('#distribution-environment-dialog').modal('hide');
+
+ return addDistributionEnvironment;
+ };
+
+
+ /**
+ * Updates the registry with the specified id.
+ *
+ * @param registryId
+ */
+ var updateRegistry = function (registryId) {
+ var registriesGrid = $('#registries-table').data('gridInstance');
+ var registriesData = registriesGrid.getData();
+
+ var registryEntity = registriesData.getItemById(registryId);
+ var requestRegistryEntity = {
+ 'revision': nfClient.getRevision(registryEntity),
+ 'disconnectedNodeAcknowledged': nfStorage.isDisconnectionAcknowledged(),
+ 'component': {
+ 'id': registryId,
+ 'name': $('#registry-name').val(),
+ 'uri': $('#registry-location').val(),
+ 'description': $('#registry-description').val()
+ }
+ };
+
+ // add the new reporting task
+ var updateRegistry = $.ajax({
+ type: 'PUT',
+ url: registryEntity.uri,
+ data: JSON.stringify(requestRegistryEntity),
+ dataType: 'json',
+ contentType: 'application/json'
+ }).done(function (registryEntity) {
+ // add the item
+ registriesData.updateItem(registryId, $.extend({
+ type: 'Registry'
+ }, registryEntity));
+ }).fail(nfErrorHandler.handleAjaxError);
+
+ // hide the dialog
+ $('#registry-configuration-dialog').modal('hide');
+
+ return updateRegistry;
+ };
+
+
+ /**
+ * Updates the distribution environment with the specified id.
+ *
+ * @param environmentId
+ */
+ var updateDistributionEnvironment = function (environmentId) {
+ var environmentsGrid = $('#distribution-environments-table').data('gridInstance');
+ var environmentsData = environmentsGrid.getData();
+
+ var environmentEntity = environmentsData.getItemById(environmentId);
+ var requestEnvironmentEntity = {
+ 'id': environmentId,
+ 'name': $('#distribution-environment-name').val(),
+ 'runtimeApiUrl': $('#distribution-environment-location').val(),
+ 'description': $('#distribution-environment-description').val(),
+// 'nextDistributionTargetId': $('#distribution-environment-nextDistributionTargetId').val()
+ };
+
+ console.log(requestEnvironmentEntity);
+ // updating distribution environment
+ var updateDistributionEnvironment = $.ajax({
+ type: 'PUT',
+ url: dcaeDistributorApiHostname+'/distribution-targets/'+environmentEntity.id,
+ data: JSON.stringify(requestEnvironmentEntity),
+ dataType: 'json',
+ contentType: 'application/json'
+ }).done(function (environmentEntity) {
+ // update the item
+ console.log(environmentsGrid);
+ environmentsData.updateItem(environmentId, $.extend({
+ type: 'Environment'
+ }, environmentEntity));
+ }).fail(nfErrorHandler.handleAjaxError);
+
+ // hide the dialog
+ $('#distribution-environment-dialog').modal('hide');
+
+ return updateDistributionEnvironment;
+ };
+
+
+
+
+
+ /**
+ * Initializes the new reporting task dialog.
+ */
+ var initNewReportingTaskDialog = function () {
+ // initialize the reporting task type table
+ var reportingTaskTypesColumns = [
+ {
+ id: 'type',
+ name: 'Type',
+ field: 'label',
+ formatter: nfCommon.typeFormatter,
+ sortable: true,
+ resizable: true
+ },
+ {
+ id: 'version',
+ name: 'Version',
+ field: 'version',
+ formatter: nfCommon.typeVersionFormatter,
+ sortable: true,
+ resizable: true
+ },
+ {
+ id: 'tags',
+ name: 'Tags',
+ field: 'tags',
+ sortable: true,
+ resizable: true,
+ formatter: nfCommon.genericValueFormatter
+ }
+ ];
+
+ // initialize the dataview
+ var reportingTaskTypesData = new Slick.Data.DataView({
+ inlineFilters: false
+ });
+ reportingTaskTypesData.setItems([]);
+ reportingTaskTypesData.setFilterArgs({
+ searchString: getReportingTaskTypeFilterText()
+ });
+ reportingTaskTypesData.setFilter(filterReportingTaskTypes);
+
+ // initialize the sort
+ nfCommon.sortType({
+ columnId: 'type',
+ sortAsc: true
+ }, reportingTaskTypesData);
+
+ // initialize the grid
+ var reportingTaskTypesGrid = new Slick.Grid('#reporting-task-types-table', reportingTaskTypesData, reportingTaskTypesColumns, gridOptions);
+ reportingTaskTypesGrid.setSelectionModel(new Slick.RowSelectionModel());
+ reportingTaskTypesGrid.registerPlugin(new Slick.AutoTooltips());
+ reportingTaskTypesGrid.setSortColumn('type', true);
+ reportingTaskTypesGrid.onSort.subscribe(function (e, args) {
+ nfCommon.sortType({
+ columnId: args.sortCol.field,
+ sortAsc: args.sortAsc
+ }, reportingTaskTypesData);
+ });
+ reportingTaskTypesGrid.onSelectedRowsChanged.subscribe(function (e, args) {
+ if ($.isArray(args.rows) && args.rows.length === 1) {
+ var reportingTaskTypeIndex = args.rows[0];
+ var reportingTaskType = reportingTaskTypesGrid.getDataItem(reportingTaskTypeIndex);
+
+ // set the reporting task type description
+ if (nfCommon.isDefinedAndNotNull(reportingTaskType)) {
+ // show the selected reporting task
+ $('#reporting-task-description-container').show();
+
+ if (nfCommon.isBlank(reportingTaskType.description)) {
+ $('#reporting-task-type-description')
+ .attr('title', '')
+ .html('<span class="unset">No description specified</span>');
+ } else {
+ $('#reporting-task-type-description')
+ .width($('#reporting-task-description-container').innerWidth() - 1)
+ .html(reportingTaskType.description)
+ .ellipsis();
+ }
+
+ var bundle = nfCommon.formatBundle(reportingTaskType.bundle);
+ var type = nfCommon.formatType(reportingTaskType);
+
+ // populate the dom
+ $('#reporting-task-type-name').text(type).attr('title', type);
+ $('#reporting-task-type-bundle').text(bundle).attr('title', bundle);
+ $('#selected-reporting-task-name').text(reportingTaskType.label);
+ $('#selected-reporting-task-type').text(reportingTaskType.type).data('bundle', reportingTaskType.bundle);
+
+ // refresh the buttons based on the current selection
+ $('#new-reporting-task-dialog').modal('refreshButtons');
+ }
+ }
+ });
+ reportingTaskTypesGrid.onDblClick.subscribe(function (e, args) {
+ var reportingTaskType = reportingTaskTypesGrid.getDataItem(args.row);
+
+ if (isSelectable(reportingTaskType)) {
+ addReportingTask(reportingTaskType.type, reportingTaskType.bundle);
+ }
+ });
+ reportingTaskTypesGrid.onViewportChanged.subscribe(function (e, args) {
+ nfCommon.cleanUpTooltips($('#reporting-task-types-table'), 'div.view-usage-restriction');
+ });
+
+ // wire up the dataview to the grid
+ reportingTaskTypesData.onRowCountChanged.subscribe(function (e, args) {
+ reportingTaskTypesGrid.updateRowCount();
+ reportingTaskTypesGrid.render();
+
+ // update the total number of displayed processors
+ $('#displayed-reporting-task-types').text(args.current);
+ });
+ reportingTaskTypesData.onRowsChanged.subscribe(function (e, args) {
+ reportingTaskTypesGrid.invalidateRows(args.rows);
+ reportingTaskTypesGrid.render();
+ });
+ reportingTaskTypesData.syncGridSelection(reportingTaskTypesGrid, true);
+
+ // hold onto an instance of the grid
+ $('#reporting-task-types-table').data('gridInstance', reportingTaskTypesGrid).on('mouseenter', 'div.slick-cell', function (e) {
+ var usageRestriction = $(this).find('div.view-usage-restriction');
+ if (usageRestriction.length && !usageRestriction.data('qtip')) {
+ var rowId = $(this).find('span.row-id').text();
+
+ // get the status item
+ var item = reportingTaskTypesData.getItemById(rowId);
+
+ // show the tooltip
+ if (item.restricted === true) {
+ var restrictionTip = $('<div></div>');
+
+ if (nfCommon.isBlank(item.usageRestriction)) {
+ restrictionTip.append($('<p style="margin-bottom: 3px;"></p>').text('Requires the following permissions:'));
+ } else {
+ restrictionTip.append($('<p style="margin-bottom: 3px;"></p>').text(item.usageRestriction + ' Requires the following permissions:'));
+ }
+
+ var restrictions = [];
+ if (nfCommon.isDefinedAndNotNull(item.explicitRestrictions)) {
+ $.each(item.explicitRestrictions, function (_, explicitRestriction) {
+ var requiredPermission = explicitRestriction.requiredPermission;
+ restrictions.push("'" + requiredPermission.label + "' - " + nfCommon.escapeHtml(explicitRestriction.explanation));
+ });
+ } else {
+ restrictions.push('Access to restricted components regardless of restrictions.');
+ }
+ restrictionTip.append(nfCommon.formatUnorderedList(restrictions));
+
+ usageRestriction.qtip($.extend({}, nfCommon.config.tooltipConfig, {
+ content: restrictionTip,
+ position: {
+ container: $('#summary'),
+ at: 'bottom right',
+ my: 'top left',
+ adjust: {
+ x: 4,
+ y: 4
+ }
+ }
+ }));
+ }
+ }
+ });
+
+ var generalRestriction = nfCommon.getPolicyTypeListing('restricted-components');
+
+ // load the available reporting tasks
+ $.ajax({
+ type: 'GET',
+ url: config.urls.reportingTaskTypes,
+ dataType: 'json'
+ }).done(function (response) {
+ var id = 0;
+ var tags = [];
+ var groups = d3.set();
+ var restrictedUsage = d3.map();
+ var requiredPermissions = d3.map();
+
+ // begin the update
+ reportingTaskTypesData.beginUpdate();
+
+ // go through each reporting task type
+ $.each(response.reportingTaskTypes, function (i, documentedType) {
+ if (documentedType.restricted === true) {
+ if (nfCommon.isDefinedAndNotNull(documentedType.explicitRestrictions)) {
+ $.each(documentedType.explicitRestrictions, function (_, explicitRestriction) {
+ var requiredPermission = explicitRestriction.requiredPermission;
+
+ // update required permissions
+ if (!requiredPermissions.has(requiredPermission.id)) {
+ requiredPermissions.set(requiredPermission.id, requiredPermission.label);
+ }
+
+ // update component restrictions
+ if (!restrictedUsage.has(requiredPermission.id)) {
+ restrictedUsage.set(requiredPermission.id, []);
+ }
+
+ restrictedUsage.get(requiredPermission.id).push({
+ type: nfCommon.formatType(documentedType),
+ bundle: nfCommon.formatBundle(documentedType.bundle),
+ explanation: nfCommon.escapeHtml(explicitRestriction.explanation)
+ })
+ });
+ } else {
+ // update required permissions
+ if (!requiredPermissions.has(generalRestriction.value)) {
+ requiredPermissions.set(generalRestriction.value, generalRestriction.text);
+ }
+
+ // update component restrictions
+ if (!restrictedUsage.has(generalRestriction.value)) {
+ restrictedUsage.set(generalRestriction.value, []);
+ }
+
+ restrictedUsage.get(generalRestriction.value).push({
+ type: nfCommon.formatType(documentedType),
+ bundle: nfCommon.formatBundle(documentedType.bundle),
+ explanation: nfCommon.escapeHtml(documentedType.usageRestriction)
+ });
+ }
+ }
+
+ // record the group
+ groups.add(documentedType.bundle.group);
+
+ // add the documented type
+ reportingTaskTypesData.addItem({
+ id: id++,
+ label: nfCommon.substringAfterLast(documentedType.type, '.'),
+ type: documentedType.type,
+ bundle: documentedType.bundle,
+ description: nfCommon.escapeHtml(documentedType.description),
+ restricted: documentedType.restricted,
+ usageRestriction: nfCommon.escapeHtml(documentedType.usageRestriction),
+ explicitRestrictions: documentedType.explicitRestrictions,
+ tags: documentedType.tags.join(', ')
+ });
+
+ // count the frequency of each tag for this type
+ $.each(documentedType.tags, function (i, tag) {
+ tags.push(tag.toLowerCase());
+ });
+ });
+
+ // end the update
+ reportingTaskTypesData.endUpdate();
+
+ // resort
+ reportingTaskTypesData.reSort();
+ reportingTaskTypesGrid.invalidate();
+
+ // set the component restrictions and the corresponding required permissions
+ nfCanvasUtils.addComponentRestrictions(restrictedUsage, requiredPermissions);
+
+ // set the total number of processors
+ $('#total-reporting-task-types, #displayed-reporting-task-types').text(response.reportingTaskTypes.length);
+
+ // create the tag cloud
+ $('#reporting-task-tag-cloud').tagcloud({
+ tags: tags,
+ select: applyReportingTaskTypeFilter,
+ remove: applyReportingTaskTypeFilter
+ });
+
+ // build the combo options
+ var options = [{
+ text: 'all groups',
+ value: ''
+ }];
+ groups.each(function (group) {
+ options.push({
+ text: group,
+ value: group
+ });
+ });
+
+ // initialize the bundle group combo
+ $('#reporting-task-bundle-group-combo').combo({
+ options: options,
+ select: applyReportingTaskTypeFilter
+ });
+ }).fail(nfErrorHandler.handleAjaxError);
+
+ var navigationKeys = [$.ui.keyCode.UP, $.ui.keyCode.PAGE_UP, $.ui.keyCode.DOWN, $.ui.keyCode.PAGE_DOWN];
+
+ // define the function for filtering the list
+ $('#reporting-task-type-filter').off('keyup').on('keyup', function (e) {
+ var code = e.keyCode ? e.keyCode : e.which;
+
+ // ignore navigation keys
+ if ($.inArray(code, navigationKeys) !== -1) {
+ return;
+ }
+
+ if (code === $.ui.keyCode.ENTER) {
+ var selected = reportingTaskTypesGrid.getSelectedRows();
+
+ if (selected.length > 0) {
+ // grid configured with multi-select = false
+ var item = reportingTaskTypesGrid.getDataItem(selected[0]);
+ if (isSelectable(item)) {
+ addSelectedReportingTask();
+ }
+ }
+ } else {
+ applyReportingTaskTypeFilter();
+ }
+ });
+
+ // setup row navigation
+ nfFilteredDialogCommon.addKeydownListener('#reporting-task-type-filter', reportingTaskTypesGrid, reportingTaskTypesGrid.getData());
+
+ // initialize the reporting task dialog
+ $('#new-reporting-task-dialog').modal({
+ scrollableContentStyle: 'scrollable',
+ headerText: 'Add Reporting Task',
+ buttons: [{
+ buttonText: 'Add',
+ color: {
+ base: '#728E9B',
+ hover: '#004849',
+ text: '#ffffff'
+ },
+ disabled: function () {
+ var selected = reportingTaskTypesGrid.getSelectedRows();
+
+ if (selected.length > 0) {
+ // grid configured with multi-select = false
+ var item = reportingTaskTypesGrid.getDataItem(selected[0]);
+ return isSelectable(item) === false;
+ } else {
+ return reportingTaskTypesGrid.getData().getLength() === 0;
+ }
+ },
+ handler: {
+ click: function () {
+ addSelectedReportingTask();
+ }
+ }
+ },
+ {
+ buttonText: 'Cancel',
+ color: {
+ base: '#E3E8EB',
+ hover: '#C7D2D7',
+ text: '#004849'
+ },
+ handler: {
+ click: function () {
+ $(this).modal('hide');
+ }
+ }
+ }],
+ handler: {
+ close: function () {
+ // clear the selected row
+ clearSelectedReportingTask();
+
+ // clear any filter strings
+ $('#reporting-task-type-filter').val('');
+
+ // clear the tagcloud
+ $('#reporting-task-tag-cloud').tagcloud('clearSelectedTags');
+
+ // reset the group combo
+ $('#reporting-task-bundle-group-combo').combo('setSelectedOption', {
+ value: ''
+ });
+
+ // reset the filter
+ applyReportingTaskTypeFilter();
+
+ // unselect any current selection
+ var reportingTaskTypesGrid = $('#reporting-task-types-table').data('gridInstance');
+ reportingTaskTypesGrid.setSelectedRows([]);
+ reportingTaskTypesGrid.resetActiveCell();
+ },
+ resize: function () {
+ $('#reporting-task-type-description')
+ .width($('#reporting-task-description-container').innerWidth() - 1)
+ .text($('#reporting-task-type-description').attr('title'))
+ .ellipsis();
+ }
+ }
+ });
+
+ // initialize the registry configuration dialog
+ $('#registry-configuration-dialog').modal({
+ scrollableContentStyle: 'scrollable',
+ handler: {
+ close: function () {
+ $('#registry-id').text('');
+ $('#registry-name').val('');
+ $('#registry-location').val('');
+ $('#registry-description').val('');
+ }
+ }
+ });
+
+
+ // initialize the distribution environment dialog
+ $('#distribution-environment-dialog').modal({
+ scrollableContentStyle: 'scrollable',
+ handler: {
+ close: function () {
+ $('#distribution-environment-id').text('');
+ $('#distribution-environment-name').val('');
+ $('#distribution-environment-location').val('');
+ $('#distribution-environment-description').val('');
+// $('#distribution-environment-nextDistributionTargetId').val('');
+ }
+ }
+ });
+ };
+
+ /**
+ * Initializes the reporting tasks tab.
+ */
+ var initReportingTasks = function () {
+ // initialize the new reporting task dialog
+ initNewReportingTaskDialog();
+
+ var moreReportingTaskDetails = function (row, cell, value, columnDef, dataContext) {
+ if (!dataContext.permissions.canRead) {
+ return '';
+ }
+
+ var markup = '<div title="View Details" class="pointer view-reporting-task fa fa-info-circle"></div>';
+
+ // always include a button to view the usage
+ markup += '<div title="Usage" class="pointer reporting-task-usage fa fa-book"></div>';
+
+ var hasErrors = !nfCommon.isEmpty(dataContext.component.validationErrors);
+ var hasBulletins = !nfCommon.isEmpty(dataContext.bulletins);
+
+ if (hasErrors) {
+ markup += '<div class="pointer has-errors fa fa-warning" ></div>';
+ }
+
+ if (hasBulletins) {
+ markup += '<div class="has-bulletins fa fa-sticky-note-o"></div>';
+ }
+
+ if (hasErrors || hasBulletins) {
+ markup += '<span class="hidden row-id">' + nfCommon.escapeHtml(dataContext.component.id) + '</span>';
+ }
+
+ return markup;
+ };
+
+ var reportingTaskRunStatusFormatter = function (row, cell, value, columnDef, dataContext) {
+ // determine the appropriate label
+ var icon = '', label = '';
+ if (dataContext.status.validationStatus === 'VALIDATING') {
+ icon = 'validating fa fa-spin fa-circle-notch';
+ label = 'Validating';
+ } else if (dataContext.status.validationStatus === 'INVALID') {
+ icon = 'invalid fa fa-warning';
+ label = 'Invalid';
+ } else {
+ if (dataContext.status.runStatus === 'STOPPED') {
+ label = 'Stopped';
+ icon = 'fa fa-stop stopped';
+ } else if (dataContext.status.runStatus === 'RUNNING') {
+ label = 'Running';
+ icon = 'fa fa-play running';
+ } else {
+ label = 'Disabled';
+ icon = 'icon icon-enable-false disabled';
+ }
+ }
+
+ // include the active thread count if appropriate
+ var activeThreadCount = '';
+ if (nfCommon.isDefinedAndNotNull(dataContext.status.activeThreadCount) && dataContext.status.activeThreadCount > 0) {
+ activeThreadCount = '(' + dataContext.status.activeThreadCount + ')';
+ }
+
+ // format the markup
+ var formattedValue = '<div layout="row"><div class="' + icon + '"></div>';
+ return formattedValue + '<div class="status-text">' + nfCommon.escapeHtml(label) + '</div><div style="float: left; margin-left: 4px;">' + nfCommon.escapeHtml(activeThreadCount) + '</div></div>';
+ };
+
+ var reportingTaskActionFormatter = function (row, cell, value, columnDef, dataContext) {
+ var markup = '';
+
+ var canWrite = dataContext.permissions.canWrite;
+ var canRead = dataContext.permissions.canRead;
+ var canOperate = dataContext.operatePermissions.canWrite || canWrite;
+ var isStopped = dataContext.status.runStatus === 'STOPPED';
+
+ if (dataContext.status.runStatus === 'RUNNING') {
+ if (canOperate) {
+ markup += '<div title="Stop" class="pointer stop-reporting-task fa fa-stop"></div>';
+ }
+
+ } else if (isStopped || dataContext.status.runStatus === 'DISABLED') {
+
+ if (canRead && canWrite) {
+ markup += '<div title="Edit" class="pointer edit-reporting-task fa fa-pencil"></div>';
+ }
+
+ // support starting when stopped and no validation errors
+ if (canOperate && dataContext.status.runStatus === 'STOPPED' && dataContext.status.validationStatus === 'VALID') {
+ markup += '<div title="Start" class="pointer start-reporting-task fa fa-play"></div>';
+ }
+
+ if (canRead && canWrite && dataContext.component.multipleVersionsAvailable === true) {
+ markup += '<div title="Change Version" class="pointer change-version-reporting-task fa fa-exchange"></div>';
+ }
+
+ if (canRead && canWrite && nfCommon.canModifyController()) {
+ markup += '<div title="Remove" class="pointer delete-reporting-task fa fa-trash"></div>';
+ }
+ }
+
+ if (canRead && canWrite && dataContext.component.persistsState === true) {
+ markup += '<div title="View State" class="pointer view-state-reporting-task fa fa-tasks"></div>';
+ }
+
+ // allow policy configuration conditionally
+ if (nfCanvasUtils.isManagedAuthorizer() && nfCommon.canAccessTenants()) {
+ markup += '<div title="Access Policies" class="pointer edit-access-policies fa fa-key"></div>';
+ }
+
+ return markup;
+ };
+
+ // define the column model for the reporting tasks table
+ var reportingTasksColumnModel = [
+ {
+ id: 'moreDetails',
+ name: '&nbsp;',
+ resizable: false,
+ formatter: moreReportingTaskDetails,
+ sortable: true,
+ width: 90,
+ maxWidth: 90,
+ toolTip: 'Sorts based on presence of bulletins'
+ },
+ {
+ id: 'name',
+ name: 'Name',
+ sortable: true,
+ resizable: true,
+ formatter: nameFormatter
+ },
+ {
+ id: 'type',
+ name: 'Type',
+ formatter: nfCommon.instanceTypeFormatter,
+ sortable: true,
+ resizable: true
+ },
+ {
+ id: 'bundle',
+ name: 'Bundle',
+ formatter: nfCommon.instanceBundleFormatter,
+ sortable: true,
+ resizable: true
+ },
+ {
+ id: 'state',
+ name: 'Run Status',
+ sortable: true,
+ resizeable: true,
+ formatter: reportingTaskRunStatusFormatter
+ }
+ ];
+
+ // action column should always be last
+ reportingTasksColumnModel.push({
+ id: 'actions',
+ name: '&nbsp;',
+ resizable: false,
+ formatter: reportingTaskActionFormatter,
+ sortable: false,
+ width: 90,
+ maxWidth: 90
+ });
+
+ // initialize the dataview
+ var reportingTasksData = new Slick.Data.DataView({
+ inlineFilters: false
+ });
+ reportingTasksData.setItems([]);
+
+ // initialize the sort
+ sort({
+ columnId: 'name',
+ sortAsc: true
+ }, reportingTasksData);
+
+ // initialize the grid
+ var reportingTasksGrid = new Slick.Grid('#reporting-tasks-table', reportingTasksData, reportingTasksColumnModel, gridOptions);
+ reportingTasksGrid.setSelectionModel(new Slick.RowSelectionModel());
+ reportingTasksGrid.registerPlugin(new Slick.AutoTooltips());
+ reportingTasksGrid.setSortColumn('name', true);
+ reportingTasksGrid.onSort.subscribe(function (e, args) {
+ sort({
+ columnId: args.sortCol.id,
+ sortAsc: args.sortAsc
+ }, reportingTasksData);
+ });
+
+ // configure a click listener
+ reportingTasksGrid.onClick.subscribe(function (e, args) {
+ var target = $(e.target);
+
+ // get the service at this row
+ var reportingTaskEntity = reportingTasksData.getItem(args.row);
+
+ // determine the desired action
+ if (reportingTasksGrid.getColumns()[args.cell].id === 'actions') {
+ if (target.hasClass('edit-reporting-task')) {
+ nfReportingTask.showConfiguration(reportingTaskEntity);
+ } else if (target.hasClass('start-reporting-task')) {
+ nfReportingTask.start(reportingTaskEntity);
+ } else if (target.hasClass('stop-reporting-task')) {
+ nfReportingTask.stop(reportingTaskEntity);
+ } else if (target.hasClass('delete-reporting-task')) {
+ nfReportingTask.promptToDeleteReportingTask(reportingTaskEntity);
+ } else if (target.hasClass('view-state-reporting-task')) {
+ var canClear = reportingTaskEntity.status.runStatus === 'STOPPED' && reportingTaskEntity.status.activeThreadCount === 0;
+ nfComponentState.showState(reportingTaskEntity, canClear);
+ } else if (target.hasClass('change-version-reporting-task')) {
+ nfComponentVersion.promptForVersionChange(reportingTaskEntity);
+ } else if (target.hasClass('edit-access-policies')) {
+ // show the policies for this service
+ nfPolicyManagement.showReportingTaskPolicy(reportingTaskEntity);
+
+ // close the settings dialog
+ $('#shell-close-button').click();
+ }
+ } else if (reportingTasksGrid.getColumns()[args.cell].id === 'moreDetails') {
+ if (target.hasClass('view-reporting-task')) {
+ nfReportingTask.showDetails(reportingTaskEntity);
+ } else if (target.hasClass('reporting-task-usage')) {
+ // close the settings dialog
+ $('#shell-close-button').click();
+
+ // open the documentation for this reporting task
+ nfShell.showPage('../nifi-docs/documentation?' + $.param({
+ select: reportingTaskEntity.component.type,
+ group: reportingTaskEntity.component.bundle.group,
+ artifact: reportingTaskEntity.component.bundle.artifact,
+ version: reportingTaskEntity.component.bundle.version
+ })).done(function () {
+ nfSettings.showSettings();
+ });
+ }
+ }
+ });
+
+ // wire up the dataview to the grid
+ reportingTasksData.onRowCountChanged.subscribe(function (e, args) {
+ reportingTasksGrid.updateRowCount();
+ reportingTasksGrid.render();
+ });
+ reportingTasksData.onRowsChanged.subscribe(function (e, args) {
+ reportingTasksGrid.invalidateRows(args.rows);
+ reportingTasksGrid.render();
+ });
+ reportingTasksData.syncGridSelection(reportingTasksGrid, true);
+
+ // hold onto an instance of the grid
+ $('#reporting-tasks-table').data('gridInstance', reportingTasksGrid).on('mouseenter', 'div.slick-cell', function (e) {
+ var errorIcon = $(this).find('div.has-errors');
+ if (errorIcon.length && !errorIcon.data('qtip')) {
+ var taskId = $(this).find('span.row-id').text();
+
+ // get the task item
+ var reportingTaskEntity = reportingTasksData.getItemById(taskId);
+
+ // format the errors
+ var tooltip = nfCommon.formatUnorderedList(reportingTaskEntity.component.validationErrors);
+
+ // show the tooltip
+ if (nfCommon.isDefinedAndNotNull(tooltip)) {
+ errorIcon.qtip($.extend({},
+ nfCommon.config.tooltipConfig,
+ {
+ content: tooltip,
+ position: {
+ target: 'mouse',
+ viewport: $('#shell-container'),
+ adjust: {
+ x: 8,
+ y: 8,
+ method: 'flipinvert flipinvert'
+ }
+ }
+ }));
+ }
+ }
+
+ var bulletinIcon = $(this).find('div.has-bulletins');
+ if (bulletinIcon.length && !bulletinIcon.data('qtip')) {
+ var taskId = $(this).find('span.row-id').text();
+
+ // get the task item
+ var reportingTaskEntity = reportingTasksData.getItemById(taskId);
+
+ // format the tooltip
+ var bulletins = nfCommon.getFormattedBulletins(reportingTaskEntity.bulletins);
+ var tooltip = nfCommon.formatUnorderedList(bulletins);
+
+ // show the tooltip
+ if (nfCommon.isDefinedAndNotNull(tooltip)) {
+ bulletinIcon.qtip($.extend({},
+ nfCommon.config.tooltipConfig,
+ {
+ content: tooltip,
+ position: {
+ target: 'mouse',
+ viewport: $('#shell-container'),
+ adjust: {
+ x: 8,
+ y: 8,
+ method: 'flipinvert flipinvert'
+ }
+ }
+ }));
+ }
+ }
+ });
+ };
+
+
+
+ /**
+ * Initializing Registry table
+ */
+ var initRegistriesTable = function () {
+
+ var locationFormatter = function (row, cell, value, columnDef, dataContext) {
+ if (!dataContext.permissions.canRead) {
+ return '<span class="blank">' + nfCommon.escapeHtml(dataContext.id) + '</span>';
+ }
+
+ return nfCommon.escapeHtml(dataContext.component.uri);
+ };
+
+ var descriptionFormatter = function (row, cell, value, columnDef, dataContext) {
+ if (!dataContext.permissions.canRead) {
+ return '<span class="blank">' + nfCommon.escapeHtml(dataContext.id) + '</span>';
+ }
+
+ return nfCommon.escapeHtml(dataContext.component.description);
+ };
+
+ var registriesActionFormatter = function (row, cell, value, columnDef, dataContext) {
+ var markup = '';
+
+ if (nfCommon.canModifyController()) {
+ // edit registry
+ markup += '<div title="Edit" class="pointer edit-registry fa fa-pencil"></div>';
+
+ // remove registry
+ markup += '<div title="Remove" class="pointer remove-registry fa fa-trash"></div>';
+ }
+
+ return markup;
+ };
+
+ // define the column model for the reporting tasks table
+ var registriesColumnModel = [
+ {
+ id: 'name',
+ name: 'Name',
+ field: 'name',
+ formatter: nameFormatter,
+ sortable: true,
+ resizable: true
+ },
+ {
+ id: 'uri',
+ name: 'Location',
+ field: 'uri',
+ formatter: locationFormatter,
+ sortable: true,
+ resizable: true
+ },
+ {
+ id: 'description',
+ name: 'Description',
+ field: 'description',
+ formatter: descriptionFormatter,
+ sortable: true,
+ resizable: true
+ }
+ ];
+
+ // action column should always be last
+ registriesColumnModel.push({
+ id: 'actions',
+ name: '&nbsp;',
+ resizable: false,
+ formatter: registriesActionFormatter,
+ sortable: false,
+ width: 90,
+ maxWidth: 90
+ });
+
+ // initialize the dataview
+ var registriesData = new Slick.Data.DataView({
+ inlineFilters: false
+ });
+ registriesData.setItems([]);
+
+ // initialize the sort
+ sort({
+ columnId: 'name',
+ sortAsc: true
+ }, registriesData);
+
+ // initialize the grid
+ var registriesGrid = new Slick.Grid('#registries-table', registriesData, registriesColumnModel, gridOptions);
+ registriesGrid.setSelectionModel(new Slick.RowSelectionModel());
+ registriesGrid.registerPlugin(new Slick.AutoTooltips());
+ registriesGrid.setSortColumn('name', true);
+ registriesGrid.onSort.subscribe(function (e, args) {
+ sort({
+ columnId: args.sortCol.id,
+ sortAsc: args.sortAsc
+ }, registriesData);
+ });
+
+ // configure a click listener
+ registriesGrid.onClick.subscribe(function (e, args) {
+ var target = $(e.target);
+
+ // get the service at this row
+ var registryEntity = registriesData.getItem(args.row);
+
+ // determine the desired action
+ if (registriesGrid.getColumns()[args.cell].id === 'actions') {
+ if (target.hasClass('edit-registry')) {
+ editRegistry(registryEntity);
+ } else if (target.hasClass('remove-registry')) {
+ promptToRemoveRegistry(registryEntity);
+ }
+ } else if (registriesGrid.getColumns()[args.cell].id === 'moreDetails') {
+ // if (target.hasClass('view-reporting-task')) {
+ // nfReportingTask.showDetails(reportingTaskEntity);
+ // } else if (target.hasClass('reporting-task-usage')) {
+ // // close the settings dialog
+ // $('#shell-close-button').click();
+ //
+ // // open the documentation for this reporting task
+ // nfShell.showPage('../nifi-docs/documentation?' + $.param({
+ // select: reportingTaskEntity.component.type,
+ // group: reportingTaskEntity.component.bundle.group,
+ // artifact: reportingTaskEntity.component.bundle.artifact,
+ // version: reportingTaskEntity.component.bundle.version
+ // })).done(function () {
+ // nfSettings.showSettings();
+ // });
+ // }
+ }
+ });
+
+ // wire up the dataview to the grid
+ registriesData.onRowCountChanged.subscribe(function (e, args) {
+ registriesGrid.updateRowCount();
+ registriesGrid.render();
+ });
+ registriesData.onRowsChanged.subscribe(function (e, args) {
+ registriesGrid.invalidateRows(args.rows);
+ registriesGrid.render();
+ });
+ registriesData.syncGridSelection(registriesGrid, true);
+
+ // hold onto an instance of the grid
+ $('#registries-table').data('gridInstance', registriesGrid);
+ };
+
+
+
+
+ /**
+ * Initializing Distribution Environments table
+ */
+ var initDistributionEnvironmentsTable = function () {
+
+ var locationFormatter = function (row, cell, value, columnDef, dataContext) {
+// if (!dataContext.permissions.canRead) {
+ return '<span class="blank">' + nfCommon.escapeHtml(dataContext.id) + '</span>';
+// }
+
+ return nfCommon.escapeHtml(dataContext.component.uri);
+ };
+
+ var descriptionFormatter = function (row, cell, value, columnDef, dataContext) {
+// if (!dataContext.permissions.canRead) {
+ return '<span class="blank">' + nfCommon.escapeHtml(dataContext.id) + '</span>';
+// }
+
+ return nfCommon.escapeHtml(dataContext.component.description);
+ };
+
+ var envActionFormatter = function (row, cell, value, columnDef, dataContext) {
+ var markup = '';
+
+ if (nfCommon.canModifyController()) {
+ // edit environment
+ markup += '<div title="Edit" class="pointer edit-registry fa fa-pencil"></div>';
+
+ // remove environment
+ markup += '<div title="Remove" class="pointer remove-registry fa fa-trash"></div>';
+ }
+
+ return markup;
+ };
+
+ // define the column model for the Distribution environments table
+ var environmentsColumnModel = [
+ {
+ id: 'name',
+ name: 'Name',
+ field: 'name',
+// formatter: nameFormatter,
+ sortable: true,
+ resizable: true
+ },
+ {
+ id: 'runtimeApiUrl',
+ name: 'Location',
+ field: 'runtimeApiUrl',
+// formatter: locationFormatter,
+ sortable: true,
+ resizable: true
+ },
+ {
+ id: 'description',
+ name: 'Description',
+ field: 'description',
+// formatter: descriptionFormatter,
+ sortable: true,
+ resizable: true
+ }
+// ,
+// {
+// id: 'nextDistributionTargetId',
+// name: 'Next Distribution TargetId',
+// field: 'nextDistributionTargetId',
+// formatter: descriptionFormatter,
+// sortable: true,
+// resizable: true
+// }
+ ];
+
+ // action column should always be last
+ environmentsColumnModel.push({
+ id: 'actions',
+ name: '&nbsp;',
+ resizable: false,
+ formatter: envActionFormatter,
+ sortable: false,
+ width: 90,
+ maxWidth: 90
+ });
+
+ // initialize the dataview
+ var environmentsData = new Slick.Data.DataView({
+ inlineFilters: false
+ });
+ environmentsData.setItems([]);
+
+ // initialize the sort
+ sort({
+ columnId: 'name',
+ sortAsc: true
+ }, environmentsData);
+
+ // initialize the grid
+ var environmentsGrid = new Slick.Grid('#distribution-environments-table', environmentsData, environmentsColumnModel, gridOptions);
+ environmentsGrid.setSelectionModel(new Slick.RowSelectionModel());
+ environmentsGrid.registerPlugin(new Slick.AutoTooltips());
+ environmentsGrid.setSortColumn('name', true);
+ environmentsGrid.onSort.subscribe(function (e, args) {
+ sort({
+ columnId: args.sortCol.id,
+ sortAsc: args.sortAsc
+ }, environmentsData);
+ });
+
+ // configure a click listener
+ environmentsGrid.onClick.subscribe(function (e, args) {
+ var target = $(e.target);
+
+ // get the service at this row
+ var environmentEntity = environmentsData.getItem(args.row);
+
+ // determine the desired action
+ if (environmentsGrid.getColumns()[args.cell].id === 'actions') {
+ if (target.hasClass('edit-registry')) { //left it as edit-registry intentionally to inherit styles
+ editDistributionEnvironment(environmentEntity);
+ } else if (target.hasClass('remove-registry')) { //left it as remove-registry intentionally to inherit styles
+ promptToRemoveDistributionEnvironment(environmentEntity);
+ }
+ } else if (environmentsGrid.getColumns()[args.cell].id === 'moreDetails') { }
+ });
+
+ // wire up the dataview to the grid
+ environmentsData.onRowCountChanged.subscribe(function (e, args) {
+ environmentsGrid.updateRowCount();
+ environmentsGrid.render();
+ });
+ environmentsData.onRowsChanged.subscribe(function (e, args) {
+ environmentsGrid.invalidateRows(args.rows);
+ environmentsGrid.render();
+ });
+ environmentsData.syncGridSelection(environmentsGrid, true);
+
+ // hold onto an instance of the grid
+ $('#distribution-environments-table').data('gridInstance', environmentsGrid);
+ };
+
+
+
+ /**
+ * Edits the specified registry entity.
+ *
+ * @param registryEntity
+ */
+ var editRegistry = function (registryEntity) {
+ // populate the dialog
+ $('#registry-id').text(registryEntity.id);
+ $('#registry-name').val(registryEntity.component.name);
+ $('#registry-location').val(registryEntity.component.uri);
+ $('#registry-description').val(registryEntity.component.description);
+
+ // show the dialog
+ $('#registry-configuration-dialog').modal('setHeaderText', 'Edit Registry Client').modal('setButtonModel', [{
+ buttonText: 'Update',
+ color: {
+ base: '#728E9B',
+ hover: '#004849',
+ text: '#ffffff'
+ },
+ handler: {
+ click: function () {
+ updateRegistry(registryEntity.id);
+ }
+ }
+ }, {
+ buttonText: 'Cancel',
+ color: {
+ base: '#E3E8EB',
+ hover: '#C7D2D7',
+ text: '#004849'
+ },
+ handler: {
+ click: function () {
+ $(this).modal('hide');
+ }
+ }
+ }]).modal('show');
+ };
+
+
+ /**
+ * Edits the specified distribution environment entity.
+ *@author Renu
+ * @param distributionEnvironmentEntity
+ */
+ var editDistributionEnvironment = function (distributionEnvironmentEntity) {
+ // populate the dialog
+ $('#distribution-environment-id').text(distributionEnvironmentEntity.id);
+ $('#distribution-environment-name').val(distributionEnvironmentEntity.name);
+ $('#distribution-environment-location').val(distributionEnvironmentEntity.runtimeApiUrl);
+ $('#distribution-environment-description').val(distributionEnvironmentEntity.description);
+// $('#distribution-environment-nextDistributionTargetId ').val(distributionEnvironmentEntity.component.description);
+
+ // show the dialog
+ $('#distribution-environment-dialog').modal('setHeaderText', 'Edit Environment').modal('setButtonModel', [{
+ buttonText: 'Update',
+ color: {
+ base: '#728E9B',
+ hover: '#004849',
+ text: '#ffffff'
+ },
+ handler: {
+ click: function () {
+ updateDistributionEnvironment(distributionEnvironmentEntity.id);
+ }
+ }
+ }, {
+ buttonText: 'Cancel',
+ color: {
+ base: '#E3E8EB',
+ hover: '#C7D2D7',
+ text: '#004849'
+ },
+ handler: {
+ click: function () {
+ $(this).modal('hide');
+ }
+ }
+ }]).modal('show');
+ };
+
+
+ /**
+ * Prompts the user before attempting to delete the specified environment.
+ *
+ * @param {object} environmentEntity
+ */
+ var promptToRemoveDistributionEnvironment = function (environmentEntity) {
+ // prompt for deletion
+ nfDialog.showYesNoDialog({
+ headerText: 'Delete Environment',
+ dialogContent: 'Delete Environment \'' + nfCommon.escapeHtml(environmentEntity.name) + '\'?',
+ yesHandler: function () {
+ removeDistributionEnvironment(environmentEntity);
+ }
+ });
+ };
+
+
+ /**
+ * Deletes the specified environment.
+ *
+ * @param {object} environmentEntity
+ */
+ var removeDistributionEnvironment = function (environmentEntity) {
+ console.log(environmentEntity);
+ $.ajax({
+ type: 'DELETE',
+ url: dcaeDistributorApiHostname+'/distribution-targets/'+environmentEntity.id,
+ dataType: 'json'
+ }).done(function (response) {
+ console.log(response);
+ // remove the task
+ var environmentsGrid = $('#distribution-environments-table').data('gridInstance');
+ console.log(environmentsGrid);
+ var environmentsData = environmentsGrid.getData();
+ environmentsData.deleteItem(environmentEntity.id);
+ }).fail(nfErrorHandler.handleAjaxError);
+ };
+
+
+ /**
+ * Prompts the user before attempting to delete the specified registry.
+ *
+ * @param {object} registryEntity
+ */
+ var promptToRemoveRegistry = function (registryEntity) {
+ // prompt for deletion
+ nfDialog.showYesNoDialog({
+ headerText: 'Delete Registry',
+ dialogContent: 'Delete registry \'' + nfCommon.escapeHtml(registryEntity.component.name) + '\'?',
+ yesHandler: function () {
+ removeRegistry(registryEntity);
+ }
+ });
+ };
+
+ /**
+ * Deletes the specified registry.
+ *
+ * @param {object} registryEntity
+ */
+ var removeRegistry = function (registryEntity) {
+ var revision = nfClient.getRevision(registryEntity);
+ $.ajax({
+ type: 'DELETE',
+ url: registryEntity.uri + '?' + $.param({
+ 'version': revision.version,
+ 'clientId': revision.clientId,
+ 'disconnectedNodeAcknowledged': nfStorage.isDisconnectionAcknowledged()
+ }),
+ dataType: 'json'
+ }).done(function (response) {
+ // remove the task
+ var registryGrid = $('#registries-table').data('gridInstance');
+ var registryData = registryGrid.getData();
+ registryData.deleteItem(registryEntity.id);
+ }).fail(nfErrorHandler.handleAjaxError);
+ };
+
+ /**
+ * Loads the settings.
+ */
+ var loadSettings = function () {
+ var setUnauthorizedText = function () {
+ $('#read-only-maximum-timer-driven-thread-count-field').addClass('unset').text('Unauthorized');
+ $('#read-only-maximum-event-driven-thread-count-field').addClass('unset').text('Unauthorized');
+ };
+
+ var setEditable = function (editable) {
+ if (editable) {
+ $('#general-settings div.editable').show();
+ $('#general-settings div.read-only').hide();
+ $('#settings-save').show();
+ } else {
+ $('#general-settings div.editable').hide();
+ $('#general-settings div.read-only').show();
+ $('#settings-save').hide();
+ }
+ };
+
+ var settings = $.Deferred(function (deferred) {
+ $.ajax({
+ type: 'GET',
+ url: config.urls.controllerConfig,
+ dataType: 'json'
+ }).done(function (response) {
+ if (response.permissions.canWrite) {
+ // populate the settings
+ $('#maximum-timer-driven-thread-count-field').removeClass('unset').val(response.component.maxTimerDrivenThreadCount);
+ $('#maximum-event-driven-thread-count-field').removeClass('unset').val(response.component.maxEventDrivenThreadCount);
+
+ setEditable(true);
+
+ // register the click listener for the save button
+ $('#settings-save').off('click').on('click', function () {
+ saveSettings(response.revision.version);
+ });
+ } else {
+ if (response.permissions.canRead) {
+ // populate the settings
+ $('#read-only-maximum-timer-driven-thread-count-field').removeClass('unset').text(response.component.maxTimerDrivenThreadCount);
+ $('#read-only-maximum-event-driven-thread-count-field').removeClass('unset').text(response.component.maxEventDrivenThreadCount);
+ } else {
+ setUnauthorizedText();
+ }
+
+ setEditable(false);
+ }
+ deferred.resolve();
+ }).fail(function (xhr, status, error) {
+ if (xhr.status === 403) {
+ setUnauthorizedText();
+ setEditable(false);
+ deferred.resolve();
+ } else {
+ deferred.reject(xhr, status, error);
+ }
+ });
+ }).promise();
+
+ // load the controller services
+ var controllerServicesUri = config.urls.api + '/flow/controller/controller-services';
+ var controllerServicesXhr = nfControllerServices.loadControllerServices(controllerServicesUri, getControllerServicesTable());
+
+ // load the reporting tasks
+ var reportingTasks = loadReportingTasks();
+
+ // load the registries
+ var registries = loadRegistries();
+
+ // load the distribution environments
+ var distributionEnvironments = loadDistributionEnvironments();
+
+ // return a deferred for all parts of the settings
+ return $.when(settings, controllerServicesXhr, reportingTasks).done(function (settingsResult, controllerServicesResult) {
+ var controllerServicesResponse = controllerServicesResult[0];
+
+ // update the current time
+ $('#settings-last-refreshed').text(controllerServicesResponse.currentTime);
+ }).fail(nfErrorHandler.handleAjaxError);
+ };
+
+ /**
+ * Loads the reporting tasks.
+ */
+ var loadReportingTasks = function () {
+ return $.ajax({
+ type: 'GET',
+ url: config.urls.reportingTasks,
+ dataType: 'json'
+ }).done(function (response) {
+ var tasks = [];
+ $.each(response.reportingTasks, function (_, task) {
+ tasks.push($.extend({
+ type: 'ReportingTask',
+ bulletins: []
+ }, task));
+ });
+
+ var reportingTasksElement = $('#reporting-tasks-table');
+ nfCommon.cleanUpTooltips(reportingTasksElement, 'div.has-errors');
+ nfCommon.cleanUpTooltips(reportingTasksElement, 'div.has-bulletins');
+
+ var reportingTasksGrid = reportingTasksElement.data('gridInstance');
+ var reportingTasksData = reportingTasksGrid.getData();
+
+ // update the reporting tasks
+ reportingTasksData.setItems(tasks);
+ reportingTasksData.reSort();
+ reportingTasksGrid.invalidate();
+ });
+ };
+
+ /**
+ * Loads the registries.
+ */
+ var loadRegistries = function () {
+ return $.ajax({
+ type: 'GET',
+ url: config.urls.registries,
+ dataType: 'json'
+ }).done(function (response) {
+ var registries = [];
+ $.each(response.registries, function (_, registryEntity) {
+ registries.push($.extend({
+ type: 'Registry'
+ }, registryEntity));
+ });
+
+ var registriesGrid = $('#registries-table').data('gridInstance');
+ var registriesData = registriesGrid.getData();
+
+ // update the registries
+ registriesData.setItems(registries);
+ registriesData.reSort();
+ registriesGrid.invalidate();
+ });
+ };
+
+ /**
+ * Loads the distribution environments.
+ */
+ var loadDistributionEnvironments = function(){
+ console.log("in loadDistributionEnvironments.. ");
+ return $.ajax({
+ type: 'GET',
+ url: dcaeDistributorApiHostname+'/distribution-targets',
+ dataType: 'json'
+ }).done(function (response) {
+ console.log(response);
+ var environments = [];
+ $.each(response.distributionTargets, function (_, environmentEntity) {
+ console.log(environmentEntity);
+ environments.push($.extend({
+ type: 'Environment'
+ }, environmentEntity));
+ });
+
+ console.log(environments);
+ var environmentsGrid = $('#distribution-environments-table').data('gridInstance');
+ console.log(environmentsGrid);
+ var environmentsData = environmentsGrid.getData();
+
+ // update the distribution environments
+ environmentsData.setItems(environments);
+ environmentsData.reSort();
+ environmentsGrid.invalidate();
+ });
+ };
+
+ /**
+ * Shows the process group configuration.
+ */
+ var showSettings = function () {
+ // show the settings dialog
+ nfShell.showContent('#settings').done(function () {
+ reset();
+ });
+
+ //reset content to account for possible policy changes
+ $('#settings-tabs').find('.selected-tab').click();
+
+ // adjust the table size
+ nfSettings.resetTableSize();
+ };
+
+ /**
+ * Reset state of this dialog.
+ */
+ var reset = function () {
+ // reset button state
+ $('#settings-save').mouseout();
+ };
+
+ var nfSettings = {
+ /**
+ * Initializes the settings page.
+ */
+ init: function () {
+ // initialize the settings tabs
+ $('#settings-tabs').tabbs({
+ tabStyle: 'tab',
+ selectedTabStyle: 'selected-tab',
+ scrollableTabContentStyle: 'scrollable',
+ tabs: [{
+ name: 'General',
+ tabContentId: 'general-settings-tab-content'
+ }, {
+ name: 'Reporting Task Controller Services',
+ tabContentId: 'controller-services-tab-content'
+ }, {
+ name: 'Reporting Tasks',
+ tabContentId: 'reporting-tasks-tab-content'
+ }, {
+ name: 'Registry Clients',
+ tabContentId: 'registries-tab-content'
+ },{
+ name: 'Distribution Target Environments',
+ tabContentId: 'distribution-environment-content'
+ }
+ ],
+ select: function () {
+ var tab = $(this).text();
+ if (tab === 'General') {
+ $('#controller-cs-availability').hide();
+ $('#new-service-or-task').hide();
+ $('#settings-save').show();
+ } else {
+ var canModifyController = false;
+ if (nfCommon.isDefinedAndNotNull(nfCommon.currentUser)) {
+ // only consider write permissions for creating new controller services/reporting tasks
+ canModifyController = nfCommon.currentUser.controllerPermissions.canWrite === true;
+ }
+
+ if (canModifyController) {
+ $('#new-service-or-task').show();
+ $('div.controller-settings-table').css('top', '32px');
+
+ // update the tooltip on the button
+ $('#new-service-or-task').attr('title', function () {
+ if (tab === 'Reporting Task Controller Services') {
+ $('#settings-save').hide();
+ return 'Create a new reporting task controller service';
+ } else if (tab === 'Reporting Tasks') {
+ $('#settings-save').hide();
+ return 'Create a new reporting task';
+ } else if (tab === 'Registry Clients') {
+ $('#settings-save').hide();
+ return 'Register a new registry client';
+ }else if (tab === 'Distribution Target Environments') {
+ console.log("in env tab...");
+ $('#settings-save').hide();
+ return 'Add a new distribution environment';
+ }
+ });
+ } else {
+ $('#new-service-or-task').hide();
+ $('div.controller-settings-table').css('top', '0');
+ }
+
+ if (tab === 'Reporting Task Controller Services') {
+ $('#controller-cs-availability').show();
+ } else if (tab === 'Reporting Tasks' || tab === 'Registry Clients'|| tab === 'Distribution Target Environments') {
+ $('#controller-cs-availability').hide();
+ }
+
+ // resize the table
+ nfSettings.resetTableSize();
+ }
+ }
+ });
+
+ // settings refresh button
+ $('#settings-refresh-button').click(function () {
+ loadSettings();
+ });
+
+ // create a new controller service or reporting task
+ $('#new-service-or-task').on('click', function () {
+ console.log("on Add Buttton clicked");
+ var selectedTab = $('#settings-tabs li.selected-tab').text();
+ if (selectedTab === 'Reporting Task Controller Services') {
+ var controllerServicesUri = config.urls.api + '/controller/controller-services';
+ nfControllerServices.promptNewControllerService(controllerServicesUri, getControllerServicesTable());
+ } else if (selectedTab === 'Reporting Tasks') {
+ $('#new-reporting-task-dialog').modal('show');
+
+ var reportingTaskTypesGrid = $('#reporting-task-types-table').data('gridInstance');
+ if (nfCommon.isDefinedAndNotNull(reportingTaskTypesGrid)) {
+ var reportingTaskTypesData = reportingTaskTypesGrid.getData();
+
+ // reset the canvas size after the dialog is shown
+ reportingTaskTypesGrid.resizeCanvas();
+
+ // select the first row if possible
+ if (reportingTaskTypesData.getLength() > 0) {
+ nfFilteredDialogCommon.choseFirstRow(reportingTaskTypesGrid);
+ }
+ }
+
+ // set the initial focus
+ $('#reporting-task-type-filter').focus();
+ } else if (selectedTab === 'Registry Clients') {
+ $('#registry-configuration-dialog').modal('setHeaderText', 'Add Registry Client').modal('setButtonModel', [{
+ buttonText: 'Add',
+ color: {
+ base: '#728E9B',
+ hover: '#004849',
+ text: '#ffffff'
+ },
+ handler: {
+ click: function () {
+ addRegistry();
+ }
+ }
+ }, {
+ buttonText: 'Cancel',
+ color: {
+ base: '#E3E8EB',
+ hover: '#C7D2D7',
+ text: '#004849'
+ },
+ handler: {
+ click: function () {
+ $(this).modal('hide');
+ }
+ }
+ }]).modal('show');
+
+ // set the initial focus
+ $('#registry-name').focus();
+ } else if (selectedTab === 'Distribution Target Environments') {
+ $('#distribution-environment-dialog').modal('setHeaderText', 'Add New Environment').modal('setButtonModel', [{
+ buttonText: 'Add',
+ color: {
+ base: '#728E9B',
+ hover: '#004849',
+ text: '#ffffff'
+ },
+ handler: {
+ click: function () {
+ addDistributionEnvironment();
+ }
+ }
+ }, {
+ buttonText: 'Cancel',
+ color: {
+ base: '#E3E8EB',
+ hover: '#C7D2D7',
+ text: '#004849'
+ },
+ handler: {
+ click: function () {
+ $(this).modal('hide');
+ }
+ }
+ }]).modal('show');
+
+ $(window).resize(function() {
+ var x=0;
+ console.log(x);
+ $("#distribution-environment-content").text(x= x + 1);
+ });
+
+ $(window).resize(function() {
+ var x=0;
+ console.log(x);
+ $("#distribution-environments-table").text(x= x + 1);
+ console.log(x);
+ console.log("resizing...table...");
+ });
+ // set the initial focus
+ $('#distribution-environment-name').focus();
+ }
+ });
+
+ // initialize each tab
+ initGeneral();
+ nfControllerServices.init(getControllerServicesTable(), nfSettings.showSettings);
+ initReportingTasks();
+ initRegistriesTable();
+ initDistributionEnvironmentsTable();
+ },
+
+ /**
+ * Update the size of the grid based on its container's current size.
+ */
+ resetTableSize: function () {
+ nfControllerServices.resetTableSize(getControllerServicesTable());
+ nfControllerServices.resetTableSize(getDistributionEnvironmentsTable());
+
+ var reportingTasksGrid = $('#reporting-tasks-table').data('gridInstance');
+ if (nfCommon.isDefinedAndNotNull(reportingTasksGrid)) {
+ reportingTasksGrid.resizeCanvas();
+ }
+ },
+
+ /**
+ * Shows the settings dialog.
+ */
+ showSettings: function () {
+ return loadSettings().done(showSettings);
+ },
+
+ /**
+ * Loads the settings dialogs.
+ */
+ loadSettings: function () {
+ return loadSettings();
+ },
+
+ /**
+ * Selects the specified controller service.
+ *
+ * @param {string} controllerServiceId
+ */
+ selectControllerService: function (controllerServiceId) {
+ var controllerServiceGrid = getControllerServicesTable().data('gridInstance');
+ var controllerServiceData = controllerServiceGrid.getData();
+
+ // select the desired service
+ var row = controllerServiceData.getRowById(controllerServiceId);
+ nfFilteredDialogCommon.choseRow(controllerServiceGrid, row);
+ controllerServiceGrid.scrollRowIntoView(row);
+
+ // select the controller services tab
+ $('#settings-tabs').find('li:eq(1)').click();
+ },
+
+ /**
+ * Selects the specified reporting task.
+ *
+ * @param {string} reportingTaskId
+ */
+ selectReportingTask: function (reportingTaskId) {
+ var reportingTaskGrid = $('#reporting-tasks-table').data('gridInstance');
+ var reportingTaskData = reportingTaskGrid.getData();
+
+ // select the desired service
+ var row = reportingTaskData.getRowById(reportingTaskId);
+ nfFilteredDialogCommon.choseRow(reportingTaskGrid, row);
+ reportingTaskGrid.scrollRowIntoView(row);
+
+ // select the controller services tab
+ $('#settings-tabs').find('li:eq(2)').click();
+ },
+
+ /**
+ * Sets the controller service and reporting task bulletins in their respective tables.
+ *
+ * @param {object} controllerServiceBulletins
+ * @param {object} reportingTaskBulletins
+ */
+ setBulletins: function (controllerServiceBulletins, reportingTaskBulletins) {
+ if ($('#controller-services-table').data('gridInstance')) {
+ nfControllerServices.setBulletins(getControllerServicesTable(), controllerServiceBulletins);
+ }
+
+ // reporting tasks
+ var reportingTasksGrid = $('#reporting-tasks-table').data('gridInstance');
+ var reportingTasksData = reportingTasksGrid.getData();
+ reportingTasksData.beginUpdate();
+
+ // if there are some bulletins process them
+ if (!nfCommon.isEmpty(reportingTaskBulletins)) {
+ var reportingTaskBulletinsBySource = d3.nest()
+ .key(function (d) {
+ return d.sourceId;
+ })
+ .map(reportingTaskBulletins, d3.map);
+
+ reportingTaskBulletinsBySource.each(function (sourceBulletins, sourceId) {
+ var reportingTask = reportingTasksData.getItemById(sourceId);
+ if (nfCommon.isDefinedAndNotNull(reportingTask)) {
+ reportingTasksData.updateItem(sourceId, $.extend(reportingTask, {
+ bulletins: sourceBulletins
+ }));
+ }
+ });
+ } else {
+ // if there are no bulletins clear all
+ var reportingTasks = reportingTasksData.getItems();
+ $.each(reportingTasks, function (_, reportingTask) {
+ reportingTasksData.updateItem(reportingTask.id, $.extend(reportingTask, {
+ bulletins: []
+ }));
+ });
+ }
+ reportingTasksData.endUpdate();
+ }
+ };
+
+ return nfSettings;
+}));