diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml index 77c7023610..8610087831 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml @@ -541,6 +541,7 @@ ${staging.dir}/js/nf/canvas/nf-controller-service.js ${staging.dir}/js/nf/canvas/nf-controller-services.js ${staging.dir}/js/nf/canvas/nf-reporting-task.js + ${staging.dir}/js/nf/canvas/nf-parameter-provider.js ${staging.dir}/js/nf/canvas/nf-settings.js ${staging.dir}/js/nf/canvas/controllers/nf-ng-breadcrumbs-controller.js ${staging.dir}/js/nf/canvas/controllers/nf-ng-canvas-header-controller.js @@ -734,6 +735,7 @@ ${project.build.directory}/${project.build.finalName}/css/nf-canvas-all.css ${staging.dir}/css/reporting-task.css + ${staging.dir}/css/parameter-provider.css ${staging.dir}/css/controller-service.css ${staging.dir}/css/processor-configuration.css ${staging.dir}/css/processor-details.css @@ -753,6 +755,7 @@ ${staging.dir}/css/new-port-dialog.css ${staging.dir}/css/new-controller-service-dialog.css ${staging.dir}/css/new-reporting-task-dialog.css + ${staging.dir}/css/new-parameter-provider-dialog.css ${staging.dir}/css/new-parameter-context-dialog.css ${staging.dir}/css/graph.css ${staging.dir}/css/header.css diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/filters/canvas.properties b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/filters/canvas.properties index ae9b533d2b..664389c0b7 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/filters/canvas.properties +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/filters/canvas.properties @@ -71,6 +71,7 @@ nf.canvas.script.tags=\n\ \n\ \n\ +\n\ \n\ \n\ \n\ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/canvas.jsp b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/canvas.jsp index 7a017e3986..f9459225f8 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/canvas.jsp +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/canvas.jsp @@ -110,8 +110,10 @@ + + @@ -141,6 +143,7 @@ + diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/fetch-parameters-dialog.jsp b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/fetch-parameters-dialog.jsp new file mode 100644 index 0000000000..9872d7f7af --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/fetch-parameters-dialog.jsp @@ -0,0 +1,204 @@ +<%-- + 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. +--%> +<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %> + diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-parameter-context-dialog.jsp b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-parameter-context-dialog.jsp index c788921fdf..b7bcb2ee34 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-parameter-context-dialog.jsp +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-parameter-context-dialog.jsp @@ -28,6 +28,7 @@
+
Name
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-parameter-provider-dialog.jsp b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-parameter-provider-dialog.jsp new file mode 100644 index 0000000000..fc0acb6d0b --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-parameter-provider-dialog.jsp @@ -0,0 +1,61 @@ +<%-- + 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. +--%> +<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %> + diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/parameter-provider-configuration.jsp b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/parameter-provider-configuration.jsp new file mode 100644 index 0000000000..0b23b869fc --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/parameter-provider-configuration.jsp @@ -0,0 +1,82 @@ +<%-- + 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. +--%> +<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %> + +
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/policy-management.jsp b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/policy-management.jsp index 024c7ba5f7..28a3c74c3a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/policy-management.jsp +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/policy-management.jsp @@ -84,6 +84,16 @@
+
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/settings-content.jsp b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/settings-content.jsp index 57f43c650c..4b19da272d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/settings-content.jsp +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/settings-content.jsp @@ -65,6 +65,9 @@
+
+
+
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/canvas.css b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/canvas.css index 8159795426..a9de76f303 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/canvas.css +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/canvas.css @@ -23,6 +23,7 @@ @import url(controller-service.css); @import url(component-state.css); @import url(reporting-task.css); +@import url(parameter-provider.css); @import url(port-configuration.css); @import url(port-details.css); @import url(label-configuration.css); @@ -34,6 +35,7 @@ @import url(new-port-dialog.css); @import url(new-controller-service-dialog.css); @import url(new-reporting-task-dialog.css); +@import url(new-parameter-provider-dialog.css); @import url(new-parameter-context-dialog.css); @import url(graph.css); @import url(header.css); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/dialog.css b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/dialog.css index e28d68088e..2baa79bf27 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/dialog.css +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/dialog.css @@ -478,7 +478,9 @@ div.variable-step { margin-bottom: 2px; } -div.parameter-context-step, div.referencing-components-loading { +div.parameter-context-step, +div.referencing-components-loading, +div.fetch-parameters-step { min-width: 16px; width: 16px; height: 16px; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/new-parameter-provider-dialog.css b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/new-parameter-provider-dialog.css new file mode 100644 index 0000000000..6dbf19c0bc --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/new-parameter-provider-dialog.css @@ -0,0 +1,105 @@ +/* + * 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. + */ + +/* + New parameter provider dialog. +*/ + +#new-parameter-provider-dialog { + min-height:620px; + height: 620px; + width: 800px; + min-width: 760px; +} + +#parameter-provider-types-container { + padding: 0px; +} + +#parameter-provider-bundle-group-combo { + margin-right: 2px; +} + +#parameter-provider-description-container { + padding: 0px; +} + +#parameter-provider-type-container { + padding: 20px 0 5px 0; + display: flex; +} + +#parameter-provider-type-name { + color: #775351; + font-size: 16px; + font-weight: 500; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +#parameter-provider-type-bundle { + margin-left: 15px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + font-size: 13px; + line-height: 16px; + color: #666; + letter-spacing: 0.25px; + min-width: 0; +} + +#parameter-provider-type-description { + height: 80px; + font-size: 13px; + line-height: 17px; + padding-top: 10px; +} + +#parameter-provider-types-table { + min-height: 150px; + overflow: hidden; + height: 70%; + width: 100%; +} + +#parameter-provider-types-table-container th { + vertical-align: middle; +} + +#parameter-provider-types-table div.slick-viewport { + overflow-x: hidden !important; +} + +/* + Processor type table filter +*/ + +#parameter-provider-type-filter-controls { + min-height: 32px; + padding: 0px; + margin: 0px; +} + +#parameter-provider-type-filter { + width: 200px; +} + +#parameter-provider-tag-cloud { + margin-top: -2px; +} \ No newline at end of file diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/parameter-provider.css b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/parameter-provider.css new file mode 100644 index 0000000000..368ddb433b --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/parameter-provider.css @@ -0,0 +1,496 @@ +/* + * 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. + */ + +/* + Parameter provider configuration styles. +*/ + +#parameter-provider-configuration { + position: absolute; + overflow: hidden; + width: 800px; + height: 450px; + font-size: 10px; + z-index: 1301; + display: none; +} + +#parameter-provider-configuration-advanced { + display: none; +} + +#parameter-provider-configuration div.configuration-tab { + display: none; +} + +.parameter-provider-editable.setting-field { + height: 32px; +} + +#parameter-provider-referencing-components { + padding: 2px; +} + +/* parameter-provider settings */ + +#parameter-provider-name { + width: 250px; + float: left; +} + +#parameter-provider-bundle { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +/* + Comments +*/ + +#parameter-provider-comments { + height: 100%; +} + +#read-only-parameter-provider-comments { + height: 100%; + white-space: pre-wrap; +} + +/* + Fetch parameters dialog +*/ + +#fetch-parameters-dialog { + position: absolute; + overflow: hidden; + min-width: 1048px; + height: 62%; + font-size: 10px; + z-index: 1301; + display: none; +} + +#fetch-parameters-dialog .dialog-content { + bottom: 48px; +} + +#fetch-parameters-dialog div.create-parameter-context-label { + display: inline-block; + line-height: normal; +} + +#fetch-parameters-dialog .dialog-content div.settings-left { + float: left; + width: 33%; +} + +#fetch-parameters-dialog .dialog-content div.settings-center { + float: left; + width: 33%; +} + +#fetch-parameters-dialog .dialog-content div.settings-right { + float: left; + width: 30%; + height: 100%; + position: absolute; + left: calc(72% - 20px); +} + +#parameter-groups-table { + position: relative; + height: 300px; +} + +#fetch-parameters-referencing-components { + border: 0 solid #CCCCCC; + overflow: auto; + padding: 2px; +} + +#fetch-parameters-update-steps li { + width: 300px; + margin-bottom: 2px; +} + +#fetched-parameters-listing-container { + position: relative; + overflow-x: auto; + border: 0 solid #CCCCCC; + padding: 2px; + min-height: 100px; + max-height: 343px; + min-width: 150px; + max-width: 326px; +} + +#fetched-parameters-listing li, +#fetched-parameters-listing span { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; +} + +ol#fetched-parameters-listing ul { + padding-bottom: 4px; +} + +ul.fetched-parameters { + padding: 0 0 2px 0; + list-style-type: disc; +} + +div.referencing-component-block { + margin-bottom: 6px; +} + +span.referencing-component-title { + margin-left: 5px; + font-weight: bold +} + +span.referencing-component-count { + margin-left: 5px; + color: #aaa; +} + +ul.referencing-component-listing { + margin-left: 20px; + margin-bottom: 6px; +} + +ul.referencing-component-listing li { + margin-bottom: 6px; + white-space: nowrap; +} + +div.referencing-component-state { + width: 13px; +} + +div.referencing-component-state.disabled:before { + content: '\e802'; + font-family: flowfont; +} + +div.referencing-component-state.enabled:before { + content: '\f0e7'; + font-family: FontAwesome; +} + +div.referencing-component-bulletins { + float: left; + margin-left: 5px; + width: 12px; + height: 12px; + background-color: transparent; + display: none; +} + +div.referencing-component-bulletins:before { + font-family: FontAwesome; + content: "\f24a"; + font-size: 16px; + color: #004849; +} + +div.service.expansion-button { + float: left; + margin-right: 4px; + width: 10px; + height: 10px; +} + +span.referencing-component-active-thread-count { + margin-left: 5px; + float: left; +} + +span.referencing-component-name { + margin-left: 5px; + margin-right: 5px; +} + +span.referencing-component-type { + color: #aaa; + font-style: italic; +} + +div.referencing-component-references { + margin-left: 2px; + margin-top: 0; + clear: left; +} + +.fetch-parameters-referencing-components-template { + padding-left: 14px; +} + +div.fetch-parameters-canceling { + position: absolute; + bottom: 10px; + right: 8px; +} + +#fetch-parameters-name { + float: left; + max-width: 280px; + text-overflow: ellipsis; +} + +#fetch-parameters-bulletins { + float: left; + margin-left: 5px; + width: 12px; + height: 12px; + background-color: transparent; + display: none; +} + +#fetch-parameters-referencing-components { + border: 0 solid #CCCCCC; + padding: 2px; + overflow: auto; + white-space: nowrap; +} + +div.fetch-parameters-referencing-components { + width: 16px; + height: 16px; + background-color: transparent; + float: right; +} + +#fetch-parameters-progress { + margin-top: 2px; +} + +#fetch-parameters-progress li { + line-height: 16px; +} + +#affected-referencing-components-container, +#fetch-parameter-referencing-components-container { + position: absolute; + bottom: 10px; + top: 108px; + width: calc(100% - 6px); + overflow: auto; + border: 0 solid #CCCCCC; + padding: 2px; +} + +#affected-referencing-components-container div.referencing-component-references { + margin: 0; +} + +.affected-referencing-components-template { + position: relative; + left: 15px; + width: calc(100% - 15px); +} + +span.parameter-provider-referencing-component-name { + margin-left: 5px; + max-width: calc(100% - 30px); +} + +#checkbox-container { + display: flex; + flex-direction: row; + align-items: center; +} + +/* + Slickgrid selectable parameters table +*/ +#selectable-parameters-table { + position: absolute; + height: 267px; + width: 332px; +} + +#selectable-parameters-table .slick-cell-checkboxsel { + padding: 1px 2px 5px 4px; +} + +#selectable-parameters-table .slick-cell-checkboxsel.selected { + padding: 0px 2px 6px 4px; +} + +#selectable-parameters-table .slick-column-name input { + margin: 5px 3px 3px 4px; +} + +#selectable-parameters-table .slick-pane-left .slick-viewport { + overflow-x: hidden; +} + +#selectable-parameters-table input[type="checkbox"] { + margin-top: 2px; + width: 0; +} + +#selectable-parameters-table input[type="checkbox"]:focus { + box-shadow: none; + border: none; +} + +#selectable-parameters-table .slick-column-name input[type="checkbox"] { + margin-top: 5px; +} + +#selectable-parameters-table .slick-column-name input[checked="checked"]:before { + margin-top: 2px; +} + +#selectable-parameters-table input[type="checkbox"]:before { + content: url(../images/inputCheckbox.png); + cursor: pointer; + clip-path: polygon(0% -16%, 50% -16%, 50% 104%, 0% 104%); + position: absolute; + margin-left: 1px; + margin-top: 3px; +} + +#selectable-parameters-table input[checked="checked"]:before { + content: url(../images/inputCheckbox.png); + cursor: pointer; + clip-path: polygon(50% -16%, 100% -16%, 100% 116%, 50% 116%); + margin-left: -11px; + margin-top: 3px; +} + +#selectable-parameters-table input[type="checkbox"].disabled:before { + content: url(../images/inputCheckbox.png); + opacity: .5; + cursor: not-allowed; + clip-path: polygon(0% -16%, 50% -16%, 50% 104%, 0% 104%); + position: absolute; + margin-left: 1px; + margin-top: 3px; +} + +#selectable-parameters-table input[checked="checked"].disabled:before { + content: url(../images/inputCheckbox.png); + opacity: .5; + cursor: not-allowed; + clip-path: polygon(50% -16%, 100% -16%, 100% 116%, 50% 116%); + margin-left: -11px; + margin-top: 3px; +} + +#parameter-groups-table .slick-pane-top .slick-viewport-top .grid-canvas-top, +#selectable-parameters-table .slick-pane-top .slick-viewport .grid-canvas-top { + width: 100% !important; +} + +#selectable-parameters-table .slick-pane-top .slick-viewport-top .grid-canvas-top .slick-cell.l1 { + padding-top: 1px; +} + +#selectable-parameters-table .slick-pane-top .slick-viewport-top .slick-cell.l1:not(.selected) .table-cell { + margin-top: 5px; +} + +#fetched-parameters-listing .slick-cell-checkboxsel { + background: #f0f0f0; + border-right-color: silver; + border-right-style: solid; +} + +.slick-columnpicker { + border: 1px solid #718BB7; + background: #f0f0f0; + padding: 6px; + -moz-box-shadow: 2px 2px 2px silver; + -webkit-box-shadow: 2px 2px 2px silver; + box-shadow: 2px 2px 2px silver; + min-width: 100px; + cursor: default; +} + +.slick-columnpicker li { + list-style: none; + margin: 0; + padding: 0; + background: none; +} + +.slick-columnpicker input { + margin: 4px; +} + +.slick-columnpicker li a { + display: block; + padding: 4px; + font-weight: bold; +} + +.slick-columnpicker li a:hover { + background: white; +} + +#selectable-parameters-buttons { + position: relative; + padding-bottom: 4px; +} + +.selectable-parameters-buttons { + line-height: 30px; + border: 1px solid #CCDADB; + background-color: rgba(249,250,251,1); + color: #004849; + padding: 0 7px; + float: left; + width: inherit; + margin-right: 8px; + display: flex; + align-items: center; + flex-direction: row; +} + +.selectable-parameters-buttons span { + font-size: 12px; + text-transform: uppercase; +} + +.selectable-parameters-buttons .fa { + font-size: 14px; + margin-left: -2px; + margin-right: 4px; +} + +button.selectable-parameters-buttons:hover { + border: 1px solid #004849; +} + +#create-parameter-context-container { + line-height: 12px; +} + +.fetch-parameters-dialog-message { + position: absolute; + top: 537px; + left: 20px; + font-size: 13px; + line-height: normal; + color: #775351; + max-width: calc(100% - 230px); + z-index: 999; +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/statusbar/jquery.statusbar.css b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/statusbar/jquery.statusbar.css index c13f7c025d..ddff90653f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/statusbar/jquery.statusbar.css +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/statusbar/jquery.statusbar.css @@ -25,11 +25,12 @@ height : 32px; } -.dialog-status-bar[state] + .dialog-content { +.dialog-status-bar[state] + .dialog-content, +.dialog-status-bar[alerts] + .dialog-content { top: 104px; } -.dialog-status-bar:not([state]), +.dialog-status-bar:not([state]):not([alerts]), .dialog-status-bar:not([state]) text.run-status-icon, .dialog-status-bar-bulletins-content, .dialog-status-bar-bulletins[count="0"], @@ -123,11 +124,12 @@ float : right; margin-left : 22px; margin-top : 5px; - background-color : rgba(36,36,36,0.75); - font-family: Arial; + background-color: rgba(0, 0, 0, 0.80) !important; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.25); + font-family: Roboto; font-weight : bold; - font-size : 12px; - padding : 10px 10px 10px 20px; + font-size : 13px; + padding : 10px; width : auto; max-width : 490px; } @@ -138,4 +140,4 @@ .dialog-status-bar-buttons *.disabled-button { display:none; -} \ No newline at end of file +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/statusbar/jquery.statusbar.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/statusbar/jquery.statusbar.js index c16e314271..c7c9afa745 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/statusbar/jquery.statusbar.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/statusbar/jquery.statusbar.js @@ -27,8 +27,7 @@ // static key path variables var PROCESSOR_ID_KEY = 'component.id', ACTIVE_THREAD_COUNT_KEY = 'status.aggregateSnapshot.activeThreadCount', - RUN_STATUS_KEY = 'status.aggregateSnapshot.runStatus', - BULLETINS_KEY = 'bulletins'; + RUN_STATUS_KEY = 'status.aggregateSnapshot.runStatus' var isUndefined = function (obj) { return typeof obj === 'undefined'; @@ -52,18 +51,28 @@ /** * Initializes the status bar. + * + * @param type - the type of component or service for the status bus */ - init: function () { + init: function (type) { + // get the combo var bar = $(this).addClass('dialog-status-bar'); - bar.html(''+ - ''+ - ''+ - '
'+ - '
'+ - '
'+ - '
'); + if (type === 'processor') { + bar.html(''+ + ''+ + ''+ + '
'+ + '
'+ + '
'+ + '
'); + } else { // parameter provider + bar.html('
'+ + '
'+ + '
'); + } + return bar; }, @@ -93,28 +102,36 @@ /** * Initializes the synchronization process to the canvas element * - * @param id - id value of the processor to observe + * @param data - object of type or service to observe * @param cb - callback to execute when a mutation is detected */ - observe: function(id,cb) { + observe: function(data,cb) { var bar = $(this); - var g = document.querySelector('g[id="id-'+id+'"]'); - //perform the initial set - bar.statusbar('set',id); + if (data.processor) { + // id value of the processor to observe + var id = data.processor; + var g = document.querySelector('g[id="id-'+id+'"]'); - //create and store an observer - bar.data('observer',new MutationObserver(function(mutations){ - bar.statusbar('set',id); - if(typeof cb == 'function'){ - cb(); - } - })); + //perform the initial set + bar.statusbar('set', data); - //initialize the observer - bar.data('observer').observe(g,{attributes:true,childList:true,subtree:true}); + //create and store an observer + bar.data('observer',new MutationObserver(function(mutations){ + bar.statusbar('set',data); + if(typeof cb == 'function'){ + cb(); + } + })); - return bar.data('observer'); + //initialize the observer + bar.data('observer').observe(g,{attributes:true,childList:true,subtree:true}); + + return bar.data('observer'); + } else { // parameter provider bulletins + //perform the initial set + return bar.statusbar('set', data); + } }, /** @@ -240,38 +257,48 @@ /** * Set the status bar display values * - * @param id - processor id to evaluate + * @param data - object of type or service to set */ - set : function(id) { + set : function(data) { var bar = $(this), - obj = d3.select('#id-' + id).datum(), - bulletinList = $("
    "), - runStatus = getKeyValue(obj,RUN_STATUS_KEY), - activeThreadCount = getKeyValue(obj,ACTIVE_THREAD_COUNT_KEY), - bulletins = getKeyValue(obj,BULLETINS_KEY); + processorId, + obj, + runStatus, + activeThreadCount, + bulletins; - //set the values - if(isDefinedAndNotNull(runStatus) && - isDefinedAndNotNull(activeThreadCount) && - isDefinedAndNotNull(bulletins) && - Array.isArray(bulletins)) { + if (data.processor) { + processorId = data.processor; + obj = d3.select('#id-' + processorId).datum(); + runStatus = getKeyValue(obj,RUN_STATUS_KEY); + activeThreadCount = getKeyValue(obj,ACTIVE_THREAD_COUNT_KEY); + bulletins = data.bulletins; + } else if (data.provider) { + bulletins = data.provider; + } + // set the values + if (isDefinedAndNotNull(runStatus) && isDefinedAndNotNull(activeThreadCount)) { bar.attr('state',runStatus.toUpperCase()); + bar.attr('alerts', 'true'); bar.find('.dialog-status-bar-state').text(runStatus); bar.find('.dialog-status-bar-threads').attr('count',activeThreadCount); bar.find('.dialog-status-bar-threads').attr('title',activeThreadCount+' active threads'); bar.find('.dialog-status-bar-threads').text('('+activeThreadCount+')'); - $.each(bulletins, function(i,item){ - if(item.canRead){ - bulletinList.append($('
  • '+item.bulletin.timestamp+' '+item.bulletin.level+'
    '+item.bulletin.message+'
     
  • ')); - } - }); - var bulletinCount = bulletinList.find('li').length; - bar.find('.dialog-status-bar-bulletins-content').html((bulletinCount > 0)?bulletinList:''); + } + + // set the bulletins + if (isDefinedAndNotNull(bulletins)) { + var bulletinCount = bulletins.find('li').length; + bar.find('.dialog-status-bar-bulletins-content').html((bulletinCount > 0)?bulletins:''); bar.find('.dialog-status-bar-bulletins').attr('count',bulletinCount); - //update the button state - bar.statusbar('refreshButtons'); + if (data.processor) { + // update the button state + bar.statusbar('refreshButtons'); + } else { + bar.attr('alerts', 'true'); + } } return bar; } @@ -285,4 +312,4 @@ } }; -})(jQuery); \ No newline at end of file +})(jQuery); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-bootstrap.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-bootstrap.js index e51f3634a7..530893367d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-bootstrap.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-bootstrap.js @@ -49,6 +49,7 @@ 'nf.ConnectionConfiguration', 'nf.ControllerService', 'nf.ReportingTask', + 'nf.ParameterProvider', 'nf.PolicyManagement', 'nf.ProcessorConfiguration', 'nf.ProcessGroupConfiguration', @@ -84,8 +85,8 @@ 'nf.ng.Canvas.OperateCtrl', 'nf.ng.BreadcrumbsDirective', 'nf.ng.DraggableDirective'], - function ($, angular, nfCommon, nfCanvasUtils, nfErrorHandler, nfClient, nfDialog, nfStorage, nfCanvas, nfGraph, nfContextMenu, nfQuickSelect, nfShell, nfParameterContexts, nfSettings, nfActions, nfSnippet, nfQueueListing, nfVerify, nfVariableRegistry, nfComponentState, nfFlowVersion, nfComponentVersion, nfDraggable, nfConnectable, nfStatusHistory, nfBirdseye, nfConnectionConfiguration, nfControllerService, nfReportingTask, nfPolicyManagement, nfProcessorConfiguration, nfProcessGroupConfiguration, nfControllerServices, nfRemoteProcessGroupConfiguration, nfRemoteProcessGroupPorts, nfPortConfiguration, nfLabelConfiguration, nfProcessorDetails, nfPortDetails, nfConnectionDetails, nfRemoteProcessGroupDetails, nfGoto, nfNgBridge, appCtrl, appConfig, serviceProvider, breadcrumbsCtrl, headerCtrl, flowStatusCtrl, globalMenuCtrl, toolboxCtrl, processorComponent, inputPortComponent, outputPortComponent, processGroupComponent, remoteProcessGroupComponent, funnelComponent, templateComponent, labelComponent, graphControlsCtrl, navigateCtrl, operateCtrl, breadcrumbsDirective, draggableDirective) { - return factory($, angular, nfCommon, nfCanvasUtils, nfErrorHandler, nfClient, nfDialog, nfStorage, nfCanvas, nfGraph, nfContextMenu, nfQuickSelect, nfShell, nfParameterContexts, nfSettings, nfActions, nfSnippet, nfQueueListing, nfVerify, nfVariableRegistry, nfComponentState, nfFlowVersion, nfComponentVersion, nfDraggable, nfConnectable, nfStatusHistory, nfBirdseye, nfConnectionConfiguration, nfControllerService, nfReportingTask, nfPolicyManagement, nfProcessorConfiguration, nfProcessGroupConfiguration, nfControllerServices, nfRemoteProcessGroupConfiguration, nfRemoteProcessGroupPorts, nfPortConfiguration, nfLabelConfiguration, nfProcessorDetails, nfPortDetails, nfConnectionDetails, nfRemoteProcessGroupDetails, nfGoto, nfNgBridge, appCtrl, appConfig, serviceProvider, breadcrumbsCtrl, headerCtrl, flowStatusCtrl, globalMenuCtrl, toolboxCtrl, processorComponent, inputPortComponent, outputPortComponent, processGroupComponent, remoteProcessGroupComponent, funnelComponent, templateComponent, labelComponent, graphControlsCtrl, navigateCtrl, operateCtrl, breadcrumbsDirective, draggableDirective); + function ($, angular, nfCommon, nfCanvasUtils, nfErrorHandler, nfClient, nfDialog, nfStorage, nfCanvas, nfGraph, nfContextMenu, nfQuickSelect, nfShell, nfParameterContexts, nfSettings, nfActions, nfSnippet, nfQueueListing, nfVerify, nfVariableRegistry, nfComponentState, nfFlowVersion, nfComponentVersion, nfDraggable, nfConnectable, nfStatusHistory, nfBirdseye, nfConnectionConfiguration, nfControllerService, nfReportingTask, nfParameterProvider, nfPolicyManagement, nfProcessorConfiguration, nfProcessGroupConfiguration, nfControllerServices, nfRemoteProcessGroupConfiguration, nfRemoteProcessGroupPorts, nfPortConfiguration, nfLabelConfiguration, nfProcessorDetails, nfPortDetails, nfConnectionDetails, nfRemoteProcessGroupDetails, nfGoto, nfNgBridge, appCtrl, appConfig, serviceProvider, breadcrumbsCtrl, headerCtrl, flowStatusCtrl, globalMenuCtrl, toolboxCtrl, processorComponent, inputPortComponent, outputPortComponent, processGroupComponent, remoteProcessGroupComponent, funnelComponent, templateComponent, labelComponent, graphControlsCtrl, navigateCtrl, operateCtrl, breadcrumbsDirective, draggableDirective) { + return factory($, angular, nfCommon, nfCanvasUtils, nfErrorHandler, nfClient, nfDialog, nfStorage, nfCanvas, nfGraph, nfContextMenu, nfQuickSelect, nfShell, nfParameterContexts, nfSettings, nfActions, nfSnippet, nfQueueListing, nfVerify, nfVariableRegistry, nfComponentState, nfFlowVersion, nfComponentVersion, nfDraggable, nfConnectable, nfStatusHistory, nfBirdseye, nfConnectionConfiguration, nfControllerService, nfReportingTask, nfParameterProvider, nfPolicyManagement, nfProcessorConfiguration, nfProcessGroupConfiguration, nfControllerServices, nfRemoteProcessGroupConfiguration, nfRemoteProcessGroupPorts, nfPortConfiguration, nfLabelConfiguration, nfProcessorDetails, nfPortDetails, nfConnectionDetails, nfRemoteProcessGroupDetails, nfGoto, nfNgBridge, appCtrl, appConfig, serviceProvider, breadcrumbsCtrl, headerCtrl, flowStatusCtrl, globalMenuCtrl, toolboxCtrl, processorComponent, inputPortComponent, outputPortComponent, processGroupComponent, remoteProcessGroupComponent, funnelComponent, templateComponent, labelComponent, graphControlsCtrl, navigateCtrl, operateCtrl, breadcrumbsDirective, draggableDirective); }); } else if (typeof exports === 'object' && typeof module === 'object') { module.exports = factory(require('jquery'), @@ -118,6 +119,7 @@ require('nf.ConnectionConfiguration'), require('nf.ControllerService'), require('nf.ReportingTask'), + require('nf.ParameterProvider'), require('nf.PolicyManagement'), require('nf.ProcessorConfiguration'), require('nf.ProcessGroupConfiguration'), @@ -184,6 +186,7 @@ root.nf.ConnectionConfiguration, root.nf.ControllerService, root.nf.ReportingTask, + root.nf.ParameterProvider, root.nf.PolicyManagement, root.nf.ProcessorConfiguration, root.nf.ProcessGroupConfiguration, @@ -220,7 +223,7 @@ root.nf.ng.BreadcrumbsDirective, root.nf.ng.DraggableDirective); } -}(this, function ($, angular, nfCommon, nfCanvasUtils, nfErrorHandler, nfClient, nfDialog, nfStorage, nfCanvas, nfGraph, nfContextMenu, nfQuickSelect, nfShell, nfParameterContexts, nfSettings, nfActions, nfSnippet, nfQueueListing, nfVerify, nfVariableRegistry, nfComponentState, nfFlowVersion, nfComponentVersion, nfDraggable, nfConnectable, nfStatusHistory, nfBirdseye, nfConnectionConfiguration, nfControllerService, nfReportingTask, nfPolicyManagement, nfProcessorConfiguration, nfProcessGroupConfiguration, nfControllerServices, nfRemoteProcessGroupConfiguration, nfRemoteProcessGroupPorts, nfPortConfiguration, nfLabelConfiguration, nfProcessorDetails, nfPortDetails, nfConnectionDetails, nfRemoteProcessGroupDetails, nfGoto, nfNgBridge, appCtrl, appConfig, serviceProvider, breadcrumbsCtrl, headerCtrl, flowStatusCtrl, globalMenuCtrl, toolboxCtrl, processorComponent, inputPortComponent, outputPortComponent, processGroupComponent, remoteProcessGroupComponent, funnelComponent, templateComponent, labelComponent, graphControlsCtrl, navigateCtrl, operateCtrl, breadcrumbsDirective, draggableDirective) { +}(this, function ($, angular, nfCommon, nfCanvasUtils, nfErrorHandler, nfClient, nfDialog, nfStorage, nfCanvas, nfGraph, nfContextMenu, nfQuickSelect, nfShell, nfParameterContexts, nfSettings, nfActions, nfSnippet, nfQueueListing, nfVerify, nfVariableRegistry, nfComponentState, nfFlowVersion, nfComponentVersion, nfDraggable, nfConnectable, nfStatusHistory, nfBirdseye, nfConnectionConfiguration, nfControllerService, nfReportingTask, nfParameterProvider, nfPolicyManagement, nfProcessorConfiguration, nfProcessGroupConfiguration, nfControllerServices, nfRemoteProcessGroupConfiguration, nfRemoteProcessGroupPorts, nfPortConfiguration, nfLabelConfiguration, nfProcessorDetails, nfPortDetails, nfConnectionDetails, nfRemoteProcessGroupDetails, nfGoto, nfNgBridge, appCtrl, appConfig, serviceProvider, breadcrumbsCtrl, headerCtrl, flowStatusCtrl, globalMenuCtrl, toolboxCtrl, processorComponent, inputPortComponent, outputPortComponent, processGroupComponent, remoteProcessGroupComponent, funnelComponent, templateComponent, labelComponent, graphControlsCtrl, navigateCtrl, operateCtrl, breadcrumbsDirective, draggableDirective) { var config = { urls: { @@ -349,7 +352,7 @@ nfShell.init(nfContextMenu); nfNgBridge.injector.get('headerCtrl').init(); nfSettings.init(); - nfParameterContexts.init(); + nfParameterContexts.init(nfParameterProvider); nfActions.init(); nfQueueListing.init(); nfVerify.init(); @@ -370,8 +373,14 @@ // initialize the connection config and invert control of the birdseye and graph nfConnectionConfiguration.init(nfBirdseye, nfGraph, configDetails.defaultBackPressureObjectThreshold, configDetails.defaultBackPressureDataSizeThreshold); - nfControllerService.init(nfControllerServices, nfReportingTask); + nfControllerService.init(nfControllerServices, nfReportingTask, nfParameterProvider); nfReportingTask.init(nfSettings); + nfParameterProvider.init({ + nfSettings: nfSettings, + statusBarOptions: { + supportsStatusBar : true + } + }); nfPolicyManagement.init(); nfProcessorConfiguration.init({ supportsStatusBar : true, diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-service.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-service.js index 086f31f7ff..72d37daa22 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-service.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-service.js @@ -68,7 +68,9 @@ }(this, function ($, d3, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfSettings, nfUniversalCapture, nfCustomUi, nfVerify, nfCanvasUtils, nfProcessor) { 'use strict'; - var nfControllerServices, nfReportingTask; + var nfControllerServices, + nfReportingTask, + nfParameterProvider; var config = { edit: 'edit', @@ -251,6 +253,15 @@ if (referencingComponentState.length) { updateReferencingSchedulableComponentState(referencingComponentState, reference); } + } else if (reference.referenceType === 'ParameterProvider') { + // reload + nfParameterProvider.reload(reference.id); + + // update the validation errors of this parameter provider + var referencingComponentState = $('div.' + reference.id + '-state'); + if (referencingComponentState.length) { + updateValidationErrors(referencingComponentState, reference); + } } else { // reload the referencing services reloadControllerService(serviceTable, reference.id); @@ -391,6 +402,42 @@ }); }; + /** + * Updates validation errors. This is used for parameter providers and registry clients. + * + * @param validationErrorIcon + * @param referencingComponent + */ + var updateValidationErrors = function (validationErrorIcon, referencingComponent) { + var currentValidationErrors = validationErrorIcon.data('validation-errors'); + + // update the validation errors if necessary + if (!_.isEqual(currentValidationErrors, referencingComponent.validationErrors)) { + validationErrorIcon.data('validation-errors', referencingComponent.validationErrors); + + // if there are validation errors update them + if (!nfCommon.isEmpty(referencingComponent.validationErrors)) { + var list = nfCommon.formatUnorderedList(referencingComponent.validationErrors); + + // update existing tooltip or initialize a new one if appropriate + if (validationErrorIcon.data('qtip')) { + validationErrorIcon.qtip('option', 'content.text', list); + } else { + validationErrorIcon.show().qtip($.extend({}, + nfCanvasUtils.config.systemTooltipConfig, + { + content: list + })); + } + } else { + if (validationErrorIcon.data('qtip')) { + validationErrorIcon.removeData('validation-errors').qtip('api').destroy(true); + } + validationErrorIcon.hide(); + } + } + }; + /** * Updates the bulletins for all referencing components. * @@ -444,6 +491,7 @@ var processors = $('
      '); var services = $('
        '); var tasks = $('
          '); + var providers = $('
            '); var unauthorized = $('
              '); $.each(referencingComponents, function (_, referencingComponentEntity) { // check the access policy for this referencing component @@ -582,6 +630,46 @@ // reporting task var reportingTaskItem = $('
            • ').append(reportingTaskState).append(reportingTaskBulletins).append(reportingTaskLink).append(reportingTaskType).append(reportingTaskActiveThreadCount); tasks.append(reportingTaskItem); + } else if (referencingComponent.referenceType === 'ParameterProvider') { + var parameterProviderLink = $('').text(referencingComponent.name).on('click', function () { + var parameterProvidersGrid = $('#parameter-providers-table').data('gridInstance'); + var parameterProvidersData = parameterProvidersGrid.getData(); + + // select the selected row + var row = parameterProvidersData.getRowById(referencingComponent.id); + parameterProvidersGrid.setSelectedRows([row]); + parameterProvidersGrid.scrollRowIntoView(row); + + // close the dialog and shell + referenceContainer.closest('.dialog').modal('hide'); + + $('#settings-tabs').find('li:eq(4)').click(); + + // adjust the table size + parameterProvidersGrid.resizeCanvas(); + }); + + // provider state - used to show the validation errors + var providerState = $('
              ').addClass(referencingComponent.id + '-state'); + if (nfCommon.isEmpty(referencingComponent.validationErrors)) { + providerState.hide(); + } else { + updateValidationErrors(providerState, referencingComponent); + } + + // bulletin + var providerBulletins = $('
              ').addClass(referencingComponent.id + '-bulletins'); + if (!nfCommon.isEmpty(referencingComponentEntity.bulletins)) { + updateBulletins(referencingComponentEntity.bulletins, providerBulletins); + } + + // type + var providerType = $('').text(referencingComponent.type); + + // parameter provider + var providerItem = $('
            • ').append(providerState).append(providerBulletins).append(parameterProviderLink).append(providerType); + + providers.append(providerItem); } } }); @@ -614,6 +702,7 @@ createReferenceBlock('Processors', processors); createReferenceBlock('Reporting Tasks', tasks); createReferenceBlock('Controller Services', services); + createReferenceBlock('Parameter Providers', providers); createReferenceBlock('Unauthorized', unauthorized); // now that the dom elements are in place, we can show the bulletin icons. @@ -734,7 +823,7 @@ referencingComponentRevisions[referencingComponentEntity.id] = nfClient.getRevision(referencingComponentEntity); } } else { - if (referencingComponent.referenceType !== 'ControllerService') { + if (referencingComponent.referenceType === 'Processor' || referencingComponent.referenceType === 'ReportingTask') { referencingComponentRevisions[referencingComponentEntity.id] = nfClient.getRevision(referencingComponentEntity); } } @@ -948,7 +1037,7 @@ var referencingComponents = service.referencingComponents; $.each(referencingComponents, function (_, referencingComponentEntity) { var referencingComponent = referencingComponentEntity.component; - if (referencingComponent.referenceType === 'Processor' || referencingComponent.referenceType === 'ReportingTask') { + if (referencingComponent.referenceType === 'Processor' || referencingComponent.referenceType === 'ReportingTask' || referencingComponent.referenceType === 'ParameterProvider') { referencingSchedulableComponents.push(referencingComponent.id); } }); @@ -1753,9 +1842,10 @@ /** * Initializes the controller service configuration dialog. */ - init: function (nfControllerServicesRef, nfReportingTaskRef) { + init: function (nfControllerServicesRef, nfReportingTaskRef, nfParameterProviderRef) { nfControllerServices = nfControllerServicesRef; nfReportingTask = nfReportingTaskRef; + nfParameterProvider = nfParameterProviderRef; // initialize the configuration dialog tabs $('#controller-service-configuration-tabs').tabbs({ @@ -1862,7 +1952,7 @@ } } }); - + // initialize the bulletin combo $('#controller-service-bulletin-level-combo').combo({ options: [{ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-parameter-contexts.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-parameter-contexts.js index 62b972196b..6b4bfc30c6 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-parameter-contexts.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-parameter-contexts.js @@ -86,6 +86,8 @@ }(this, function ($, Slick, d3, nfClient, nfDialog, nfStorage, nfCommon, nfCanvasUtils, nfNgBridge, nfErrorHandler, nfFilteredDialogCommon, nfShell, nfComponentState, nfComponentVersion, nfPolicyManagement, nfProcessor, nfProcessGroup, nfProcessGroupConfiguration, _) { 'use strict'; + var nfParameterProvider; + var config = { urls: { parameterContexts: '../nifi-api/parameter-contexts' @@ -132,6 +134,29 @@ return nfCommon.escapeHtml(dataContext.component.name); }; + /** + * Formatter for the provider column. + * + * @param {type} row + * @param {type} cell + * @param {type} value + * @param {type} columnDef + * @param {type} dataContext + * @returns {String} + */ + var providerFormatter = function (row, cell, value, columnDef, dataContext) { + var component = dataContext.component ? dataContext.component : null; + + if (component && component.parameterProviderConfiguration) { + if (!dataContext.permissions.canRead) { + return '' + nfCommon.escapeHtml(component.parameterProviderConfiguration.id) + ''; + } + + return nfCommon.escapeHtml(component.parameterProviderConfiguration.component.parameterGroupName + + ' from ' + component.parameterProviderConfiguration.component.parameterProviderName); + } + }; + /** * Sorts the specified data using the specified sort details. * @@ -216,6 +241,8 @@ $('#parameter-process-group-id').text('').removeData('revision'); $('#parameter-referencing-components-context').removeClass('unset').attr('title', '').text(''); + $('#parameter-context-provider-setting').hide(); + var parameterGrid = $('#parameter-table').data('gridInstance'); var parameterData = parameterGrid.getData(); parameterGrid.setSelectedRows([]); @@ -1053,7 +1080,7 @@ referencingComponents: originalParameter.referencingComponents, previousValue: originalParameter.value, previousDescription: originalParameter.description, - isEditable: originalParameter.isEditable, + isEditable: originalParameter.isEditable || originalParameter.provided !== true, isEmptyStringSet: serializedParam.isEmptyStringSet, isNew: originalParameter.isNew, hasValueChanged: serializedParam.hasValueChanged, @@ -1086,12 +1113,11 @@ $('#parameter-context-dialog').modal('refreshButtons'); }; - var hasParameterContextChanged = function (parameterContextEntity) { - var parameters = marshalParameters(); var proposedParamContextName = $('#parameter-context-name').val(); var proposedParamContextDesc = $('#parameter-context-description-field').val(); var inheritedParameterContexts = marshalInheritedParameterContexts(); + var componentDescription = _.get(parameterContextEntity, 'component.description', ''); var inheritedParameterContextEquals = isInheritedParameterContextEquals(parameterContextEntity, inheritedParameterContexts); if (inheritedParameterContextEquals) { @@ -1100,15 +1126,23 @@ $('#inherited-parameter-contexts-message').removeClass('hidden'); } - if (_.isEmpty(parameters) && - proposedParamContextName === _.get(parameterContextEntity, 'component.name') && - proposedParamContextDesc === _.get(parameterContextEntity, 'component.description') && - inheritedParameterContextEquals) { - - return false; + if (parameterContextEntity.component.parameterProviderConfiguration) { + if (proposedParamContextName === _.get(parameterContextEntity, 'component.name') && + proposedParamContextDesc === componentDescription && + inheritedParameterContextEquals) { + return false; + } } else { - return true; + var parameters = marshalParameters(); + if (_.isEmpty(parameters) && + proposedParamContextName === _.get(parameterContextEntity, 'component.name') && + proposedParamContextDesc === _.get(parameterContextEntity, 'component.description') && + inheritedParameterContextEquals) { + return false; + } } + + return true; }; /** @@ -1560,7 +1594,7 @@ description: parameterEntity.parameter.description, previousValue: parameterEntity.parameter.value, previousDescription: parameterEntity.parameter.description, - isEditable: _.defaultTo(readOnly, false) ? false : parameterEntity.canWrite, + isEditable: _.defaultTo(readOnly, false) || parameterEntity.parameter.provided ? false : parameterEntity.canWrite, referencingComponents: parameterEntity.parameter.referencingComponents, parameterContext: containingParameterContext, isInherited: (containingParameterContext.id !== parameterContext.component.id), @@ -2496,6 +2530,10 @@ markup += '
              '; } + if (canRead && dataContext.component.parameterProviderConfiguration) { + markup += '
              '; + } + return markup; }; @@ -2537,6 +2575,13 @@ resizable: true, formatter: nameFormatter }, + { + id: 'parameterProviderConfiguration', + name: 'Provider', + sortable: true, + resizable: true, + formatter: providerFormatter + }, { id: 'description', name: 'Description', @@ -2600,6 +2645,13 @@ // close the settings dialog $('#shell-close-button').click(); + } else if (target.hasClass('go-to-provider')) { + if (parameterContextEntity.component.parameterProviderConfiguration) { + nfParameterProvider.showParameterProvider(parameterContextEntity.component.parameterProviderConfiguration.id); + + // close the settings dialog + $('#shell-close-button').click(); + } } } else if (parameterContextsGrid.getColumns()[args.cell].id === 'info') { if (target.hasClass('view-parameter-context')) { @@ -2657,8 +2709,12 @@ var nfParameterContexts = { /** * Initializes the parameter contexts page. + * + * @param nfParameterProviderRef The nfParameterProvider module. */ - init: function () { + init: function (nfParameterProviderRef) { + nfParameterProvider = nfParameterProviderRef; + // parameter context refresh button $('#parameter-contexts-refresh-button').on('click', function () { loadParameterContexts(); @@ -2926,6 +2982,36 @@ .prop('title', parameterContextEntity.id) .text(parameterContextEntity.id); + // if provided, show the provider setting + if (parameterContextEntity.component.parameterProviderConfiguration) { + $('#parameter-context-provider-setting').show(); + + var parameterContextProviderSetting = $('#parameter-context-provider-setting').empty(); + var providerContent = nfCommon.escapeHtml(parameterContextEntity.component.parameterProviderConfiguration.component.parameterGroupName + + ' from ' + parameterContextEntity.component.parameterProviderConfiguration.component.parameterProviderName); + + $('
              Provider
              ').appendTo(parameterContextProviderSetting); + var settingEl = $('
              '); + + // provider name + var providerLinkEl = $('') + .prop('title', providerContent) + .text(providerContent) + .on('click', function () { + // check if there are outstanding changes + handleOutstandingChanges().done(function () { + // close the shell + $('#shell-dialog').modal('hide'); + + // show the provider in question + nfParameterProvider.showParameterProvider(parameterContextEntity.component.parameterProviderConfiguration.id) + }); + }); + + providerLinkEl.appendTo(settingEl); + settingEl.appendTo(parameterContextProviderSetting); + } + // get the reference container var referencingComponentsContainer = $('#parameter-context-referencing-components'); @@ -2996,6 +3082,22 @@ // select the parameters tab $('#parameter-context-tabs').find('li:eq(1)').click(); + // if parameters are provided + if (parameterContextEntity.component.parameterProviderConfiguration) { + // hide the add parameter button + $('#add-parameter').hide(); + } else { + // hide the provider details + if (!$('#parameter-context-provider-setting').hasClass('hidden')) { + $('#parameter-context-provider-setting') + .empty() + .addClass('hidden'); + } + + // show the add parameter button + $('#add-parameter').show(); + } + // check if border is necessary updateReferencingComponentsBorder($('#parameter-referencing-components-container')); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-parameter-provider.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-parameter-provider.js new file mode 100644 index 0000000000..6e4ff661e2 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-parameter-provider.js @@ -0,0 +1,3317 @@ +/* + * 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. + */ + +/* global define, module, require, exports */ + +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + define(['jquery', + 'Slick', + 'nf.ErrorHandler', + 'nf.Common', + 'nf.CanvasUtils', + 'nf.Dialog', + 'nf.Storage', + 'nf.Client', + 'nf.ControllerService', + 'nf.ControllerServices', + 'nf.UniversalCapture', + 'nf.CustomUi', + 'nf.Verify', + 'nf.Processor', + 'nf.ProcessGroup', + 'nf.ParameterContexts', + 'nf.ProcessGroupConfiguration', + 'lodash'], + function ($, Slick, nfErrorHandler, nfCommon, nfCanvasUtils, nfDialog, nfStorage, nfClient, nfControllerService, nfControllerServices, nfUniversalCapture, nfCustomUi, nfVerify, nfProcessor, nfProcessGroup, nfParameterContexts, nfProcessGroupConfiguration, _) { + return (nf.ParameterProvider = factory($, Slick, nfErrorHandler, nfCommon, nfCanvasUtils, nfDialog, nfStorage, nfClient, nfControllerService, nfControllerServices, nfUniversalCapture, nfCustomUi, nfVerify, nfProcessor, nfProcessGroup, nfParameterContexts, nfProcessGroupConfiguration, _)); + }); + } else if (typeof exports === 'object' && typeof module === 'object') { + module.exports = (nf.ParameterProvider = + factory(require('jquery'), + require('Slick'), + require('nf.ErrorHandler'), + require('nf.Common'), + require('nf.CanvasUtils'), + require('nf.Dialog'), + require('nf.Storage'), + require('nf.Client'), + require('nf.ControllerService'), + require('nf.ControllerServices'), + require('nf.UniversalCapture'), + require('nf.CustomUi'), + require('nf.Verify'), + require('nf.Processor'), + require('nf.ProcessGroup'), + require('nf.ParameterContexts'), + require('nf.ProcessGroupConfiguration'), + require('lodash'))); + } else { + nf.ParameterProvider = factory(root.$, + root.Slick, + root.nf.ErrorHandler, + root.nf.Common, + root.nf.CanvasUtils, + root.nf.Dialog, + root.nf.Storage, + root.nf.Client, + root.nf.ControllerService, + root.nf.ControllerServices, + root.nf.UniversalCapture, + root.nf.CustomUi, + root.nf.Verify, + root.nf.Processor, + root.nf.ProcessGroup, + root.nf.ParameterContexts, + root.nf.ProcessGroupConfiguration, + root._); + } +}(this, function ($, Slick, nfErrorHandler, nfCommon, nfCanvasUtils, nfDialog, nfStorage, nfClient, nfControllerService, nfControllerServices, nfUniversalCapture, nfCustomUi, nfVerify, nfProcessor, nfProcessGroup, nfParameterContexts, nfProcessGroupConfiguration, _) { + 'use strict'; + + var nfSettings; + var fetchParameterProviderOptions; + + var config = { + edit: 'edit', + readOnly: 'read-only', + urls: { + parameterProviders: '../nifi-api/parameter-providers', + api: '../nifi-api' + } + }; + + // load the controller services + var controllerServicesUri = config.urls.api + '/flow/controller/controller-services'; + + var groupCount = 0; + var parameterCount = 0; + + var SENSITIVE = 'SENSITIVE'; + var NON_SENSITIVE = 'NON_SENSITIVE'; + + var parameterGroupsGridOptions = { + autosizeColsMode: Slick.GridAutosizeColsMode.LegacyForceFit, + enableTextSelectionOnCells: true, + enableCellNavigation: true, + enableColumnReorder: false, + editable: false, + enableAddRow: false, + autoEdit: false, + multiSelect: false, + rowHeight: 24 + }; + + var selectableParametersGridOptions = { + autosizeColsMode: Slick.GridAutosizeColsMode.LegacyForceFit, + enableTextSelectionOnCells: true, + enableCellNavigation: true, + enableColumnReorder: false, + editable: false, + enableAddRow: false, + autoEdit: false, + multiSelect: false, + rowHeight: 24, + asyncEditorLoading: false + }; + + // the last submitted referenced attributes + var referencedAttributes = null; + + /** + * Gets the controller services table. + * + * @returns {*|jQuery|HTMLElement} + */ + var getControllerServicesTable = function () { + return $('#controller-services-table'); + }; + + /** + * Determines whether the user has made any changes to the parameter provider configuration + * that needs to be saved. + */ + var isSaveRequired = function () { + var entity = $('#parameter-provider-configuration').data('parameterProviderDetails'); + + // determine if any parameter provider settings have changed + if ($('#parameter-provider-name').val() !== entity.component['name']) { + return true; + } + if ($('#parameter-provider-comments').val() !== entity.component['comments']) { + return true; + } + + // defer to the properties + return $('#parameter-provider-properties').propertytable('isSaveRequired'); + }; + + + /** + * Marshals the data that will be used to update the parameter provider's configuration. + */ + var marshalDetails = function () { + // properties + var properties = $('#parameter-provider-properties').propertytable('marshalProperties'); + + // create the parameter provider dto + var parameterProviderDto = {}; + parameterProviderDto['id'] = $('#parameter-provider-id').text(); + parameterProviderDto['name'] = $('#parameter-provider-name').val(); + parameterProviderDto['comments'] = $('#parameter-provider-comments').val(); + + // set the properties + if ($.isEmptyObject(properties) === false) { + parameterProviderDto['properties'] = properties; + } + + // create the parameter provider entity + var parameterProviderEntity = {}; + parameterProviderEntity['component'] = parameterProviderDto; + + // return the marshaled details + return parameterProviderEntity; + }; + + /** + * Marshals the parameter groups in the table. + */ + var marshalParameterGroups = function () { + var groups = []; + var table = $('#parameter-groups-table'); + var groupsGrid = table.data('gridInstance'); + var groupsData = groupsGrid.getData(); + $.each(groupsData.getItems(), function (_, g) { + if (g.isParameterContext || g.createNewParameterContext) { + var group = { + 'groupName': g.name, + 'parameterContextName': g.parameterContextName, + 'synchronized': true, + 'parameterSensitivities': g.parameterSensitivities + } + + groups.push(group); + } + }) + + return groups; + }; + + /** + * Validates the specified details. + * + * @param providerDetails the parameter provider details to validate + * @param originalProviderDetails the original parameter provider details to compare changes + * @param existingParametersProviders existing parameter providers to verify there are no duplicates + * @return {boolean} + */ + var validateDetails = function (providerDetails, existingParametersProviders, originalProviderDetails) { + var parameterProvider = providerDetails['component']; + + if (parameterProvider.name === '') { + nfDialog.showOkDialog({ + headerText: 'Configuration Error', + dialogContent: 'The name of the Parameter Provider must be specified.' + }); + return false; + } + + // make sure the parameter provider name does not use any unsupported characters + var parameterProviderNameRegex = /^[a-zA-Z0-9-_. ]+$/; + if (!parameterProviderNameRegex.test(parameterProvider.name)) { + nfDialog.showOkDialog({ + headerText: 'Configuration Error', + dialogContent: 'The name of the Parameter Provider appears to have an invalid character or characters. Only alpha-numeric characters (a-z, A-Z, 0-9), hyphens (-), underscores (_), periods (.), and spaces ( ) are accepted.' + }); + return false; + } + + // validate the parameter provider is not a duplicate + var matchingParameterProvider; + var match; + + if (nfCommon.isUndefinedOrNull(matchingParameterProvider) && originalProviderDetails.component.name !== providerDetails.component.name){ + $.each(existingParametersProviders, function (i, provider) { + if (nfCommon.isUndefinedOrNull(match)) { + match = _.find(provider, {name: parameterProvider.name}); + if (match) { + matchingParameterProvider = match; + } + } + + }); + } + + if (_.isNil(matchingParameterProvider)) { + return true; + } else { + nfDialog.showOkDialog({ + headerText: 'Parameter Provider Exists', + dialogContent: 'A Parameter Provider with this name already exists.' + }); + } + return false; + }; + + /** + * Renders the specified parameter provider. + * + * @param {object} parameterProviderEntity parameter provider entity + */ + var renderParameterProvider = function (parameterProviderEntity) { + // get the table and update the row accordingly + var parameterProviderGrid = $('#parameter-providers-table').data('gridInstance'); + var parameterProviderData = parameterProviderGrid.getData(); + var currentParameterProvider = parameterProviderData.getItemById(parameterProviderEntity.id); + parameterProviderData.updateItem(parameterProviderEntity.id, $.extend({ + type: 'ParameterProvider', + bulletins: currentParameterProvider.bulletins + }, parameterProviderEntity)); + }; + + /** + * Goes to a service configuration from the property table. + */ + var goToServiceFromProperty = function () { + return $.Deferred(function (deferred) { + // close all fields currently being edited + $('#parameter-provider-properties').propertytable('saveRow'); + + // determine if changes have been made + if (isSaveRequired()) { + // see if those changes should be saved + nfDialog.showYesNoDialog({ + headerText: 'Save', + dialogContent: 'Save changes before going to this Controller Service?', + noHandler: function () { + deferred.resolve(); + }, + yesHandler: function () { + var parameterProvider = $('#parameter-provider-configuration').data('parameterProviderDetails'); + saveParameterProvider(parameterProvider).done(function () { + deferred.resolve(); + }).fail(function () { + deferred.reject(); + }); + } + }); + } else { + deferred.resolve(); + } + }).promise(); + }; + + /** + * Saves the specified parameter provider. + * + * @param {type} parameterProviderEntity parameter provider entity + */ + var saveParameterProvider = function (parameterProviderEntity) { + // save the original provider to detect a name change + var originalParameterProvider = parameterProviderEntity; + + // marshal the settings and properties and update the parameter provider + var updatedParameterProvider = marshalDetails(); + + // ensure details are valid as far as we can tell + var parameterProvidersGrid = $('#parameter-providers-table').data('gridInstance'); + var parameterProvidersData = parameterProvidersGrid.getData(); + + if (validateDetails(updatedParameterProvider, parameterProvidersData.getItems(), originalParameterProvider)) { + updatedParameterProvider['revision'] = nfClient.getRevision(parameterProviderEntity); + updatedParameterProvider['disconnectedNodeAcknowledged'] = nfStorage.isDisconnectionAcknowledged(); + + // update the selected component + return $.ajax({ + type: 'PUT', + data: JSON.stringify(updatedParameterProvider), + url: parameterProviderEntity.uri, + dataType: 'json', + contentType: 'application/json' + }).done(function (response) { + // update the parameter provider + renderParameterProvider(response); + }).fail(nfErrorHandler.handleConfigurationUpdateAjaxError); + } else { + return $.Deferred(function (deferred) { + deferred.reject(); + }).promise(); + } + }; + + /** + * Gets a property descriptor for the parameter provider currently being configured. + * + * @param {type} propertyName property descriptor name + * @param {type} sensitive requested sensitive status + */ + var getParameterProviderPropertyDescriptor = function (propertyName, sensitive) { + var details = $('#parameter-provider-configuration').data('parameterProviderDetails'); + return $.ajax({ + type: 'GET', + url: details.uri + '/descriptors', + data: { + propertyName: propertyName, + sensitive: sensitive + }, + dataType: 'json' + }).fail(nfErrorHandler.handleAjaxError); + }; + + /** + * Handles verification results. + */ + var handleVerificationResults = function (verificationResults, referencedAttributeMap) { + // record the most recently submitted referenced attributes + referencedAttributes = referencedAttributeMap; + + var verificationResultsContainer = $('#parameter-provider-properties-verification-results'); + + // expand the dialog to make room for the verification result + if (verificationResultsContainer.is(':visible') === false) { + // show the verification results + $('#parameter-provider-properties').css('bottom', '40%').propertytable('resetTableSize') + verificationResultsContainer.show(); + } + + // show borders if appropriate + var verificationResultsListing = $('#parameter-provider-properties-verification-results-listing'); + if (verificationResultsListing.get(0).scrollHeight > Math.round(verificationResultsListing.innerHeight())) { + verificationResultsListing.css('border-width', '1px'); + } + }; + + /** + * Applies the fetched parameters of a specified Parameter Provider. + * + * @param parameterProviderEntity + * @returns {*} + */ + var applyParametersHandler = function (parameterProviderEntity) { + var currentParameterProviderEntity = parameterProviderEntity; + var fetchParametersDialog = $('#fetch-parameters-dialog'); + + // clean up any tooltips that may have been generated + nfCommon.cleanUpTooltips($('#parameter-table'), 'div.fa-question-circle, div.fa-info'); + + var groups = marshalParameterGroups(); + currentParameterProviderEntity.component.parameterGroupConfigurations = groups; + + return $.Deferred(function (deferred) { + // updates the button model to show the close button + var updateToCloseButtonModel = function () { + fetchParametersDialog.modal('setButtonModel', [{ + buttonText: 'Close', + color: { + base: '#728E9B', + hover: '#004849', + text: '#ffffff' + }, + handler: { + click: function () { + deferred.resolve(); + closeModal('#fetch-parameters-dialog'); + } + } + }]); + }; + + var updateToApplyOrCancelButtonModel = function () { + fetchParametersDialog.modal('setButtonModel', [{ + buttonText: 'Apply', + color: { + base: '#728E9B', + hover: '#004849', + text: '#ffffff' + }, + handler: { + click: function () { + applyParametersHandler(currentParameterProviderEntity).done(function () { + // reload the parameter provider + nfParameterProvider.reload(parameterProviderEntity.id); + }); + } + } + }, { + buttonText: 'Cancel', + color: { + base: '#E3E8EB', + hover: '#C7D2D7', + text: '#004849' + }, + handler: { + click: function () { + deferred.resolve(); + confirmCancelDialog('#fetch-parameters-dialog'); + } + } + }]); + }; + + var cancelled = false; + + // update the button model to show the cancel button + fetchParametersDialog.modal('setButtonModel', [{ + buttonText: 'Cancel', + color: { + base: '#E3E8EB', + hover: '#C7D2D7', + text: '#004849' + }, + handler: { + click: function () { + cancelled = true; + updateToCloseButtonModel(); + } + } + }]); + + var requestId; + var handleAjaxFailure = function (xhr, status, error) { + // delete the request if possible + if (nfCommon.isDefinedAndNotNull(requestId)) { + deleteUpdateRequest(currentParameterProviderEntity.id, requestId); + } + + // update the step status + $('#fetch-parameters-update-steps') + .find('div.fetch-parameters-step.ajax-loading') + .removeClass('ajax-loading') + .addClass('ajax-error'); + + if ($('#affected-referencing-components-container').is(':visible')) { + updateReferencingComponentsBorder($('#affected-referencing-components-container')); + } + + // update the button model + updateToApplyOrCancelButtonModel(); + }; + + submitUpdateRequest(currentParameterProviderEntity).done(function (response) { + var pollUpdateRequest = function (updateRequestEntity) { + var updateRequest = updateRequestEntity.request; + var errored = nfCommon.isDefinedAndNotNull(updateRequest.failureReason); + + // get the request id + requestId = updateRequest.requestId; + + // update the affected referencing components + populateAffectedReferencingComponents(updateRequest.referencingComponents); + + // update the progress/steps + populateFetchParametersUpdateStep(updateRequest.updateSteps, cancelled, errored); + + // if this request was cancelled, remove the update request + if (cancelled) { + deleteUpdateRequest(currentParameterProviderEntity.id, requestId); + } else { + // show update steps + $('#fetch-parameters-update-status-container').show(); + + if (updateRequest.complete === true) { + if (errored) { + nfDialog.showOkDialog({ + headerText: 'Apply Parameter Provider Error', + dialogContent: 'Unable to complete parameter provider update request: ' + nfCommon.escapeHtml(updateRequest.failureReason) + }); + } + + // reload referencing processors + $.each(updateRequest.referencingComponents, function (_, referencingComponentEntity) { + if (referencingComponentEntity.permissions.canRead === true) { + var referencingComponent = referencingComponentEntity.component; + + // reload the processor if it's in the current group + if (referencingComponent.referenceType === 'PROCESSOR' && nfCanvasUtils.getGroupId() === referencingComponent.processGroupId) { + nfProcessor.reload(referencingComponent.id); + } + } + }); + + // update the fetch parameter table if displayed + if ($('#fetch-parameters-table').is(':visible')) { + var parameterProviderGrid = $('#fetch-parameters-table').data('gridInstance'); + var parameterProviderData = parameterProviderGrid.getData(); + + $.extend(currentParameterProviderEntity, { + revision: updateRequestEntity.parameterContextRevision, + component: updateRequestEntity.request.parameterProvider + }); + + var item = parameterProviderData.getItemById(currentParameterProviderEntity.id); + if (nfCommon.isDefinedAndNotNull(item)) { + parameterProviderData.updateItem(currentParameterProviderEntity.id, currentParameterProviderEntity); + } + } + + // delete the update request + deleteUpdateRequest(currentParameterProviderEntity.id, requestId); + + // update the button model + updateToCloseButtonModel(); + + // check if border is necessary + if ($('#affected-referencing-components-container').is(':visible')) { + updateReferencingComponentsBorder($('#affected-referencing-components-container')); + } + } else { + // wait to get an updated status + setTimeout(function () { + getUpdateRequest(currentParameterProviderEntity.id, requestId).done(function (getResponse) { + pollUpdateRequest(getResponse); + }).fail(handleAjaxFailure); + }, 2000); + } + } + }; + + // get the parameter provider groups names + var parameterProviderGroupNames = []; + $.each(response.request.parameterProvider.parameterGroupConfigurations, function (_, parameterProviderGroup) { + parameterProviderGroupNames.push(parameterProviderGroup.groupName); + }); + $('#apply-groups-list') + .removeClass('unset') + .attr('title', parameterProviderGroupNames.join(', ')) + .text(parameterProviderGroupNames.join(', ')); + + // update the visibility + // left column + $('#fetch-parameters-usage-container').hide(); + $('#apply-groups-container').show(); + + // middle column + $('#parameters-container').hide(); + $('#fetch-parameters-update-status').show(); + + pollUpdateRequest(response); + }).fail(handleAjaxFailure); + }).promise(); + }; + + /** + * Confirms a cancel dialog. + */ + var confirmCancelDialog = function (dialog) { + nfDialog.showYesNoDialog({ + headerText: 'Fetch Parameters', + dialogContent: 'Are you sure you want to cancel?', + noText: 'Cancel', + yesText: 'Yes', + yesHandler: function () { + closeModal(dialog); + } + }); + }; + + /** + * Shows the dialog to fetch parameters. + * + * @param {object} parameterProviderEntity parameterProviderEntity + * @param {object} fetchParameterProviderOptions fetchParameterProviderOptions + */ + var showFetchParametersDialog = function (parameterProviderEntity, fetchParameterProviderOptions) { + updateFetchParametersRequest(parameterProviderEntity).done(function (response) { + var updatedParameterProviderEntity = _.cloneDeep(response); + currentParameterProviderEntity = response; + + groupCount = 0; + parameterCount = 0; + + // populate the fetch parameters dialog + $('#fetch-parameters-id').text(updatedParameterProviderEntity.id); + $('#fetch-parameters-name').text(nfCommon.getComponentName(updatedParameterProviderEntity)); + + // set parameters contexts to be updated to none + $('
              None
              ') + .appendTo($('#parameter-contexts-to-create-container')); + + // list parameter contexts to update + var parameterContextsToUpdate = $('#parameter-contexts-to-update-container').empty(); + + if (!updatedParameterProviderEntity.component.referencingParameterContexts) { + $('
              None
              ') + .appendTo(parameterContextsToUpdate); + } else { + // populate contexts to be updated + var parameterContextNames = []; + $.each(updatedParameterProviderEntity.component.referencingParameterContexts, function (_, paramContext) { + parameterContextNames.push(paramContext.component.name); + }); + parameterContextNames.sort(); + parameterContextsToUpdate + .removeClass('unset') + .attr('title', parameterContextNames.join(', ')) + .text(parameterContextNames.join(', ')); + } + + loadParameterGroups(updatedParameterProviderEntity); + + // keep original group data + var initialFetchedGroups = getFetchedParameterGroups(response); + + // update visibility + $('#fetch-parameters-permissions-parameter-contexts-message').addClass('hidden'); + $('#fetch-parameters-permissions-affected-components-message').addClass('hidden'); + $('#fetch-parameters-missing-context-name-message').addClass('hidden'); + + $('#fetch-parameters-usage-container').show(); + $('#parameters-container').show(); + + // build the button model + var buttons = [{ + buttonText: 'Apply', + color: { + base: '#728E9B', + hover: '#004849', + text: '#ffffff' + }, + disabled: function () { + return disableApplyButton(updatedParameterProviderEntity, initialFetchedGroups); + }, + handler: { + click: function () { + applyParametersHandler(updatedParameterProviderEntity).done(function () { + // reload the parameter provider + nfParameterProvider.reload(parameterProviderEntity.id); + }); + } + } + }, { + buttonText: 'Cancel', + color: { + base: '#E3E8EB', + hover: '#C7D2D7', + text: '#004849' + }, + handler: { + click: function () { + if (!disableApplyButton(updatedParameterProviderEntity, initialFetchedGroups)) { + return confirmCancelDialog('#fetch-parameters-dialog'); + } + closeModal('#fetch-parameters-dialog'); + } + } + }]; + + // synchronize the current component canvas attributes in the status bar + if (fetchParameterProviderOptions.supportsStatusBar) { + var formattedBulletins = nfCommon.getFormattedBulletins(updatedParameterProviderEntity.bulletins); + var unorderedBulletins = nfCommon.formatUnorderedList(formattedBulletins); + + // initialize the canvas synchronization + if (updatedParameterProviderEntity.bulletins.length !== 0) { + $('#fetch-parameters-status-bar').statusbar( + 'observe', + { provider: unorderedBulletins } + ); + } + } + + $('#fetch-parameters-affected-referencing-components-container').hide(); + $('#fetch-parameters-referencing-components-container').show(); + + // show the dialog + $('#fetch-parameters-dialog') + .modal('setButtonModel', buttons) + .modal('show'); + + if ($('#fetched-parameters-listing-container').is(':visible')) { + updateReferencingComponentsBorder($('#fetched-parameters-listing-container')); + } + }); + }; + + /** + * Determines if the fetch parameters dialog has changes and whether the user has permissions to apply the changes. + * + * @param {object} updatedParameterProviderEntity updatedParameterProviderEntity + * @param {object} initialFetchedGroups initialFetchedGroups + */ + var disableApplyButton = function (updatedParameterProviderEntity, initialFetchedGroups) { + var canReadWrite = function (component) { + return component.permissions.canRead && component.permissions.canWrite; + } + + // referencing parameter contexts + if (updatedParameterProviderEntity.component.referencingParameterContexts) { + var hasReadWriteParameterContextsPermissions = updatedParameterProviderEntity.component.referencingParameterContexts.every(canReadWrite); + + if (hasReadWriteParameterContextsPermissions) { + // user has read and write permissions on a referencing parameter context + $('#fetch-parameters-permissions-parameter-contexts-message').addClass('hidden'); + } else { + // user does not have read and write permissions on a referencing parameter context + // no need to continue checking + $('#fetch-parameters-permissions-parameter-contexts-message').removeClass('hidden'); + return true; + } + } + + // affected referencing components + if (updatedParameterProviderEntity.component.affectedComponents) { + var hasReadWriteAffectedComponentsPermissions = updatedParameterProviderEntity.component.affectedComponents.every(canReadWrite); + + if (hasReadWriteAffectedComponentsPermissions) { + // user has read and write permissions on an affected component + $('#fetch-parameters-permissions-affected-components-message').addClass('hidden'); + + // user has permissions to all affected component... enable Apply button + } else { + // user does not have read and write permissions on an affected component + // no need to continue checking + $('#fetch-parameters-permissions-affected-components-message').removeClass('hidden'); + return true; + } + } + + var groupsData = $('#parameter-groups-table').data('gridInstance').getData(); + var groups = groupsData.getItems(); + + // new parameter contexts + var parameterContextNames = []; + $.each(groups, function (i, g) { + if (g.createNewParameterContext) { + parameterContextNames.push(g.parameterContextName); + } + }) + + // if any createNewParameterContext, then the name input cannot be empty + var isNameBlank = function (name) { + return nfCommon.isBlank(name); + } + + if (!_.isEmpty(parameterContextNames)) { + var isAnyParameterContextNameBlank = parameterContextNames.some(isNameBlank); + + if (isAnyParameterContextNameBlank) { + // missing a parameter context name + // no need to continue checking + $('#fetch-parameters-missing-context-name-message').removeClass('hidden'); + return true; + } else { + $('#fetch-parameters-missing-context-name-message').addClass('hidden'); + } + } else { + // hide the message if previously shown + $('#fetch-parameters-missing-context-name-message').addClass('hidden'); + } + + // parameter sensitivities + for (var k = 0; k < initialFetchedGroups.length; k++) { + var groupFromDataGrid = groups[k]; + + if (nfCommon.isDefinedAndNotNull(groupFromDataGrid)) { + if (groupFromDataGrid.isParameterContext && nfCommon.isUndefinedOrNull(groupFromDataGrid.createNewParameterContext)) { + // form the initially fetched group sensitivities + var groupInitiallyFetched = initialFetchedGroups[k]; + var initialGroupParamSensitivity = {}; + + for (var param in groupInitiallyFetched.parameterSensitivities) { + initialGroupParamSensitivity[param] = groupInitiallyFetched.parameterSensitivities[param] ? groupInitiallyFetched.parameterSensitivities[param] : SENSITIVE; + } + + // compare + if (!_.isEqual(initialGroupParamSensitivity, groupFromDataGrid.parameterSensitivities)) { + // parameter sensitive has changed... do not disable the Apply button + return false; + } + } + } + } + + // check for changed parameter values + if (updatedParameterProviderEntity.component.parameterStatus) { + var isChanged = function (parameterStatus) { + return parameterStatus.status === 'CHANGED'; + } + + var isAnyParameterValueChanged = updatedParameterProviderEntity.component.parameterStatus.some(isChanged); + + if (isAnyParameterValueChanged) { + // a fetched parameter value has changed... do not disable the Apply button + return false; + } + } + + return _.isEmpty(parameterContextNames); + }; + + /** + * Loads the specified fetched groups. + * + * @param {object} parameterProviderGroupEntity + * @param {boolean} if the parameters should be displayed in a read-only state regardless of permissions + */ + var loadParameterGroups = function (parameterProviderGroupEntity) { + // providedGroups will be an array of groups + if (nfCommon.isDefinedAndNotNull(parameterProviderGroupEntity)) { + var groupsGrid = $('#parameter-groups-table').data('gridInstance'); + var groupsData = groupsGrid.getData(); + + // begin the update + groupsData.beginUpdate(); + + var parameterGroups = []; + $.each(parameterProviderGroupEntity.component.parameterGroupConfigurations, function (i, groupConfig) { + var referencingParameterContext = parameterProviderGroupEntity.component.referencingParameterContexts + ? isReferencingParamContext(parameterProviderGroupEntity.component.referencingParameterContexts, groupConfig.parameterContextName) + : false; + + var canWriteParameterContexts; + if (referencingParameterContext) { + canWriteParameterContexts = referencingParameterContext.permissions.canWrite; + } else { + canWriteParameterContexts = true; + } + + var canWriteAffectedComponents; + if (parameterProviderGroupEntity.component.affectedComponents) { + canWriteAffectedComponents = (parameterProviderGroupEntity.component.affectedComponents).every(function (c) { + return c.permissions.canRead && c.permissions.canWrite; + }); + } else { + canWriteAffectedComponents = true; + } + + var group = { + id: groupCount++, + hidden: false, + isParameterContext: referencingParameterContext ? true : false, + name: groupConfig.groupName, + parameterContextName: groupConfig.parameterContextName, + parameterSensitivities: groupConfig.parameterSensitivities, + referencingParameterContexts: groupConfig.referencingParameterContexts ? groupConfig.referencingParameterContexts : null, + enableParametersCheckboxes: canWriteParameterContexts && canWriteAffectedComponents, + parameterStatus: parameterProviderGroupEntity.component.parameterStatus + }; + + parameterGroups.push({ + group: group + }); + + groupsData.addItem(group); + }); + + // complete the update + groupsData.endUpdate(); + groupsData.reSort(); + + // select the first row + groupsGrid.setSelectedRows([0]); + } + }; + + /** + * Determines if the provided group is synced to a parameter context. + * + * @param {object} referencingParameterContexts + * @param {string} parameterContextName + * @returns {boolean} + */ + var isReferencingParamContext = function (referencingParameterContexts, parameterContextName) { + var referencingParamContext = null; + $.each(referencingParameterContexts, function (i, paramContext) { + if (paramContext.component.name.includes(parameterContextName)) { + referencingParamContext = paramContext; + } + }) + + return referencingParamContext; + } + + /** + * Loads the selectable parameters for a specified parameter group. + * + * @param groupId + * @param {object} parametersEntity + * @param {object} updatedGroup + */ + var loadSelectableParameters = function (groupId, parametersEntity, updatedGroup) { + if (nfCommon.isDefinedAndNotNull(parametersEntity)) { + var selectableParametersGrid = $('#selectable-parameters-table').data('gridInstance'); + var parametersData = selectableParametersGrid.getData(); + + // clear the rows + selectableParametersGrid.setSelectedRows([]); + parametersData.setItems([]); + + // begin the update + parametersData.beginUpdate(); + + var isAffectedParameter = function (providerEntity, param) { + var isAffectedParameter = false; + // check for affected components + $.each(providerEntity.component.parameterStatus, function (i, status) { + if (status.parameter.parameter.name === param) { + if (status.status === 'CHANGED') { + isAffectedParameter = true; + } + } + }); + return isAffectedParameter; + } + + var getParameterStatus = function (parameterStatus, param) { + return nfCommon.isDefinedAndNotNull(parameterStatus.find(function (status) { return status.parameter.parameter.name === param })) + ? parameterStatus.find(function (status) { return status.parameter.parameter.name === param }) + : []; + } + + var isReferencedParameter = function (paramStatus, param) { + var status = getParameterStatus(paramStatus, param); + return !_.isEmpty(status) && !_.isEmpty(status.parameter.parameter.referencingComponents); + } + + var idx = 0; + var referencingParameters = 0; + var parameterCount = 0; + for (var param in parametersEntity) { + + var parameter = { + id: idx++, + groupId: groupId, + name: param, + sensitivity: parametersEntity[param] ? parametersEntity[param] : SENSITIVE, + isAffectedParameter: currentParameterProviderEntity.component.affectedComponents ? isAffectedParameter(currentParameterProviderEntity, param) : false, + isReferencingParameter: !_.isEmpty(updatedGroup.parameterStatus) ? isReferencedParameter(updatedGroup.parameterStatus, param) : false, + parameterStatus: !_.isEmpty(updatedGroup.parameterStatus) ? getParameterStatus(updatedGroup.parameterStatus, param) : [] + } + + parametersData.addItem(parameter); + + parameterCount++; + if (parameter.isReferencingParameter === true) { + referencingParameters++; + } + } + + // complete the update + parametersData.endUpdate(); + parametersData.reSort(); + + // select the the first row + selectableParametersGrid.setSelectedRows([0]); + + // list the parameters to be created + loadParameterContextsToCreate(); + } + }; + + /** + * Populates the affected referencing components for the specified parameter provider. + * + * @param {object} referencingComponents + */ + var populateAffectedReferencingComponents = function (referencingComponents) { + // toggles the visibility of a container + var toggle = function (twist, container) { + if (twist.hasClass('expanded')) { + twist.removeClass('expanded').addClass('collapsed'); + container.hide(); + } else { + twist.removeClass('collapsed').addClass('expanded'); + container.show(); + } + }; + + // update visibility + $('#fetch-parameters-referencing-components-container').hide(); + $('#affected-referencing-components-container').show(); + updateReferencingComponentsBorder($('#affected-referencing-components-container')); + + $('#fetch-parameters-affected-referencing-components-container').show(); + + var referencingProcessors = []; + var referencingControllerServices = []; + var unauthorizedReferencingComponents = []; + + var spinner = $('#fetch-parameters-affected-referencing-components-container .referencing-components-loading'); + + var loadingDeferred = $.Deferred(function (deferred) { + spinner.addClass('ajax-loading'); + deferred.resolve(); + }); + loadingDeferred.then(function () { + resetUsage(); + }).then(function() { + var parameterReferencingComponentsContainer = $('#affected-referencing-components-container').empty(); + + // referencing component will be undefined when a new parameter is added + if (nfCommon.isUndefined(referencingComponents)) { + // set to pending + $('
              Pending Apply
              ').appendTo(parameterReferencingComponentsContainer); + } else { + // bin the referencing components according to their type + $.each(referencingComponents, function (_, referencingComponentEntity) { + if (referencingComponentEntity.permissions.canRead === true && referencingComponentEntity.permissions.canWrite === true) { + if (referencingComponentEntity.component.referenceType === 'PROCESSOR') { + referencingProcessors.push(referencingComponentEntity); + } else { + referencingControllerServices.push(referencingComponentEntity); + } + } else { + unauthorizedReferencingComponents.push(referencingComponentEntity); + } + }); + + var referencingProcessGroups = {}; + + // bin the referencing processors according to their PG + $.each(referencingProcessors, function (_, referencingProcessorEntity) { + if (referencingProcessGroups[referencingProcessorEntity.processGroup.id]) { + referencingProcessGroups[referencingProcessorEntity.processGroup.id].referencingProcessors.push(referencingProcessorEntity); + referencingProcessGroups[referencingProcessorEntity.processGroup.id].id = referencingProcessorEntity.processGroup.id; + referencingProcessGroups[referencingProcessorEntity.processGroup.id].name = referencingProcessorEntity.processGroup.name; + } else { + referencingProcessGroups[referencingProcessorEntity.processGroup.id] = { + referencingProcessors: [], + referencingControllerServices: [], + unauthorizedReferencingComponents: [], + name: referencingProcessorEntity.processGroup.name, + id: referencingProcessorEntity.processGroup.id + }; + + referencingProcessGroups[referencingProcessorEntity.processGroup.id].referencingProcessors.push(referencingProcessorEntity); + } + }); + + // bin the referencing CS according to their PG + $.each(referencingControllerServices, function (_, referencingControllerServiceEntity) { + if (referencingProcessGroups[referencingControllerServiceEntity.processGroup.id]) { + referencingProcessGroups[referencingControllerServiceEntity.processGroup.id].referencingControllerServices.push(referencingControllerServiceEntity); + referencingProcessGroups[referencingControllerServiceEntity.processGroup.id].id = referencingControllerServiceEntity.processGroup.id; + referencingProcessGroups[referencingControllerServiceEntity.processGroup.id].name = referencingControllerServiceEntity.processGroup.name; + } else { + referencingProcessGroups[referencingControllerServiceEntity.processGroup.id] = { + referencingProcessors: [], + referencingControllerServices: [], + unauthorizedReferencingComponents: [], + name: referencingControllerServiceEntity.processGroup.name, + id: referencingControllerServiceEntity.processGroup.id + }; + + referencingProcessGroups[referencingControllerServiceEntity.processGroup.id].referencingControllerServices.push(referencingControllerServiceEntity); + } + }); + + // bin the referencing unauthorized components according to their PG + $.each(unauthorizedReferencingComponents, function (_, unauthorizedReferencingComponentEntity) { + if (referencingProcessGroups[unauthorizedReferencingComponentEntity.processGroup.id]) { + referencingProcessGroups[unauthorizedReferencingComponentEntity.processGroup.id].unauthorizedReferencingComponents.push(unauthorizedReferencingComponentEntity); + referencingProcessGroups[unauthorizedReferencingComponentEntity.processGroup.id].id = unauthorizedReferencingComponentEntity.processGroup.id; + referencingProcessGroups[unauthorizedReferencingComponentEntity.processGroup.id].name = unauthorizedReferencingComponentEntity.processGroup.name; + } else { + referencingProcessGroups[unauthorizedReferencingComponentEntity.processGroup.id] = { + referencingProcessors: [], + referencingControllerServices: [], + unauthorizedReferencingComponents: [], + name: unauthorizedReferencingComponentEntity.processGroup.name, + id: unauthorizedReferencingComponentEntity.processGroup.id + }; + + referencingProcessGroups[unauthorizedReferencingComponentEntity.processGroup.id].unauthorizedReferencingComponents.push(unauthorizedReferencingComponentEntity); + } + }); + + var parameterReferencingComponentsContainer = $('#affected-referencing-components-container'); + var groups = $('
                '); + + var referencingProcessGroupsArray = []; + for (var key in referencingProcessGroups) { + if (referencingProcessGroups.hasOwnProperty(key)) { + referencingProcessGroupsArray.push(referencingProcessGroups[key]); + } + } + + if (nfCommon.isEmpty(referencingProcessGroupsArray)) { + // set to none + $('
                None
                ').appendTo(parameterReferencingComponentsContainer); + } else { + //sort alphabetically + var sortedReferencingProcessGroups = referencingProcessGroupsArray.sort(function (a, b) { + if (a.name < b.name) { + return -1; + } + if (a.name > b.name) { + return 1; + } + return 0; + }); + + sortedReferencingProcessGroups.forEach(function (referencingProcessGroup) { + // container for this pg's references + var referencingPgReferencesContainer = $('
                '); + parameterReferencingComponentsContainer.append(referencingPgReferencesContainer); + + // create the collapsable listing for each PG + var createReferenceBlock = function (referencingProcessGroup, list) { + var twist = $(''); + var title = $('').text(referencingProcessGroup.name); + var count = $('').text('(' + (referencingProcessGroup.referencingProcessors.length + referencingProcessGroup.referencingControllerServices.length + referencingProcessGroup.unauthorizedReferencingComponents.length) + ')'); + var referencingComponents = $('#affected-referencing-components-template').clone(); + referencingComponents.removeAttr('id'); + referencingComponents.removeClass('hidden'); + + // create the reference block + var groupTwist = $('
                ').data('processGroupId', referencingProcessGroup.id).on('click', function () { + if (twist.hasClass('collapsed')) { + groupTwist.append(referencingComponents); + + var processorContainer = groupTwist.find('.fetch-parameters-referencing-processors'); + nfCommon.cleanUpTooltips(processorContainer, 'div.referencing-component-state'); + nfCommon.cleanUpTooltips(processorContainer, 'div.referencing-component-bulletins'); + processorContainer.empty(); + + var controllerServiceContainer = groupTwist.find('.fetch-parameters-referencing-controller-services'); + nfCommon.cleanUpTooltips(controllerServiceContainer, 'div.referencing-component-state'); + nfCommon.cleanUpTooltips(controllerServiceContainer, 'div.referencing-component-bulletins'); + controllerServiceContainer.empty(); + + var unauthorizedComponentsContainer = groupTwist.find('.fetch-parameters-referencing-unauthorized-components').empty(); + + if (referencingProcessGroups[$(this).data('processGroupId')].referencingProcessors.length === 0) { + $('
              • None
              • ').appendTo(processorContainer); + } else { + // sort the referencing processors + referencingProcessGroups[$(this).data('processGroupId')].referencingProcessors.sort(nameComparator); + + // render each and register a click handler + $.each(referencingProcessGroups[$(this).data('processGroupId')].referencingProcessors, function (_, referencingProcessorEntity) { + renderReferencingProcessor(referencingProcessorEntity, processorContainer); + }); + } + + if (referencingProcessGroups[$(this).data('processGroupId')].referencingControllerServices.length === 0) { + $('
              • None
              • ').appendTo(controllerServiceContainer); + } else { + // sort the referencing controller services + referencingProcessGroups[$(this).data('processGroupId')].referencingControllerServices.sort(nameComparator); + + // render each and register a click handler + $.each(referencingProcessGroups[$(this).data('processGroupId')].referencingControllerServices, function (_, referencingControllerServiceEntity) { + renderReferencingControllerService(referencingControllerServiceEntity, controllerServiceContainer); + }); + } + + if (referencingProcessGroups[$(this).data('processGroupId')].unauthorizedReferencingComponents.length === 0) { + $('
              • None
              • ').appendTo(unauthorizedComponentsContainer); + } else { + // sort the unauthorized referencing components + referencingProcessGroups[$(this).data('processGroupId')].unauthorizedReferencingComponents.sort(function (a, b) { + if (a.permissions.canRead === true && b.permissions.canRead === true) { + // processors before controller services + var sortVal = a.component.referenceType === b.component.referenceType ? 0 : a.component.referenceType > b.component.referenceType ? -1 : 1; + + // if a and b are the same type, then sort by name + if (sortVal === 0) { + sortVal = a.component.name === b.component.name ? 0 : a.component.name > b.component.name ? 1 : -1; + } + + return sortVal; + } else { + + // if lacking read and write perms on both, sort by id + if (a.permissions.canRead === false && b.permissions.canRead === false) { + return a.id > b.id ? 1 : -1; + } else { + // if only one has read perms, then let it come first + if (a.permissions.canRead === true) { + return -1; + } else { + return 1; + } + } + } + }); + + $.each(referencingProcessGroups[$(this).data('processGroupId')].unauthorizedReferencingComponents, function (_, unauthorizedReferencingComponentEntity) { + if (unauthorizedReferencingComponentEntity.permissions.canRead === true) { + if (unauthorizedReferencingComponentEntity.component.referenceType === 'PROCESSOR') { + renderReferencingProcessor(unauthorizedReferencingComponentEntity, unauthorizedComponentsContainer); + } else { + renderReferencingControllerService(unauthorizedReferencingComponentEntity, unauthorizedComponentsContainer); + } + } else { + var referencingUnauthorizedComponentContainer = $('
              • ').appendTo(unauthorizedComponentsContainer); + $('') + .prop('title', unauthorizedReferencingComponentEntity.id) + .text(unauthorizedReferencingComponentEntity.id) + .on('click', function () { + // close the shell + $('#shell-dialog').modal('hide'); + + // show the component in question + if (unauthorizedReferencingComponentEntity.referenceType === 'PROCESSOR') { + nfCanvasUtils.showComponent(unauthorizedReferencingComponentEntity.processGroup.id, unauthorizedReferencingComponentEntity.id); + } else if (unauthorizedReferencingComponentEntity.referenceType === 'CONTROLLER_SERVICE') { + nfProcessGroupConfiguration.showConfiguration(unauthorizedReferencingComponentEntity.processGroup.id).done(function () { + nfProcessGroup.enterGroup(unauthorizedReferencingComponentEntity.processGroup.id); + nfProcessGroupConfiguration.selectControllerService(unauthorizedReferencingComponentEntity.id); + }); + } + }) + .appendTo(referencingUnauthorizedComponentContainer); + } + }); + } + } else { + groupTwist.find('.affected-referencing-components-template').remove(); + } + + // toggle this block + toggle(twist, list); + + // update the border if necessary + updateReferencingComponentsBorder($('#affected-referencing-components-container')); + }).append(twist).append(title).append(count).appendTo(referencingPgReferencesContainer); + + // add the listing + list.appendTo(referencingPgReferencesContainer); + + // expand the group twist + groupTwist.click(); + }; + + // create block for this process group + createReferenceBlock(referencingProcessGroup, groups); + }); + } + } + }) + .always(function () { + spinner.removeClass('ajax-loading'); + }); + return loadingDeferred.promise(); + }; + + /** + * Loads the referencing components for this parameter provider. + * + * @param {jQuery} parameterProviderReferencingComponentsContainer + * @param {object} parameterProviderEntity + */ + var loadParameterProviderReferencingComponents = function (parameterProviderReferencingComponentsContainer, parameterProviderEntity) { + parameterProviderReferencingComponentsContainer.empty(); + var parameterProviderComponent = parameterProviderEntity; + + if (nfCommon.isEmpty(parameterProviderComponent.referencingParameterContexts)) { + parameterProviderReferencingComponentsContainer.append('
                No referencing components.
                '); + return; + } + + // toggles the visibility of a container + var toggle = function (twist, container) { + if (twist.hasClass('expanded')) { + twist.removeClass('expanded').addClass('collapsed'); + container.hide(); + } else { + twist.removeClass('collapsed').addClass('expanded'); + container.show(); + } + }; + + var parameterContexts = $('
                  '); + var unauthorized = $('
                    '); + + $.each(parameterProviderComponent.referencingParameterContexts, function (_, refParameterContextComponent) { + // check the access policy for this referencing component + if (refParameterContextComponent.permissions.canRead === false) { + var unauthorizedReferencingComponent = $('
                    ').text(refParameterContextComponent.id); + unauthorized.append(unauthorizedReferencingComponent); + } else { + var referencingComponent = refParameterContextComponent.component; + + var parameterContextLink = $('') + .text(referencingComponent.name) + .on('click', function () { + // show the component + nfParameterContexts.showParameterContexts(referencingComponent.id); + + // close the dialog and shell + parameterProviderReferencingComponentsContainer.closest('.dialog').modal('hide'); + $('#shell-close-button').click(); + }); + var parameterContextItem = $('
                  • ').append(parameterContextLink); + parameterContexts.append(parameterContextItem); + } + }); + + // create the collapsable listing for each type + var createReferenceBlock = function (titleText, list) { + if (list.is(':empty')) { + list.remove(); + return; + } + + var twist = $('
                    '); + var title = $('').text(titleText); + var count = $('').text('(' + list.children().length + ')'); + + // create the reference block + $('
                    ') + .on('click', function () { + // toggle this block + toggle(twist, list); + + // update the border if necessary + updateReferencingComponentsBorder(parameterProviderReferencingComponentsContainer); + }) + .append(twist) + .append(title) + .append(count) + .appendTo(parameterProviderReferencingComponentsContainer); + + // add the listing + list.appendTo(parameterProviderReferencingComponentsContainer); + }; + + // create blocks for each type of component + createReferenceBlock('Parameter Contexts', parameterContexts); + createReferenceBlock('Unauthorized', unauthorized); + }; + + /** + * Loads the groups that will be created as a parameter context. + * + */ + var loadParameterContextsToCreate = function () { + var parameterContextsToCreate = $('#parameter-contexts-to-create-container').empty(); + var parameterContextNames = []; + + var groupsGrid = $('#parameter-groups-table').data('gridInstance'); + var groupsData = groupsGrid.getData(); + + $.each(groupsData.getItems(), function (_, group) { + if (group.createNewParameterContext) { + parameterContextNames.push(group.parameterContextName); + } + }); + + if (parameterContextNames.length === 0) { + $('
                    None
                    ') + .appendTo(parameterContextsToCreate); + } else { + parameterContextNames.sort(); + parameterContextsToCreate + .removeClass('unset') + .attr('title', parameterContextNames.join(', ')) + .text(parameterContextNames.join(', ')); + } + } + + var getFetchedParameterGroups = function (groupEntity) { + var parameterGroups = []; + $.each(groupEntity.component.parameterGroupConfigurations, function (i, groupConfig) { + var referencingParameterContext = groupEntity.component.referencingParameterContexts + ? isReferencingParamContext(groupEntity.component.referencingParameterContexts, groupConfig.parameterContextName) + : false; + + var canWriteParameterContexts; + if (referencingParameterContext) { + canWriteParameterContexts = referencingParameterContext.permissions.canWrite; + } else { + canWriteParameterContexts = true; + } + + var canWriteAffectedComponents; + if (groupEntity.component.affectedComponents) { + canWriteAffectedComponents = (groupEntity.component.affectedComponents).every(function (c) { + return c.permissions.canRead && c.permissions.canWrite; + }); + } else { + canWriteAffectedComponents = true; + } + + var index = 0; + var group = { + id: index++, + hidden: false, + isParameterContext: referencingParameterContext ? true : false, + name: groupConfig.groupName, + parameterContextName: groupConfig.parameterContextName, + parameterSensitivities: groupConfig.parameterSensitivities, + referencingParameterContexts: groupConfig.referencingParameterContexts ? groupConfig.referencingParameterContexts : null, + enableParametersCheckboxes: canWriteParameterContexts && canWriteAffectedComponents, + parameterStatus: groupEntity.component.parameterStatus + }; + + parameterGroups.push(group); + }); + return parameterGroups; + } + + /** + * Handles outstanding changes. + * + * @returns {deferred} + */ + var handleOutstandingChanges = function () { + return $.Deferred(function (deferred) { + if ($('#fetch-parameters-update-status').is(':visible')) { + close(); + deferred.resolve(); + } else { + var parameterGroups = marshalParameterGroups(); + + // if there are no parameters there is nothing to save + if ($.isEmptyObject(parameterGroups)) { + close(); + deferred.resolve(); + } else { + // see if those changes should be saved + nfDialog.showYesNoDialog({ + headerText: 'Fetch Parameters', + dialogContent: 'Save changes before leaving parameters configuration?', + noHandler: function () { + close(); + deferred.resolve(); + }, + yesHandler: function () { + applyParametersHandler(currentParameterProviderEntity).done(function () { + deferred.resolve(); + }).fail(function () { + deferred.reject(); + }); + } + }); + } + } + + }).promise(); + }; + + /** + * Adds a border to the fetch parameters referencing components if necessary. + * + * @argument {jQuery} referenceContainer + */ + var updateReferencingComponentsBorder = function (referenceContainer) { + // determine if it is too big + var tooBig = referenceContainer.get(0).scrollHeight > Math.round(referenceContainer.innerHeight()) || + referenceContainer.get(0).scrollWidth > Math.round(referenceContainer.innerWidth()); + + // draw the border if necessary + if (referenceContainer.is(':visible') && tooBig) { + referenceContainer.css('border-width', '1px'); + } else { + referenceContainer.css('border-width', '0px'); + } + }; + + /** + * Determines if any of the specified referencing components are not authorized to apply parameters. + * + * @param {object} parameterProviderEntity having referencingComponents referencing components + * @returns {boolean} + */ + var hasUnauthorizedReferencingComponent = function (parameterProviderEntity) { + + if (parameterProviderEntity.permissions.canRead === false + || (parameterProviderEntity.permissions.canWrite === false && parameterProviderEntity.operatePermissions.canWrite === false)) { + return true; + } + + var hasUnauthorized = false; + var referencingComponents = parameterProviderEntity.component.referencingComponents; + $.each(referencingComponents, function (_, referencingComponentEntity) { + if (hasUnauthorizedReferencingComponent(referencingComponentEntity)) { + hasUnauthorized = true; + return false; + } + }); + + return hasUnauthorized; + }; + + /** + * Used to handle closing a modal dialog + * + * * @param {string} dialog the dialog to close + */ + var closeModal = function (dialog) { + $(dialog).modal('hide'); + }; + + /** + * Obtains the current state of the updateRequest using the specified update request id. + * + * @param {string} parameterProviderId parameter provider id + * @param {string} updateRequestId update request id + * @returns {deferred} update request xhr + */ + var getUpdateRequest = function (parameterProviderId, updateRequestId) { + return $.ajax({ + type: 'GET', + url: config.urls.parameterProviders + '/' + encodeURIComponent(parameterProviderId) + '/apply-parameters-requests/' + encodeURIComponent(updateRequestId), + dataType: 'json' + }).fail(nfErrorHandler.handleAjaxError); + }; + + /** + * Deletes an updateRequest using the specified update request id. + * + * @param {string} parameterProviderId parameter provider id + * @param {string} updateRequestId update request id + * @returns {deferred} update request xhr + */ + var deleteUpdateRequest = function (parameterProviderId, updateRequestId) { + return $.ajax({ + type: 'DELETE', + url: config.urls.parameterProviders + '/' + encodeURIComponent(parameterProviderId) + '/apply-parameters-requests/' + encodeURIComponent(updateRequestId) + '?' + $.param({ + 'disconnectedNodeAcknowledged': nfStorage.isDisconnectionAcknowledged() + }), + dataType: 'json' + }).fail(nfErrorHandler.handleAjaxError); + }; + + /** + * Submits a parameter provider update request. + * + * @param {object} parameterProviderEntity parameter provider id + * @returns {deferred} update request xhr + */ + var submitUpdateRequest = function (parameterProviderEntity) { + var requestEntity = { + 'id': parameterProviderEntity.id, + 'revision': nfClient.getRevision(parameterProviderEntity), + 'disconnectedNodeAcknowledged': nfStorage.isDisconnectionAcknowledged(), + 'parameterGroupConfigurations': parameterProviderEntity.component.parameterGroupConfigurations + } + + return $.ajax({ + type: 'POST', + data: JSON.stringify(requestEntity), + url: config.urls.parameterProviders + '/' + encodeURIComponent(requestEntity.id) + '/apply-parameters-requests', + dataType: 'json', + contentType: 'application/json' + }).fail(nfErrorHandler.handleAjaxError); + }; + + /** + * Submits a parameter provider update request. + * + * @param {object} parameterProviderEntity parameter provider id + * @returns {deferred} update request xhr + */ + var updateFetchParametersRequest = function (parameterProviderEntity) { + return $.ajax({ + type: 'POST', + data: JSON.stringify(parameterProviderEntity), + url: config.urls.parameterProviders + '/' + encodeURIComponent(parameterProviderEntity.id) + '/parameters/fetch-requests'+ '?' + $.param({ + 'disconnectedNodeAcknowledged': nfStorage.isDisconnectionAcknowledged() + }), + dataType: 'json', + contentType: 'application/json' + }).fail(nfErrorHandler.handleAjaxError); + }; + + /** + * Populates the fetch parameters update steps. + * + * @param {array} updateSteps steps to update + * @param {boolean} cancelled whether this request has been cancelled + * @param {boolean} errored whether this request has errored + */ + var populateFetchParametersUpdateStep = function (updateSteps, cancelled, errored) { + var updateStatusContainer = $('#fetch-parameters-update-steps').empty(); + + // go through each step + $.each(updateSteps, function (_, updateStep) { + var stepItem = $('
                  • ').text(updateStep.description).appendTo(updateStatusContainer); + + $('
                    ').addClass(function () { + if (nfCommon.isDefinedAndNotNull(updateStep.failureReason)) { + return 'ajax-error'; + } else { + if (updateStep.complete === true) { + return 'ajax-complete'; + } else { + return cancelled === true || errored === true ? 'ajax-error' : 'ajax-loading'; + } + } + }).appendTo(stepItem); + + $('
                    ').appendTo(stepItem); + }); + }; + + /** + * Loads the fetched parameters for the specified parameter group. + * + * @param {object} fetchedGroup the parameter group + */ + var loadFetchedParameters = function (fetchedGroup) { + var updatedGroup = fetchedGroup; + var isParameterContext = updatedGroup.isParameterContext; + var isCreateNewParameterContext = updatedGroup.createNewParameterContext; + + $('#fetched-parameters-listing').empty(); + + // get an instance of the grid + var groupsGrid = $('#parameter-groups-table').data('gridInstance'); + var groupsData = groupsGrid.getData(); + + // show the appropriate parameters table when dialog first opens + if (isParameterContext) { + // get the active group's parameters to populate the selectable parameters container + loadSelectableParameters(updatedGroup.id, updatedGroup.parameterSensitivities, updatedGroup); + + $('#parameters-container').show(); + $('#selectable-parameters-container').show(); + $('#fetched-parameters-container').hide(); + } else { + $('#selectable-parameters-container').hide(); + $('#fetched-parameters-container').show(); + } + + if (Object.keys(updatedGroup.parameterSensitivities).length !== 0) { + $('#create-parameter-context-checkbox-container').show(); + + /* Form the create parameter context checkbox */ + var parametersCheckboxContainer = $('#create-parameter-context-checkbox-container').empty(); + var createParamContextContainer; + + /* Form the parameter context name input */ + if (isParameterContext) { + // only show the name + createParamContextContainer = $('
                    '); + + $('
                    ' + + '
                    Parameter Context Name
                    ' + + '
                    ' + + '
                    ' + nfCommon.escapeHtml(fetchedGroup.parameterContextName) + '
                    ' + + '
                    ').appendTo(createParamContextContainer); + } else { + + var checkboxMarkup = $('
                    '); + + if (isCreateNewParameterContext) { + // select checkbox + $('
                    ').appendTo(checkboxMarkup); + + loadSelectableParameters(updatedGroup.id, updatedGroup.parameterSensitivities, updatedGroup); + + $('#parameters-container').show(); + $('#selectable-parameters-container').show(); + $('#fetched-parameters-container').hide(); + } else { + // deselect checkbox + $('
                    ').appendTo(checkboxMarkup); + + $('#selectable-parameters-container').hide(); + $('#fetched-parameters-container').show(); + } + + $('
                    ' + + 'Create Parameter Context' + + '
                    ').appendTo(checkboxMarkup); + + var settingMarkup = $('
                    '); + $(checkboxMarkup).appendTo(settingMarkup); + $(settingMarkup).appendTo(parametersCheckboxContainer); + + // create the input container and set visibility + if (isCreateNewParameterContext) { + createParamContextContainer = $('
                    '); + } else { + createParamContextContainer = $(''); + } + + // create the input + $('
                    ' + + '
                    Parameter Context Name
                    ' + + '
                    ' + + '
                    ' + + '
                    ').appendTo(createParamContextContainer); + } + + createParamContextContainer.appendTo(parametersCheckboxContainer); + + // populate the name input + var contextName = updatedGroup.parameterContextName; + $('#create-parameter-context-input').val(contextName); + } else { + $('#create-parameter-context-checkbox-container').hide(); + } + + /* Form the parameters listing */ + var fetchedParametersContainer = $('#fetched-parameters-listing').empty(); + var fetchedParameters = updatedGroup.parameterSensitivities; + + // get parameter names only + var parametersArray = Object.keys(fetchedParameters); + + // create parameter names listing + if (parametersArray.length > 0) { + $.each(parametersArray, function (i, parameter) { + var li = $('
                  • ').text(parameter); + $('
                    ').appendTo(li); + li.appendTo(fetchedParametersContainer); + }) + } else { + // set to none + $('
                    None
                    ').appendTo(fetchedParametersContainer); + } + + // update the border if necessary + updateReferencingComponentsBorder($('#fetched-parameters-listing-container')); + + /* Temporarily save any changes */ + // begin updating the group table + groupsData.beginUpdate(); + + // save parameter context name change + $('#create-parameter-context-input').on('blur', function () { + // get the input value + updatedGroup.parameterContextName = $('#create-parameter-context-input').val(); + + // update the group item + groupsData.updateItem(updatedGroup.id, updatedGroup); + + // update the list of parameters to be created + loadParameterContextsToCreate(); + + $('#fetch-parameters-dialog').modal('refreshButtons'); + }) + + // create parameter checkbox behaviors + $('#create-parameter-context-field').off().on('change', function (event, args) { + // if checked then show the name input, hide parameters listing, show selectable parameters table + if (args.isChecked) { + updatedGroup.createNewParameterContext = true; + + loadSelectableParameters(updatedGroup.id, updatedGroup.parameterSensitivities, updatedGroup); + + $('#fetched-parameters-container').hide(); + $('#create-parameter-context-container').show(); + $('#selectable-parameters-container').show(); + $('#fetch-parameters-dialog').modal('refreshButtons'); + } else { + // if unchecked, then hide the input and only show the parameters listing + updatedGroup.createNewParameterContext = false; + + loadSelectableParameters(updatedGroup.id, updatedGroup.parameterSensitivities, updatedGroup); + + $('#create-parameter-context-container').hide(); + $('#selectable-parameters-container').hide(); + $('#fetched-parameters-container').show(); + $('#fetch-parameters-dialog').modal('refreshButtons'); + } + + // update the group item + groupsData.updateItem(updatedGroup.id, updatedGroup); + }); + + // finish updating the group table + groupsData.endUpdate(); + groupsData.reSort(); + }; + + /** + * Reset the dialog. + */ + var resetFetchParametersDialog = function () { + $('#fetch-parameters-affected-referencing-components-container').hide(); + $('#fetch-parameters-referencing-components-container').show(); + $('#fetch-parameters-permissions-parameter-contexts-message').addClass('hidden'); + $('#fetch-parameters-permissions-affected-components-message').addClass('hidden'); + $('#create-parameter-context-input').val(''); + + var headerCheckbox = $('#selectable-parameters-table .slick-column-name input'); + headerCheckbox.removeAttr('checked'); + + // clear the groups table + var groupsGrid = $('#parameter-groups-table').data('gridInstance'); + var groupsData = groupsGrid.getData(); + groupsGrid.setSelectedRows([]); + groupsData.setItems([]); + + // clear the selectable parameters table + var selectableParametersGrid = $('#selectable-parameters-table').data('gridInstance'); + var selectableParametersData = selectableParametersGrid.getData(); + selectableParametersGrid.setSelectedRows([]); + selectableParametersData.setItems([]); + + resetUsage(); + + // reset the last selected + lastSelectedGroupId = null; + lastSelectedParameterId = null; + }; + + var lastSelectedGroupId = null; + var lastSelectedParameterId = null; + + /** + * Sorts the specified data using the specified sort details. + * + * @param {object} sortDetails + * @param {object} data + */ + var sortParameters = function (sortDetails, data) { + // defines a function for sorting + var comparer = function (a, b) { + // direct parameters always come above inherited ones + if (a.isInherited === false && b.isInherited === true) { + return -1; + } + if (a.isInherited === true && b.isInherited === false) { + return 1; + } + if (sortDetails.columnId === 'name') { + var aString = _.get(a, '[' + sortDetails.columnId + ']', ''); + var bString = _.get(b, '[' + sortDetails.columnId + ']', ''); + return aString === bString ? 0 : aString > bString ? 1 : -1; + } + }; + + // perform the sort + data.sort(comparer, sortDetails.sortAsc); + }; + + /** + * Sorts the specified entities based on the name. + * + * @param {object} a + * @param {object} b + * @returns {number} + */ + var nameComparator = function (a, b) { + return a.component.name.localeCompare(b.component.name); + }; + + /** + * 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) { + return item.hidden === false; + }; + + /** + * Renders the bulletins as a tooltip of the bulletinIconElement, shows the icon + * + * @param bulletins bulletins to be rendered + * @param bulletinIconElement jQuery element to display as the bulletin icon and source for the tooltip + */ + var renderBulletins = function (bulletins, bulletinIconElement) { + // format the new bulletins + var formattedBulletins = nfCommon.getFormattedBulletins(bulletins); + + var list = nfCommon.formatUnorderedList(formattedBulletins); + + // update existing tooltip or initialize a new one if appropriate + bulletinIconElement.addClass('has-bulletins').show().qtip($.extend({}, + nfCanvasUtils.config.systemTooltipConfig, + { + content: list + })); + } + + /** + * Populates the referencing components for the specified parameter context. + * + * @param {object} referencingComponents + */ + var populateReferencingComponents = function (referencingComponents) { + // toggles the visibility of a container + var toggle = function (twist, container) { + if (twist.hasClass('expanded')) { + twist.removeClass('expanded').addClass('collapsed'); + container.hide(); + } else { + twist.removeClass('collapsed').addClass('expanded'); + container.show(); + } + }; + + var referencingProcessors = []; + var referencingControllerServices = []; + var unauthorizedReferencingComponents = []; + + var spinner = $('#fetch-parameters-referencing-components-container .referencing-components-loading'); + + var loadingDeferred = $.Deferred(function (deferred) { + spinner.addClass('ajax-loading'); + deferred.resolve(); + }); + loadingDeferred.then(function () { + resetUsage(); + }).then(function() { + var fetchParameterReferencingComponentsContainer = $('#fetch-parameter-referencing-components-container').empty(); + + // referencing component will be undefined when a new parameter is added + if (_.isEmpty(referencingComponents)) { + // set to pending + $('
                    None
                    ').appendTo(fetchParameterReferencingComponentsContainer); + } else { + // bin the referencing components according to their type + $.each(referencingComponents.parameter.parameter.referencingComponents, function (_, referencingComponentEntity) { + if (referencingComponentEntity.permissions.canRead === true && referencingComponentEntity.permissions.canWrite === true) { + if (referencingComponentEntity.component.referenceType === 'PROCESSOR') { + referencingProcessors.push(referencingComponentEntity); + } else { + referencingControllerServices.push(referencingComponentEntity); + } + } else { + unauthorizedReferencingComponents.push(referencingComponentEntity); + } + }); + + var referencingProcessGroups = {}; + + // bin the referencing processors according to their PG + $.each(referencingProcessors, function (_, referencingProcessorEntity) { + if (referencingProcessGroups[referencingProcessorEntity.processGroup.id]) { + referencingProcessGroups[referencingProcessorEntity.processGroup.id].referencingProcessors.push(referencingProcessorEntity); + referencingProcessGroups[referencingProcessorEntity.processGroup.id].id = referencingProcessorEntity.processGroup.id; + referencingProcessGroups[referencingProcessorEntity.processGroup.id].name = referencingProcessorEntity.processGroup.name; + } else { + referencingProcessGroups[referencingProcessorEntity.processGroup.id] = { + referencingProcessors: [], + referencingControllerServices: [], + unauthorizedReferencingComponents: [], + name: referencingProcessorEntity.processGroup.name, + id: referencingProcessorEntity.processGroup.id + }; + + referencingProcessGroups[referencingProcessorEntity.processGroup.id].referencingProcessors.push(referencingProcessorEntity); + } + }); + + // bin the referencing CS according to their PG + $.each(referencingControllerServices, function (_, referencingControllerServiceEntity) { + if (referencingProcessGroups[referencingControllerServiceEntity.processGroup.id]) { + referencingProcessGroups[referencingControllerServiceEntity.processGroup.id].referencingControllerServices.push(referencingControllerServiceEntity); + referencingProcessGroups[referencingControllerServiceEntity.processGroup.id].id = referencingControllerServiceEntity.processGroup.id; + referencingProcessGroups[referencingControllerServiceEntity.processGroup.id].name = referencingControllerServiceEntity.processGroup.name; + } else { + referencingProcessGroups[referencingControllerServiceEntity.processGroup.id] = { + referencingProcessors: [], + referencingControllerServices: [], + unauthorizedReferencingComponents: [], + name: referencingControllerServiceEntity.processGroup.name, + id: referencingControllerServiceEntity.processGroup.id + }; + + referencingProcessGroups[referencingControllerServiceEntity.processGroup.id].referencingControllerServices.push(referencingControllerServiceEntity); + } + }); + + // bin the referencing unauthorized components according to their PG + $.each(unauthorizedReferencingComponents, function (_, unauthorizedReferencingComponentEntity) { + if (referencingProcessGroups[unauthorizedReferencingComponentEntity.processGroup.id]) { + referencingProcessGroups[unauthorizedReferencingComponentEntity.processGroup.id].unauthorizedReferencingComponents.push(unauthorizedReferencingComponentEntity); + referencingProcessGroups[unauthorizedReferencingComponentEntity.processGroup.id].id = unauthorizedReferencingComponentEntity.processGroup.id; + referencingProcessGroups[unauthorizedReferencingComponentEntity.processGroup.id].name = unauthorizedReferencingComponentEntity.processGroup.name; + } else { + referencingProcessGroups[unauthorizedReferencingComponentEntity.processGroup.id] = { + referencingProcessors: [], + referencingControllerServices: [], + unauthorizedReferencingComponents: [], + name: unauthorizedReferencingComponentEntity.processGroup.name, + id: unauthorizedReferencingComponentEntity.processGroup.id + }; + + referencingProcessGroups[unauthorizedReferencingComponentEntity.processGroup.id].unauthorizedReferencingComponents.push(unauthorizedReferencingComponentEntity); + } + }); + + var fetchParameterReferencingComponentsContainer = $('#fetch-parameter-referencing-components-container'); + var groups = $('
                      '); + + var referencingProcessGroupsArray = []; + for (var key in referencingProcessGroups) { + if (referencingProcessGroups.hasOwnProperty(key)) { + referencingProcessGroupsArray.push(referencingProcessGroups[key]); + } + } + + if (nfCommon.isEmpty(referencingProcessGroupsArray)) { + // set to none + $('
                      None
                      ').appendTo(fetchParameterReferencingComponentsContainer); + } else { + //sort alphabetically + var sortedReferencingProcessGroups = referencingProcessGroupsArray.sort(function (a, b) { + if (a.name < b.name) { + return -1; + } + if (a.name > b.name) { + return 1; + } + return 0; + }); + + sortedReferencingProcessGroups.forEach(function (referencingProcessGroup) { + // container for this pg's references + var referencingPgReferencesContainer = $('
                      '); + fetchParameterReferencingComponentsContainer.append(referencingPgReferencesContainer); + + // create the collapsable listing for each PG + var createReferenceBlock = function (referencingProcessGroup, list) { + var twist = $(''); + var title = $('').text(referencingProcessGroup.name); + var count = $('').text('(' + (referencingProcessGroup.referencingProcessors.length + referencingProcessGroup.referencingControllerServices.length + referencingProcessGroup.unauthorizedReferencingComponents.length) + ')'); + var referencingComponents = $('#fetch-parameters-referencing-components-template').clone(); + referencingComponents.removeAttr('id'); + referencingComponents.removeClass('hidden'); + + // create the reference block + var groupTwist = $('
                      ').data('processGroupId', referencingProcessGroup.id).on('click', function () { + if (twist.hasClass('collapsed')) { + groupTwist.append(referencingComponents); + + var processorContainer = groupTwist.find('.fetch-parameters-referencing-processors'); + nfCommon.cleanUpTooltips(processorContainer, 'div.referencing-component-state'); + nfCommon.cleanUpTooltips(processorContainer, 'div.referencing-component-bulletins'); + processorContainer.empty(); + + var controllerServiceContainer = groupTwist.find('.fetch-parameters-referencing-controller-services'); + nfCommon.cleanUpTooltips(controllerServiceContainer, 'div.referencing-component-state'); + nfCommon.cleanUpTooltips(controllerServiceContainer, 'div.referencing-component-bulletins'); + controllerServiceContainer.empty(); + + var unauthorizedComponentsContainer = groupTwist.find('.fetch-parameters-referencing-unauthorized-components').empty(); + + if (referencingProcessGroups[$(this).data('processGroupId')].referencingProcessors.length === 0) { + $('
                    • None
                    • ').appendTo(processorContainer); + } else { + // sort the referencing processors + referencingProcessGroups[$(this).data('processGroupId')].referencingProcessors.sort(nameComparator); + + // render each and register a click handler + $.each(referencingProcessGroups[$(this).data('processGroupId')].referencingProcessors, function (_, referencingProcessorEntity) { + renderReferencingProcessor(referencingProcessorEntity, processorContainer); + }); + } + + if (referencingProcessGroups[$(this).data('processGroupId')].referencingControllerServices.length === 0) { + $('
                    • None
                    • ').appendTo(controllerServiceContainer); + } else { + // sort the referencing controller services + referencingProcessGroups[$(this).data('processGroupId')].referencingControllerServices.sort(nameComparator); + + // render each and register a click handler + $.each(referencingProcessGroups[$(this).data('processGroupId')].referencingControllerServices, function (_, referencingControllerServiceEntity) { + renderReferencingControllerService(referencingControllerServiceEntity, controllerServiceContainer); + }); + } + + if (referencingProcessGroups[$(this).data('processGroupId')].unauthorizedReferencingComponents.length === 0) { + $('
                    • None
                    • ').appendTo(unauthorizedComponentsContainer); + } else { + // sort the unauthorized referencing components + referencingProcessGroups[$(this).data('processGroupId')].unauthorizedReferencingComponents.sort(function (a, b) { + if (a.permissions.canRead === true && b.permissions.canRead === true) { + // processors before controller services + var sortVal = a.component.referenceType === b.component.referenceType ? 0 : a.component.referenceType > b.component.referenceType ? -1 : 1; + + // if a and b are the same type, then sort by name + if (sortVal === 0) { + sortVal = a.component.name === b.component.name ? 0 : a.component.name > b.component.name ? 1 : -1; + } + + return sortVal; + } else { + + // if lacking read and write perms on both, sort by id + if (a.permissions.canRead === false && b.permissions.canRead === false) { + return a.id > b.id ? 1 : -1; + } else { + // if only one has read perms, then let it come first + if (a.permissions.canRead === true) { + return -1; + } else { + return 1; + } + } + } + }); + + $.each(referencingProcessGroups[$(this).data('processGroupId')].unauthorizedReferencingComponents, function (_, unauthorizedReferencingComponentEntity) { + if (unauthorizedReferencingComponentEntity.permissions.canRead === true) { + if (unauthorizedReferencingComponentEntity.component.referenceType === 'PROCESSOR') { + renderReferencingProcessor(unauthorizedReferencingComponentEntity, unauthorizedComponentsContainer); + } else { + renderReferencingControllerService(unauthorizedReferencingComponentEntity, unauthorizedComponentsContainer); + } + } else { + var referencingUnauthorizedComponentContainer = $('
                    • ').appendTo(unauthorizedComponentsContainer); + $('') + .prop('title', unauthorizedReferencingComponentEntity.id) + .text(unauthorizedReferencingComponentEntity.id) + .on('click', function () { + // check if there are outstanding changes + handleOutstandingChanges().done(function () { + // close the shell + $('#shell-dialog').modal('hide'); + + // show the component in question + if (unauthorizedReferencingComponentEntity.referenceType === 'PROCESSOR') { + nfCanvasUtils.showComponent(unauthorizedReferencingComponentEntity.processGroup.id, unauthorizedReferencingComponentEntity.id); + } else if (unauthorizedReferencingComponentEntity.referenceType === 'CONTROLLER_SERVICE') { + nfProcessGroupConfiguration.showConfiguration(unauthorizedReferencingComponentEntity.processGroup.id).done(function () { + nfProcessGroup.enterGroup(unauthorizedReferencingComponentEntity.processGroup.id); + nfProcessGroupConfiguration.selectControllerService(unauthorizedReferencingComponentEntity.id); + }); + } + }); + }) + .appendTo(referencingUnauthorizedComponentContainer); + } + }); + } + } else { + groupTwist.find('.fetch-parameters-referencing-components-template').remove(); + } + + // toggle this block + toggle(twist, list); + + // update the border if necessary + updateReferencingComponentsBorder($('#fetch-parameter-referencing-components-container')); + }).append(twist).append(title).append(count).appendTo(referencingPgReferencesContainer); + + // add the listing + list.appendTo(referencingPgReferencesContainer); + + // expand the group twist + groupTwist.click(); + }; + + // create block for this process group + createReferenceBlock(referencingProcessGroup, groups); + }); + } + } + }) + .always(function () { + spinner.removeClass('ajax-loading'); + }); + return loadingDeferred.promise(); + }; + + /** + * Renders the specified referencing component. + * + * @param {object} referencingProcessorEntity + * @param {jQuery} container + */ + var renderReferencingProcessor = function (referencingProcessorEntity, container) { + var referencingProcessorContainer = $('
                    • ').appendTo(container); + var referencingProcessor = referencingProcessorEntity.component; + + // processor state + $('
                      ').addClass(function () { + if (nfCommon.isDefinedAndNotNull(referencingProcessor.state)) { + var icon = $(this); + + var state = referencingProcessor.state.toLowerCase(); + if (state === 'stopped' && !nfCommon.isEmpty(referencingProcessor.validationErrors)) { + state = 'invalid'; + + // build the validation error listing + var list = nfCommon.formatUnorderedList(referencingProcessor.validationErrors); + + // add tooltip for the warnings + icon.qtip($.extend({}, + nfCanvasUtils.config.systemTooltipConfig, + { + content: list + })); + } + + return state; + } else { + return ''; + } + }).appendTo(referencingProcessorContainer); + + + // processor name + $('') + .prop('title', referencingProcessor.name) + .text(referencingProcessor.name) + .on('click', function () { + // close the shell + $('#shell-dialog').modal('hide'); + + // show the component in question + nfCanvasUtils.showComponent(referencingProcessorEntity.processGroup.id, referencingProcessor.id); + $('#fetch-parameters-dialog').modal('hide'); + }).appendTo(referencingProcessorContainer); + + // bulletin + var bulletinIcon = $('
                      ').addClass(referencingProcessor.id + '-referencing-bulletins'); + bulletinIcon.appendTo(referencingProcessorContainer); + if (!nfCommon.isEmpty(referencingProcessorEntity.bulletins)) { + renderBulletins(referencingProcessorEntity.bulletins, bulletinIcon); + } + + // processor active threads + $('').text(function () { + if (nfCommon.isDefinedAndNotNull(referencingProcessor.activeThreadCount) && referencingProcessor.activeThreadCount > 0) { + return '(' + referencingProcessor.activeThreadCount + ')'; + } else { + return ''; + } + }).appendTo(referencingProcessorContainer); + }; + + /** + * Renders the specified affect controller service. + * + * @param {object} referencingControllerServiceEntity + * @param {jQuery} container + */ + var renderReferencingControllerService = function (referencingControllerServiceEntity, container) { + var referencingControllerServiceContainer = $('
                    • ').appendTo(container); + var referencingControllerService = referencingControllerServiceEntity.component; + + // controller service state + $('
                      ').addClass(function () { + if (nfCommon.isDefinedAndNotNull(referencingControllerService.state)) { + var icon = $(this); + + var state = referencingControllerService.state === 'ENABLED' ? 'enabled' : 'disabled'; + if (state === 'disabled' && !nfCommon.isEmpty(referencingControllerService.validationErrors)) { + state = 'invalid'; + + // build the error listing + var list = nfCommon.formatUnorderedList(referencingControllerService.validationErrors); + + // add tooltip for the warnings + icon.qtip($.extend({}, + nfCanvasUtils.config.systemTooltipConfig, + { + content: list + })); + } + return state; + } else { + return ''; + } + }).appendTo(referencingControllerServiceContainer); + + // bulletin + var bulletinIcon = $('
                      ') + .addClass(referencingControllerService.id + '-referencing-bulletins') + .appendTo(referencingControllerServiceContainer); + if (!nfCommon.isEmpty(referencingControllerServiceEntity.bulletins)) { + renderBulletins(referencingControllerServiceEntity.bulletins, bulletinIcon); + } + + // controller service name + $('') + .prop('title', referencingControllerService.name) + .text(referencingControllerService.name) + .on('click', function () { + // close the shell + $('#shell-dialog').modal('hide'); + + nfProcessGroup.enterGroup(referencingControllerService.processGroupId); + + // show the component in question + nfProcessGroupConfiguration.showConfiguration(referencingControllerService.processGroupId) + .done(function () { + nfProcessGroupConfiguration.selectControllerService(referencingControllerService.id); + $('#fetch-parameters-dialog').modal('hide'); + }); + }).appendTo(referencingControllerServiceContainer); + }; + + /** + * Initializes the selectable parameters table + */ + var initSelectableParametersTable = function () { + var selectableParametersTable = $('#selectable-parameters-table'); + + var nameFormatter = function (row, cell, value, columnDef, dataContext) { + var valueWidthOffset = 10; + var cellContent = $('
                      '); + + // format the contents + var formattedValue = $('').addClass('table-cell').text(value).appendTo(cellContent); + if (dataContext.type === 'required') { + formattedValue.addClass('required'); + } + + if (dataContext.isAffectedParameter || dataContext.parameterStatus.status === 'CHANGED') { + valueWidthOffset += 30; + $('
                      ').appendTo(cellContent); + } + + if (dataContext.isReferencingParameter) { + valueWidthOffset += 30; + $('
                      ').appendTo(cellContent); + } + + // adjust the width accordingly + formattedValue.width(columnDef.width - valueWidthOffset).ellipsis(); + + // return the cell content + return cellContent.html(); + }; + + var checkboxSelectionFormatter = function (row, cell, value, columnDef, dataContext) { + if (dataContext) { + if (_.isEmpty(dataContext.parameterStatus) || _.isEmpty(dataContext.parameterStatus.parameter.parameter.referencingComponents)) { + if (dataContext.sensitivity === SENSITIVE) { + return ""; + } else { + return ""; + } + } + + if (!_.isEmpty(dataContext.parameterStatus.parameter.parameter.referencingComponents)) { + // disable checkboxes + if (dataContext.sensitivity === SENSITIVE) { + return ""; + } else { + return ""; + } + } + + $('#fetch-parameters-dialog').modal('refreshButtons'); + } + return null; + }; + + var parametersColumn = []; + + // define the column models for the table + var nameColumnDefinition = { + id: 'name', + name: 'Parameter Name', + field: 'name', + formatter: nameFormatter, + sortable: true, + resizable: false, + rerenderOnResize: true, + width: 280, + minWidth: 280, + editor: Slick.Editors.Text + }; + + var checkboxColumnDefinition = { + id: 'selector', + field: 'sel', + width: 30, + resizable: false, + sortable: false, + cssClass: 'slick-cell-checkboxsel', + hideSelectAllCheckbox: false, + formatter: checkboxSelectionFormatter + } + + parametersColumn.push(checkboxColumnDefinition); + parametersColumn.push(nameColumnDefinition); + + // initialize the dataview + var selectableParametersData = new Slick.Data.DataView({ + inlineFilters: false + }); + + // initialize the sort + sortParameters({ + columnId: 'name', + sortAsc: true + }, selectableParametersData); + + + // initialize the grid + var selectableParametersGrid = new Slick.Grid(selectableParametersTable, selectableParametersData, parametersColumn, selectableParametersGridOptions); + selectableParametersGrid.setSelectionModel(new Slick.RowSelectionModel()); + selectableParametersGrid.registerPlugin(new Slick.AutoTooltips()); + + selectableParametersGrid.setSortColumn('name', true); + selectableParametersGrid.onSort.subscribe(function (e, args) { + sortParameters({ + columnId: args.sortCol.id, + sortAsc: args.sortAsc + }, selectableParametersData); + }); + + selectableParametersGrid.onClick.subscribe(function (e, args) { + var target = $(e.target); + // get the node at this row + var item = selectableParametersData.getItem(args.row); + var saveToGroup = false; + + if (selectableParametersGrid.getColumns()[args.cell].id === 'selector') { + if (target.hasClass('unchecked-input-enabled')) { + saveToGroup = true; + // check the box + item.sensitivity = SENSITIVE; + selectableParametersData.updateItem(item.id, item) + } else if (target.hasClass('checked-input-enabled')) { + saveToGroup = true; + // uncheck the box + item.sensitivity = NON_SENSITIVE; + selectableParametersData.updateItem(item.id, item) + } + + // save to its group + if (saveToGroup) { + var groupsGrid = $('#parameter-groups-table').data('gridInstance'); + var groupsData = groupsGrid.getData(); + var currentGroup = groupsData.getItem([item.groupId]); + + currentGroup.parameterSensitivities[item.name] = item.sensitivity; + groupsData.updateItem(item.groupId, currentGroup); + + $('#fetch-parameters-dialog').modal('refreshButtons'); + } + } + }) + + selectableParametersGrid.onSelectedRowsChanged.subscribe(function (e, args) { + if ($.isArray(args.rows) && args.rows.length === 1) { + // show the referencing components for the selected parameter + if (selectableParametersGrid.getDataLength() > 0) { + var parameterIndex = args.rows[0]; + var parameter = selectableParametersGrid.getDataItem(parameterIndex); + + // only populate referencing components if this parameter is different than the last selected + if (lastSelectedParameterId === null || lastSelectedParameterId !== parameter.id) { + + populateReferencingComponents(parameter.parameterStatus) + .then(function () { + updateReferencingComponentsBorder($('#fetch-parameter-referencing-components-container')); + + // update the last selected id + lastSelectedParameterId = parameter.id; + }); + } + } + } + + $('#fetch-parameters-dialog').modal('refreshButtons'); + }) + + // wire up the dataview to the grid + selectableParametersData.onRowCountChanged.subscribe(function (e, args) { + var selectableParameters = args.dataView.getItems(); + + if (!_.isEmpty(selectableParameters)) { + var groupsGrid = $('#parameter-groups-table').data('gridInstance'); + var groupsData = groupsGrid.getData(); + var currentGroupId = selectableParameters[0].groupId; + var currentGroup = groupsData.getItem([currentGroupId]); + + if (!currentGroup.isParameterContext) { + // update parameter sensitivities + var paramSensitivities = {}; + $.each(selectableParameters, function (i, param) { + paramSensitivities[param.name] = param.sensitivity; + }) + + // save to its group + currentGroup.parameterSensitivities = paramSensitivities; + groupsData.updateItems(currentGroupId, currentGroup); + } + } + + selectableParametersGrid.updateRowCount(); + selectableParametersGrid.render(); + }); + selectableParametersData.onRowsChanged.subscribe(function (e, args) { + selectableParametersGrid.invalidateRows(args.rows); + selectableParametersGrid.render(); + }); + selectableParametersData.syncGridSelection(selectableParametersGrid, true); + + // hold onto an instance of the grid and create an affected component tooltip + selectableParametersTable.data('gridInstance', selectableParametersGrid).on('mouseenter', 'div.slick-cell', function (e) { + var asteriskIconElement = $(this).find('div.fa-asterisk'); + var asteriskTooltipContent = nfCommon.escapeHtml('Value has changed.'); + + // initialize tooltip + asteriskIconElement.qtip($.extend({}, + nfCommon.config.tooltipConfig, + { + content: asteriskTooltipContent + })); + + var hashtagIconElement = $(this).find('div.fa-hashtag'); + var hashtagTooltipContent = nfCommon.escapeHtml('This parameter is currently referenced by a property. The sensitivity cannot be changed.'); + + // initialize tooltip + hashtagIconElement.qtip($.extend({}, + nfCommon.config.tooltipConfig, + { + content: hashtagTooltipContent + })); + }); + + /** + * Select or deselect parameters that are not disabled. + * + * @param selectionType The type of selection. + */ + var selectOrDeselectAll = function (selectionType) { + var sensitivity = selectionType === 'select' ? SENSITIVE : NON_SENSITIVE; + + // get all selectable parameters + var selectableParams = []; + $.each(selectableParametersData.getItems(), function (i, param) { + if (!param.isReferencingParameter) { + selectableParams.push(param); + } + }); + + if (!_.isEmpty(selectableParams)) { + var groupsGrid = $('#parameter-groups-table').data('gridInstance'); + var groupsData = groupsGrid.getData(); + var currentGroupId = groupsGrid.getSelectedRows(); + var currentGroup = groupsData.getItem(currentGroupId); + + // begin updating + groupsData.beginUpdate(); + + // set sensitivities + $.each(selectableParams, function (i, param) { + var updateParamItem = $.extend(param, { sensitivity: sensitivity }); + selectableParametersData.updateItem(param.id, updateParamItem); + + // save to its group + currentGroup.parameterSensitivities[param.name] = sensitivity; + }) + + // complete the update + groupsData.endUpdate(); + + $('#fetch-parameters-dialog').modal('refreshButtons'); + } + } + + $('#select-all-fetched-parameters').on('click', function() { + selectOrDeselectAll('select'); + }); + + $('#deselect-all-fetched-parameters').on('click', function() { + selectOrDeselectAll('deselect'); + }); + + // end + } + + /** + * Initializes the parameter groups table + */ + var initParameterGroupsTable = function () { + var parameterGroupsTable = $('#parameter-groups-table'); + + var nameFormatter = function (row, cell, value, columnDef, dataContext) { + var nameWidthOffset = 30; + var cellContent = $('
                      '); + + // format the contents + var formattedValue = $('').addClass('table-cell').text(value).appendTo(cellContent); + if (dataContext.type === 'required') { + formattedValue.addClass('required'); + } + + // add icon if group is or will be created as a parameter context + if (dataContext.isParameterContext || dataContext.createNewParameterContext) { + $('
                      ').appendTo(cellContent); + } + + // adjust the width accordingly + formattedValue.width(columnDef.width - nameWidthOffset).ellipsis(); + + // return the cell content + return cellContent.html(); + }; + + // define the column model for the table + var groupsColumn = [ + { + id: 'name', + name: 'Parameter Group Name', + field: 'name', + formatter: nameFormatter, + sortable: true, + resizable: true, + rerenderOnResize: true, + width: 327, + minWidth: 327, + maxWidth: 327 + } + ]; + + // initialize the dataview + var groupsData = new Slick.Data.DataView({ + inlineFilters: false + }); + groupsData.setFilterArgs({ + searchString: '', + property: 'hidden' + }); + groupsData.setFilter(filter); + + // initialize the sort + sortParameters({ + columnId: 'name', + sortAsc: true + }, groupsData); + + // initialize the grid + var groupsGrid = new Slick.Grid(parameterGroupsTable, groupsData, groupsColumn, parameterGroupsGridOptions); + groupsGrid.setSelectionModel(new Slick.RowSelectionModel()); + groupsGrid.registerPlugin(new Slick.AutoTooltips()); + groupsGrid.setSortColumn('name', true); + groupsGrid.onSort.subscribe(function (e, args) { + sortParameters({ + columnId: args.sortCol.id, + sortAsc: args.sortAsc + }, groupsData); + }); + groupsGrid.onSelectedRowsChanged.subscribe(function (e, args) { + // clean up tooltips + nfCommon.cleanUpTooltips($('#selectable-parameters-table'), 'div.fa-asterisk'); + nfCommon.cleanUpTooltips($('#selectable-parameters-table'), 'div.fa-hashtag'); + + if ($.isArray(args.rows) && args.rows.length === 1) { + if (groupsGrid.getDataLength() > 0) { + var groupIndex = args.rows[0]; + var group = groupsGrid.getDataItem(groupIndex); + + // only populate fetch parameters column if this group is different than the last selected + if (lastSelectedGroupId === null || lastSelectedGroupId !== group.id) { + loadFetchedParameters(group); + + // update the last selected id + lastSelectedGroupId = group.id; + + // populate parameter referencing components + var selectableParametersGrid = $('#selectable-parameters-table').data('gridInstance'); + var selectedRow = selectableParametersGrid.getSelectedRows()[0]; + var parameter = selectableParametersGrid.getData().getItem(selectedRow); + + if (parameter && group.isParameterContext) { + populateReferencingComponents(parameter.parameterStatus).then(function () { + updateReferencingComponentsBorder($('#fetch-parameter-referencing-components-container')); + }); + } else { + // show 'None' for referencing components + populateReferencingComponents({}).then(function () { + updateReferencingComponentsBorder($('#fetch-parameter-referencing-components-container')); + }); + } + } + } + } + }); + groupsGrid.onBeforeCellEditorDestroy.subscribe(function (e, args) { + setTimeout(function () { + groupsGrid.resizeCanvas(); + }, 50); + }); + + // wire up the dataview to the grid + groupsData.onRowCountChanged.subscribe(function (e, args) { + groupsGrid.updateRowCount(); + groupsGrid.render(); + }); + groupsData.onRowsChanged.subscribe(function (e, args) { + groupsGrid.invalidateRows(args.rows); + groupsGrid.render(); + }); + groupsData.syncGridSelection(groupsGrid, true); + + // hold onto an instance of the grid and create parameter context tooltip + parameterGroupsTable.data('gridInstance', groupsGrid).on('mouseenter', 'div.slick-cell', function (e) { + var starIconElement = $(this).find('div.fa-star'); + var tooltipContent = nfCommon.escapeHtml('Synced to a parameter context.'); + + // initialize tooltip + starIconElement.qtip($.extend({}, + nfCommon.config.tooltipConfig, + { + content: tooltipContent + })); + }); + }; + // end initParameterGroupTable + + var resetUsage = function () { + // empty the containers + var fetchParameterRefComponents = $('#fetch-parameter-referencing-components-container .referencing-component-references'); + fetchParameterRefComponents.empty(); + var fetchParameterRefComponentsContainer = $('#fetch-parameter-referencing-components-container'); + + var processorContainer = $('.fetch-parameters-referencing-processors'); + nfCommon.cleanUpTooltips(processorContainer, 'div.referencing-component-state'); + nfCommon.cleanUpTooltips(processorContainer, 'div.referencing-component-bulletins'); + processorContainer.empty(); + + var controllerServiceContainer = $('.fetch-parameters-referencing-controller-services'); + nfCommon.cleanUpTooltips(controllerServiceContainer, 'div.referencing-component-state'); + nfCommon.cleanUpTooltips(controllerServiceContainer, 'div.referencing-component-bulletins'); + controllerServiceContainer.empty(); + + var unauthorizedComponentsContainer = $('.fetch-parameters-referencing-unauthorized-components').empty(); + + $('#affected-referencing-components-container').empty(); + + // reset the last selected + lastSelectedGroupId = null; + lastSelectedParameterId = null; + + // indicate no referencing components + $('
                      None
                      ').appendTo(fetchParameterRefComponentsContainer); + $('
                    • None
                    • ').appendTo(processorContainer); + $('
                    • None
                    • ').appendTo(controllerServiceContainer); + $('
                    • None
                    • ').appendTo(unauthorizedComponentsContainer); + }; + + var currentParameterProviderEntity = null; + + var nfParameterProvider = { + /** + * Initializes the parameter provider configuration dialog. + * + * @param options Option settings for the parameter provider. + */ + init: function (options) { + nfSettings = options.nfSettings; + fetchParameterProviderOptions = options.statusBarOptions; + + + // initialize the configuration dialog tabs + $('#parameter-provider-configuration-tabs').tabbs({ + tabStyle: 'tab', + selectedTabStyle: 'selected-tab', + scrollableTabContentStyle: 'scrollable', + tabs: [{ + name: 'Settings', + tabContentId: 'parameter-provider-standard-settings-tab-content' + }, { + name: 'Properties', + tabContentId: 'parameter-provider-properties-tab-content' + }, { + name: 'Comments', + tabContentId: 'parameter-provider-comments-tab-content' + }], + select: function () { + // remove all property detail dialogs + nfUniversalCapture.removeAllPropertyDetailDialogs(); + + // update the property table size in case this is the first time its rendered + if ($(this).text() === 'Properties') { + $('#parameter-provider-properties').propertytable('resetTableSize'); + } + + // close all fields currently being edited + $('#parameter-provider-properties').propertytable('saveRow'); + } + }); + + // initialize the parameter provider configuration dialog + $('#parameter-provider-configuration').data('mode', config.edit).modal({ + scrollableContentStyle: 'scrollable', + headerText: 'Configure Parameter Provider', + handler: { + close: function () { + // cancel any active edits + $('#parameter-provider-properties').propertytable('cancelEdit'); + + // clear the tables + $('#parameter-provider-properties').propertytable('clear'); + + // clear the comments + nfCommon.clearField('read-only-parameter-provider-comments'); + + // removed the cached parameter provider details + $('#parameter-provider-configuration').removeData('parameterProviderDetails'); + + // clean up an shown verification errors + $('#parameter-provider-properties-verification-results').hide(); + $('#parameter-provider-properties-verification-results-listing').css('border-width', '0').empty(); + $('#parameter-provider-properties').css('bottom', '0'); + + // clean up an shown verification errors + $('#parameter-provider-properties-verification-results').hide(); + $('#parameter-provider-properties-verification-results-listing').css('border-width', '0').empty(); + $('#parameter-provider-properties').css('bottom', '0'); + + // clear most recently submitted referenced attributes + referencedAttributes = null; + }, + open: function () { + nfCommon.toggleScrollable($('#' + this.find('.tab-container').attr('id') + '-content').get(0)); + } + } + }); + + // if the status bar is supported, initialize it. + if (fetchParameterProviderOptions) { + $('#fetch-parameters-status-bar').statusbar('provider'); + } + + // initialize the property table + $('#parameter-provider-properties').propertytable({ + readOnly: false, + supportsGoTo: true, + dialogContainer: '#new-parameter-provider-property-container', + descriptorDeferred: getParameterProviderPropertyDescriptor, + controllerServiceCreatedDeferred: function (response) { + return nfControllerServices.loadControllerServices(controllerServicesUri, $('#controller-services-table')); + }, + goToServiceDeferred: goToServiceFromProperty + }); + + // initialize the fetch parameters dialog + $('#fetch-parameters-dialog').modal({ + headerText: 'Fetch Parameters', + scrollableContentStyle: 'scrollable', + handler: { + close: function () { + // reset visibility + $('#fetch-parameters-update-status-container').hide(); + $('#apply-groups-container').hide(); + + // clear the dialog + $('#fetch-parameters-id').text(''); + $('#fetch-parameters-name').text(''); + $('#fetched-parameters-listing').empty(); + $('#fetch-parameters-update-steps').empty(); + $('#parameter-contexts-to-create-container').empty(); + + // clean up tooltips + nfCommon.cleanUpTooltips($('#parameter-groups-table'), 'div.fa-star'); + + // reset progress + $('div.parameter-contexts-to-update').removeClass('ajax-loading ajax-complete ajax-error'); + + //stop any synchronization + if (fetchParameterProviderOptions) { + $('#fetch-parameters-status-bar').statusbar('disconnect'); + } + + // reset dialog + resetFetchParametersDialog(); + } + } + }); + + initParameterGroupsTable(); + initSelectableParametersTable(); + + $(window).on('resize', function (e) { + if ($('#affected-referencing-components-container').is(':visible')) { + updateReferencingComponentsBorder($('#affected-referencing-components-container')); + } + + if ($('#fetch-parameter-referencing-components-container').is(':visible')) { + updateReferencingComponentsBorder($('#fetch-parameter-referencing-components-container')); + } + }); + }, + + /** + * Shows the configuration dialog for the specified parameter provider. + * + * @argument {parameterProvider} parameterProviderEntity the parameter provider + */ + showConfiguration: function (parameterProviderEntity) { + var parameterProviderDialog = $('#parameter-provider-configuration'); + + parameterProviderDialog.find('.dialog-header .dialog-header-text').text('Configure Parameter Provider'); + if (parameterProviderDialog.data('mode') === config.readOnly) { + // update the visibility + $('#parameter-provider-configuration .parameter-provider-read-only').hide(); + $('#parameter-provider-configuration .parameter-provider-editable').show(); + + // initialize the property table + $('#parameter-provider-properties').propertytable('destroy').propertytable({ + readOnly: false, + supportsGoTo: true, + dialogContainer: '#new-parameter-provider-property-container', + descriptorDeferred: getParameterProviderPropertyDescriptor, + controllerServiceCreatedDeferred: function (response) { + return nfControllerServices.loadControllerServices(controllerServicesUri, $('#controller-services-table')); + }, + goToServiceDeferred: goToServiceFromProperty + }); + + // update the mode + parameterProviderDialog.data('mode', config.edit); + } + + // reload the provider in case the property descriptors have changed + var reloadProvider = $.ajax({ + type: 'GET', + url: parameterProviderEntity.uri, + dataType: 'json' + }); + + // get the parameter provider history + var loadHistory = $.ajax({ + type: 'GET', + url: '../nifi-api/flow/history/components/' + encodeURIComponent(parameterProviderEntity.id), + dataType: 'json' + }); + + // once everything is loaded, show the dialog + $.when(reloadProvider, loadHistory).done(function (providerResponse, historyResponse) { + // get the updated parameter provider + parameterProviderEntity = providerResponse[0]; + currentParameterProviderEntity = parameterProviderEntity; + var parameterProvider = parameterProviderEntity.component; + + // get the parameter provider history + var parameterProviderHistory = historyResponse[0].componentHistory; + + // record the parameter provider details + $('#parameter-provider-configuration').data('parameterProviderDetails', parameterProviderEntity); + + // populate the parameter provider settings + nfCommon.populateField('parameter-provider-id', parameterProvider['id']); + + nfCommon.populateField('parameter-provider-type', nfCommon.formatType(parameterProvider)); + $('#parameter-provider-configuration').modal('setSubtitle', nfCommon.formatType(parameterProvider)); + + nfCommon.populateField('parameter-provider-bundle', nfCommon.formatBundle(parameterProvider['bundle'])); + $('#parameter-provider-name').val(parameterProvider['name']); + $('#parameter-provider-comments').val(parameterProvider['comments']); + + // load referencing components for the parameter provider + loadParameterProviderReferencingComponents($('#parameter-provider-referencing-components'), parameterProvider); + + var buttons = [{ + buttonText: 'Apply', + color: { + base: '#728E9B', + hover: '#004849', + text: '#ffffff' + }, + handler: { + click: function () { + // close all fields currently being edited + $('#parameter-provider-properties').propertytable('saveRow'); + + // save the parameter provider + saveParameterProvider(parameterProviderEntity).done(function (response) { + // reload the parameter provider + nfControllerService.reloadReferencedServices(getControllerServicesTable(), response.component); + + // close the details panel + closeModal('#parameter-provider-configuration'); + }); + } + } + }, + { + buttonText: 'Cancel', + color: { + base: '#E3E8EB', + hover: '#C7D2D7', + text: '#004849' + }, + handler: { + click: function () { + closeModal('#parameter-provider-configuration'); + } + } + }]; + + // determine if we should show the advanced button + if (nfCommon.isDefinedAndNotNull(parameterProvider.customUiUrl) && parameterProvider.customUiUrl !== '') { + buttons.push({ + buttonText: 'Advanced', + clazz: 'fa fa-cog button-icon', + color: { + base: '#E3E8EB', + hover: '#C7D2D7', + text: '#004849' + }, + handler: { + click: function () { + var openCustomUi = function () { + // reset state and close the dialog manually to avoid hiding the faded background + closeModal('#parameter-provider-configuration'); + + // close the settings dialog since the custom ui is also opened in the shell + $('#shell-close-button').click(); + + // show the custom ui + nfCustomUi.showCustomUi(parameterProviderEntity, parameterProvider.customUiUrl, true).done(function () { + // once the custom ui is closed, reload the parameter provider + nfParameterProvider.reload(parameterProviderEntity.id).done(function (response) { + nfControllerService.reloadReferencedServices(getControllerServicesTable(), response.parameterProvider); + }); + + // show the settings + nfSettings.showSettings(); + }); + }; + + // close all fields currently being edited + $('#parameter-provider-properties').propertytable('saveRow'); + + // determine if changes have been made + if (isSaveRequired()) { + // see if those changes should be saved + nfDialog.showYesNoDialog({ + headerText: 'Save', + dialogContent: 'Save changes before opening the advanced configuration?', + noHandler: openCustomUi, + yesHandler: function () { + saveParameterProvider(parameterProviderEntity).done(function () { + // open the custom ui + openCustomUi(); + }); + } + }); + } else { + // if there were no changes, simply open the custom ui + openCustomUi(); + } + } + } + }); + } + + // set the button model + $('#parameter-provider-configuration').modal('setButtonModel', buttons); + + // load the property table + $('#parameter-provider-properties') + .propertytable('setGroupId', null) + .propertytable('loadProperties', parameterProvider.properties, parameterProvider.descriptors, parameterProviderHistory.propertyHistory) + .propertytable('setPropertyVerificationCallback', function (proposedProperties) { + nfVerify.verify(parameterProvider['id'], parameterProviderEntity['uri'], proposedProperties, referencedAttributes, handleVerificationResults, $('#parameter-provider-properties-verification-results-listing')); + }); + + // show the details + $('#parameter-provider-configuration').modal('show'); + + $('#parameter-provider-properties').propertytable('resetTableSize'); + }).fail(nfErrorHandler.handleAjaxError); + }, + + /** + * Shows the parameter provider details in a read only dialog. + * + * @param {object} parameterProviderEntity parameter provider id + */ + showDetails: function (parameterProviderEntity) { + var parameterProviderDialog = $('#parameter-provider-configuration'); + + parameterProviderDialog.find('.dialog-header .dialog-header-text').text('Parameter Provider Details'); + if (parameterProviderDialog.data('mode') === config.edit) { + // update the visibility + $('#parameter-provider-configuration .parameter-provider-read-only').show(); + $('#parameter-provider-configuration .parameter-provider-editable').hide(); + + // initialize the property table + $('#parameter-provider-properties').propertytable('destroy').propertytable({ + supportsGoTo: true, + readOnly: true + }); + + // update the mode + parameterProviderDialog.data('mode', config.readOnly); + } + + // reload the provider in case the property descriptors have changed + var reloadProvider = $.ajax({ + type: 'GET', + url: parameterProviderEntity.uri, + dataType: 'json' + }); + + // get the parameter provider history + var loadHistory = $.ajax({ + type: 'GET', + url: '../nifi-api/flow/history/components/' + encodeURIComponent(parameterProviderEntity.id), + dataType: 'json' + }); + + // once everything is loaded, show the dialog + $.when(reloadProvider, loadHistory).done(function (providerResponse, historyResponse) { + // get the updated parameter provider + parameterProviderEntity = providerResponse[0]; + var parameterProvider = parameterProviderEntity.component; + + // get the parameter provider history + var parameterProviderHistory = historyResponse[0].componentHistory; + + // populate the parameter provider settings + nfCommon.populateField('parameter-provider-id', parameterProvider['id']); + nfCommon.populateField('parameter-provider-type', nfCommon.substringAfterLast(parameterProvider['type'], '.')); + nfCommon.populateField('parameter-provider-bundle', nfCommon.formatBundle(parameterProvider['bundle'])); + nfCommon.populateField('read-only-parameter-provider-name', parameterProvider['name']); + nfCommon.populateField('read-only-parameter-provider-comments', parameterProvider['comments']); + + // load referencing components for the parameter provider + loadParameterProviderReferencingComponents($('#parameter-provider-referencing-components'), parameterProvider); + + var buttons = [{ + buttonText: 'Ok', + color: { + base: '#728E9B', + hover: '#004849', + text: '#ffffff' + }, + handler: { + click: function () { + // hide the dialog + closeModal('#parameter-provider-configuration'); + } + } + }]; + + // determine if we should show the advanced button + if (nfCommon.isDefinedAndNotNull(nfCustomUi) && nfCommon.isDefinedAndNotNull(parameterProvider.customUiUrl) && parameterProvider.customUiUrl !== '') { + buttons.push({ + buttonText: 'Advanced', + clazz: 'fa fa-cog button-icon', + color: { + base: '#E3E8EB', + hover: '#C7D2D7', + text: '#004849' + }, + handler: { + click: function () { + // reset state and close the dialog manually to avoid hiding the faded background + closeModal('#parameter-provider-configuration'); + + // close the settings dialog since the custom ui is also opened in the shell + $('#shell-close-button').click(); + + // show the custom ui + nfCustomUi.showCustomUi(parameterProviderEntity, parameterProvider.customUiUrl, false).done(function () { + nfSettings.showSettings(); + }); + } + } + }); + } + + // show the dialog + parameterProviderDialog.modal('setButtonModel', buttons).modal('show'); + + // load the property table + $('#parameter-provider-properties') + .propertytable('setGroupId', null) + .propertytable('loadProperties', parameterProvider.properties, parameterProvider.descriptors, parameterProviderHistory.propertyHistory); + + // show the details + parameterProviderDialog.modal('show'); + + $('#parameter-provider-properties').propertytable('resetTableSize'); + }); + }, + + /** + * Show the fetch parameters dialog. + * + * @param {object} parameterProviderEntity parameter provider id + */ + showFetchDialog: function (parameterProviderEntity) { + showFetchParametersDialog(parameterProviderEntity, fetchParameterProviderOptions); + }, + + /** + * Reloads the specified parameter provider. + * + * @param {string} id + */ + reload: function (id) { + var parameterProviderGrid = $('#parameter-providers-table').data('gridInstance'); + var parameterProviderData = parameterProviderGrid.getData(); + var parameterProviderEntity = parameterProviderData.getItemById(id); + + return $.ajax({ + type: 'GET', + url: parameterProviderEntity.uri, + dataType: 'json' + }).done(function (response) { + renderParameterProvider(response); + }).fail(nfErrorHandler.handleAjaxError); + }, + + /** + * Prompts the user before attempting to delete the specified parameter provider. + * + * @param {object} parameterProviderEntity parameter provider id + */ + promptToDeleteParameterProvider: function (parameterProviderEntity) { + // prompt for deletion + nfDialog.showYesNoDialog({ + headerText: 'Delete Parameter Provider', + dialogContent: 'Delete parameter provider \'' + nfCommon.escapeHtml(parameterProviderEntity.component.name) + '\'?', + yesHandler: function () { + nfParameterProvider.remove(parameterProviderEntity); + } + }); + }, + + /** + * Deletes the specified parameter provider. + * + * @param {object} parameterProviderEntity parameter provider id + */ + remove: function (parameterProviderEntity) { + var revision = nfClient.getRevision(parameterProviderEntity); + $.ajax({ + type: 'DELETE', + url: parameterProviderEntity.uri + '?' + $.param({ + 'version': revision.version, + 'clientId': revision.clientId, + 'disconnectedNodeAcknowledged': nfStorage.isDisconnectionAcknowledged() + }), + dataType: 'json' + }).done(function (response) { + // remove the provider + var parameterProviderGrid = $('#parameter-providers-table').data('gridInstance'); + var parameterProviderData = parameterProviderGrid.getData(); + parameterProviderData.deleteItem(parameterProviderEntity.id); + }).fail(nfErrorHandler.handleAjaxError); + }, + + /** + * Shows the specified parameter provider. + */ + showParameterProvider: function (parameterProviderId) { + // show the settings dialog + nfSettings.showSettings().done(function () { + var parameterProviderGrid = $('#parameter-providers-table').data('gridInstance'); + var parameterProviderData = parameterProviderGrid.getData(); + + // select the desired provider + var row = parameterProviderData.getRowById(parameterProviderId); + parameterProviderGrid.setSelectedRows([row]); + parameterProviderGrid.scrollRowIntoView(row); + + $('#settings-tabs').find('li:eq(4)').click(); + + // adjust the table size + nfSettings.resetTableSize(); + }); + } + }; + + return nfParameterProvider; +})); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-policy-management.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-policy-management.js index a5874d2c07..01e699c311 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-policy-management.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-policy-management.js @@ -1556,6 +1556,60 @@ return loadPolicy().always(showPolicy); }, + /** + * Shows the paramter provider policy. + * + * @param d + */ + showParameterProviderPolicy: function (d) { + initializingComponentPolicy = true; + + // reset the policy message + resetPolicyMessage(); + + // update the policy controls visibility + $('#component-policy-controls').show(); + $('#global-policy-controls').hide(); + + // update the visibility + if (d.permissions.canRead === true) { + $('#policy-selected-parameter-provider-container div.policy-selected-component-name').text(d.component.name); + } else { + $('#policy-selected-parameter-provider-container div.policy-selected-component-name').text(d.id); + } + $('#policy-selected-parameter-provider-container').show(); + + // populate the initial resource + $('#selected-policy-component-id').text(d.id); + $('#selected-policy-component-type').text('parameter-providers'); + $('#component-policy-target') + .combo('setOptionEnabled', { + value: 'operate-component' + }, false) + .combo('setOptionEnabled', { + value: 'write-receive-data' + }, false) + .combo('setOptionEnabled', { + value: 'write-send-data' + }, false) + .combo('setOptionEnabled', { + value: 'read-data' + }, false) + .combo('setOptionEnabled', { + value: 'read-provenance' + }, false) + .combo('setOptionEnabled', { + value: 'write-data' + }, false) + .combo('setSelectedOption', { + value: 'read-component' + }); + + initializingComponentPolicy = false; + + return loadPolicy().always(showPolicy); + }, + /** * Shows the template policy. * diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-configuration.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-configuration.js index b802c3b4b0..027f4ff27d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-configuration.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-configuration.js @@ -659,7 +659,7 @@ //if the status bar is supported, initialize it. if(config.supportsStatusBar){ - $('#processor-configuration-status-bar').statusbar(); + $('#processor-configuration-status-bar').statusbar('processor'); } // initialize the bulletin combo @@ -784,6 +784,7 @@ $.when.apply(window, requests).done(function (processorResult, historyResult) { // get the updated processor' var processorResponse = processorResult[0]; + var bulletins = processorResponse.bulletins; processor = processorResponse.component; // get the processor history @@ -1047,10 +1048,20 @@ //Synchronize the current component canvas attributes in the status bar if(config.supportsStatusBar){ + var formattedBulletins = nfCommon.getFormattedBulletins(bulletins); + var unorderedBulletins = nfCommon.formatUnorderedList(formattedBulletins); + //initialize the canvas synchronization - $("#processor-configuration-status-bar").statusbar('observe',processor.id, function(){ - $('#processor-configuration').modal('refreshButtons'); - }); + $("#processor-configuration-status-bar").statusbar( + 'observe', + { + processor: processor.id, + bulletins: unorderedBulletins + }, + function () { + $('#processor-configuration').modal('refreshButtons'); + } + ); //if there are active threads, add the terminate button to the status bar if(nfCommon.isDefinedAndNotNull(config.nfActions) && diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js index a602335a57..0c5ef6acbc 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js @@ -34,9 +34,10 @@ '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)); + 'nf.PolicyManagement', + 'nf.ParameterProvider'], + function ($, Slick, d3, nfClient, nfDialog, nfStorage, nfCommon, nfCanvasUtils, nfControllerServices, nfErrorHandler, nfFilteredDialogCommon, nfReportingTask, nfShell, nfComponentState, nfComponentVersion, nfPolicyManagement, nfParameterProvider) { + return (nf.Settings = factory($, Slick, d3, nfClient, nfDialog, nfStorage, nfCommon, nfCanvasUtils, nfControllerServices, nfErrorHandler, nfFilteredDialogCommon, nfReportingTask, nfShell, nfComponentState, nfComponentVersion, nfPolicyManagement, nfParameterProvider)); }); } else if (typeof exports === 'object' && typeof module === 'object') { module.exports = (nf.Settings = @@ -55,7 +56,8 @@ require('nf.Shell'), require('nf.ComponentState'), require('nf.ComponentVersion'), - require('nf.PolicyManagement'))); + require('nf.PolicyManagement'), + require('nf.ParameterProvider'))); } else { nf.Settings = factory(root.$, root.Slick, @@ -72,9 +74,10 @@ root.nf.Shell, root.nf.ComponentState, root.nf.ComponentVersion, - root.nf.PolicyManagement); + root.nf.PolicyManagement, + root.nf.ParameterProvider); } -}(this, function ($, Slick, d3, nfClient, nfDialog, nfStorage, nfCommon, nfCanvasUtils, nfControllerServices, nfErrorHandler, nfFilteredDialogCommon, nfReportingTask, nfShell, nfComponentState, nfComponentVersion, nfPolicyManagement) { +}(this, function ($, Slick, d3, nfClient, nfDialog, nfStorage, nfCommon, nfCanvasUtils, nfControllerServices, nfErrorHandler, nfFilteredDialogCommon, nfReportingTask, nfShell, nfComponentState, nfComponentVersion, nfPolicyManagement, nfParameterProvider) { 'use strict'; @@ -85,7 +88,10 @@ 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' + registries: '../nifi-api/controller/registry-clients', + createParameterProvider: '../nifi-api/controller/parameter-providers', + parameterProviderTypes: '../nifi-api/flow/parameter-provider-types', + parameterProviders: '../nifi-api/flow/parameter-providers' } }; @@ -345,6 +351,15 @@ return $('#reporting-task-type-filter').val(); }; + /** + * 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 getParameterProviderTypeFilterText = function () { + return $('#parameter-provider-type-filter').val(); + }; + /** * Filters the reporting task type table. */ @@ -372,6 +387,33 @@ } }; + /** + * Filters the parameter provider type table. + */ + var applyParameterProviderTypeFilter = function () { + // get the dataview + var parameterProviderTypesGrid = $('#parameter-provider-types-table').data('gridInstance'); + + // ensure the grid has been initialized + if (nfCommon.isDefinedAndNotNull(parameterProviderTypesGrid)) { + var parameterProviderTypesData = parameterProviderTypesGrid.getData(); + + // update the search criteria + parameterProviderTypesData.setFilterArgs({ + searchString: getParameterProviderTypeFilterText() + }); + parameterProviderTypesData.refresh(); + + // update the buttons to possibly trigger the disabled state + $('#new-parameter-provider-dialog').modal('refreshButtons'); + + // update the selection if possible + if (parameterProviderTypesData.getLength() > 0) { + nfFilteredDialogCommon.choseFirstRow(parameterProviderTypesGrid); + } + } + }; + /** * Hides the selected reporting task. */ @@ -384,6 +426,18 @@ $('#reporting-task-description-container').hide(); }; + /** + * Hides the selected parameter provider. + */ + var clearSelectedParameterProvider = function () { + $('#parameter-provider-type-description').attr('title', '').text(''); + $('#parameter-provider-type-name').attr('title', '').text(''); + $('#parameter-provider-type-bundle').attr('title', '').text(''); + $('#selected-parameter-provider-name').text(''); + $('#selected-parameter-provider-type').text('').removeData('bundle'); + $('#parameter-provider-description-container').hide(); + }; + /** * Clears the selected reporting task type. */ @@ -396,6 +450,18 @@ reportingTaskTypesGrid.resetActiveCell(); }; + /** + * Clears the selected parameter provider type. + */ + var clearParameterProviderSelection = function () { + // clear the selected row + clearSelectedParameterProvider(); + + // clear the active cell then it can be reselected when its included + var parameterProviderTypesGrid = $('#parameter-provider-types-table').data('gridInstance'); + parameterProviderTypesGrid.resetActiveCell(); + }; + /** * Performs the filtering. * @@ -437,6 +503,47 @@ return matches; }; + /** + * 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 filterParameterProviderTypes = 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 = $('#parameter-provider-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 = $('#parameter-provider-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-parameter-provider-type').text() === item['type']) { + clearParameterProviderSelection(); + } + + return matches; + }; + /** * Adds the currently selected reporting task. */ @@ -455,6 +562,24 @@ } }; + /** + * Adds the currently selected parameter provider. + */ + var addSelectedParameterProvider = function () { + var selectedParameterProviderType = $('#selected-parameter-provider-type').text(); + var selectedParameterProviderBundle = $('#selected-selected-parameter-type').data('bundle'); + + // ensure something was selected + if (selectedParameterProviderType === '') { + nfDialog.showOkDialog({ + headerText: 'Settings', + dialogContent: 'The type of parameter provider to create must be selected.' + }); + } else { + addParameterProvider(selectedParameterProviderType, selectedParameterProviderBundle); + } + }; + /** * Adds a new reporting task of the specified type. * @@ -558,6 +683,59 @@ return addRegistry; }; + /** + * Adds a new parameter provider of the specified type. + * + * @param {string} parameterProviderType + * @param {object} parameterProviderBundle + */ + var addParameterProvider = function (parameterProviderType, parameterProviderBundle) { + // build the parameter provider entity + var parameterProviderEntity = { + 'revision': nfClient.getRevision({ + 'revision': { + 'version': 0 + } + }), + 'disconnectedNodeAcknowledged': nfStorage.isDisconnectionAcknowledged(), + 'component': { + 'type': parameterProviderType, + 'bundle': parameterProviderBundle + } + }; + + // add the new parameter provider + var addProvider = $.ajax({ + type: 'POST', + url: config.urls.createParameterProvider, + data: JSON.stringify(parameterProviderEntity), + dataType: 'json', + contentType: 'application/json' + }).done(function (parameterProviderEntity) { + // add the item + var parameterProviderGrid = $('#parameter-providers-table').data('gridInstance'); + var parameterProviderData = parameterProviderGrid.getData(); + parameterProviderData.addItem($.extend({ + type: 'ParameterProvider', + bulletins: [] + }, parameterProviderEntity)); + + // resort + parameterProviderData.reSort(); + parameterProviderGrid.invalidate(); + + // select the new parameter provider + var row = parameterProviderData.getRowById(parameterProviderEntity.id); + nfFilteredDialogCommon.choseRow(parameterProviderGrid, row); + parameterProviderGrid.scrollRowIntoView(row); + }).fail(nfErrorHandler.handleAjaxError); + + // hide the dialog + $('#new-parameter-provider-dialog').modal('hide'); + + return addProvider; + }; + /** * Updates the registry with the specified id. * @@ -1001,6 +1179,395 @@ }); }; + /** + * Initializes the new parameter provider dialog. + */ + var initNewParameterProviderDialog = function () { + // initialize the parameter provider type table + var parameterProviderColumns = [ + { + 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 parameterProviderTypesData = new Slick.Data.DataView({ + inlineFilters: false + }); + parameterProviderTypesData.setItems([]); + parameterProviderTypesData.setFilterArgs({ + searchString: getParameterProviderTypeFilterText() + }); + parameterProviderTypesData.setFilter(filterParameterProviderTypes); + + // initialize the sort + nfCommon.sortType({ + columnId: 'type', + sortAsc: true + }, parameterProviderTypesData); + + // initialize the grid + var parameterProviderTypesGrid = new Slick.Grid('#parameter-provider-types-table', parameterProviderTypesData, parameterProviderColumns, gridOptions); + parameterProviderTypesGrid.setSelectionModel(new Slick.RowSelectionModel()); + parameterProviderTypesGrid.registerPlugin(new Slick.AutoTooltips()); + parameterProviderTypesGrid.setSortColumn('type', true); + parameterProviderTypesGrid.onSort.subscribe(function (e, args) { + nfCommon.sortType({ + columnId: args.sortCol.field, + sortAsc: args.sortAsc + }, parameterProviderTypesData); + }); + parameterProviderTypesGrid.onSelectedRowsChanged.subscribe(function (e, args) { + if ($.isArray(args.rows) && args.rows.length === 1) { + var parameterProviderTypeIndex = args.rows[0]; + var parameterProviderType = parameterProviderTypesGrid.getDataItem(parameterProviderTypeIndex); + + // set the parameter provider type description + if (nfCommon.isDefinedAndNotNull(parameterProviderType)) { + // show the selected parameter provider + $('#parameter-provider-description-container').show(); + + if (nfCommon.isBlank(parameterProviderType.description)) { + $('#parameter-provider-type-description') + .attr('title', '') + .html('No description specified'); + } else { + $('#parameter-provider-type-description') + .width($('#parameter-provider-description-container').innerWidth() - 1) + .html(parameterProviderType.description) + .ellipsis(); + } + + var bundle = nfCommon.formatBundle(parameterProviderType.bundle); + var type = nfCommon.formatType(parameterProviderType); + + // populate the dom + $('#parameter-provider-type-name').text(type).attr('title', type); + $('#parameter-provider-type-bundle').text(bundle).attr('title', bundle); + $('#selected-parameter-provider-name').text(parameterProviderType.label); + $('#selected-parameter-provider-type').text(parameterProviderType.type).data('bundle', parameterProviderType.bundle); + + // refresh the buttons based on the current selection + $('#new-parameter-provider-dialog').modal('refreshButtons'); + } + } + }); + parameterProviderTypesGrid.onDblClick.subscribe(function (e, args) { + var parameterProviderType = parameterProviderTypesGrid.getDataItem(args.row); + + if (isSelectable(parameterProviderType)) { + addParameterProvider(parameterProviderType.type, parameterProviderType.bundle); + } + }); + parameterProviderTypesGrid.onViewportChanged.subscribe(function (e, args) { + nfCommon.cleanUpTooltips($('#parameter-provider-types-table'), 'div.view-usage-restriction'); + }); + + // wire up the dataview to the grid + parameterProviderTypesData.onRowCountChanged.subscribe(function (e, args) { + parameterProviderTypesGrid.updateRowCount(); + parameterProviderTypesGrid.render(); + + // update the total number of displayed processors + $('#displayed-parameter-provider-types').text(args.current); + }); + parameterProviderTypesData.onRowsChanged.subscribe(function (e, args) { + parameterProviderTypesGrid.invalidateRows(args.rows); + parameterProviderTypesGrid.render(); + }); + parameterProviderTypesData.syncGridSelection(parameterProviderTypesGrid, true); + + // hold onto an instance of the grid + $('#parameter-provider-types-table').data('gridInstance', parameterProviderTypesGrid).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 = parameterProviderTypesData.getItemById(rowId); + + // show the tooltip + if (item.restricted === true) { + var restrictionTip = $('
                      '); + + if (nfCommon.isBlank(item.usageRestriction)) { + restrictionTip.append($('

                      ').text('Requires the following permissions:')); + } else { + restrictionTip.append($('

                      ').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 parameter providers + $.ajax({ + type: 'GET', + url: config.urls.parameterProviderTypes, + 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 + parameterProviderTypesData.beginUpdate(); + + // go through each parameter provider type + $.each(response.parameterProviderTypes, 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 + parameterProviderTypesData.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 + parameterProviderTypesData.endUpdate(); + + // resort + parameterProviderTypesData.reSort(); + parameterProviderTypesGrid.invalidate(); + + // set the component restrictions and the corresponding required permissions + nfCanvasUtils.addComponentRestrictions(restrictedUsage, requiredPermissions); + + // set the total number of processors + $('#total-parameter-provider-types, #displayed-parameter-provider-types').text(response.parameterProviderTypes.length); + + // create the tag cloud + $('#parameter-provider-tag-cloud').tagcloud({ + tags: tags, + select: applyParameterProviderTypeFilter, + remove: applyParameterProviderTypeFilter + }); + + // 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 + $('#parameter-provider-bundle-group-combo').combo({ + options: options, + select: applyParameterProviderTypeFilter + }); + }).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 + $('#parameter-provider-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 = parameterProviderTypesGrid.getSelectedRows(); + + if (selected.length > 0) { + // grid configured with multi-select = false + var item = parameterProviderTypesGrid.getDataItem(selected[0]); + if (isSelectable(item)) { + addSelectedParameterProvider(); + } + } + } else { + applyParameterProviderTypeFilter(); + } + }); + + // setup row navigation + nfFilteredDialogCommon.addKeydownListener('#parameter-provider-type-filter', parameterProviderTypesGrid, parameterProviderTypesGrid.getData()); + + // initialize the parameter provider dialog + $('#new-parameter-provider-dialog').modal({ + scrollableContentStyle: 'scrollable', + headerText: 'Add Parameter Provider', + buttons: [{ + buttonText: 'Add', + color: { + base: '#728E9B', + hover: '#004849', + text: '#ffffff' + }, + disabled: function () { + var selected = parameterProviderTypesGrid.getSelectedRows(); + + if (selected.length > 0) { + // grid configured with multi-select = false + var item = parameterProviderTypesGrid.getDataItem(selected[0]); + return isSelectable(item) === false; + } else { + return parameterProviderTypesGrid.getData().getLength() === 0; + } + }, + handler: { + click: function () { + addSelectedParameterProvider(); + } + } + }, + { + buttonText: 'Cancel', + color: { + base: '#E3E8EB', + hover: '#C7D2D7', + text: '#004849' + }, + handler: { + click: function () { + $(this).modal('hide'); + } + } + }], + handler: { + close: function () { + // clear the selected row + clearSelectedParameterProvider(); + + // clear any filter strings + $('#parameter-provider-type-filter').val(''); + + // clear the tagcloud + $('#parameter-provider-tag-cloud').tagcloud('clearSelectedTags'); + + // reset the group combo + $('#parameter-provider-bundle-group-combo').combo('setSelectedOption', { + value: '' + }); + + // reset the filter + applyParameterProviderTypeFilter(); + + // unselect any current selection + var parameterProviderTypesGrid = $('#parameter-provider-types-table').data('gridInstance'); + parameterProviderTypesGrid.setSelectedRows([]); + parameterProviderTypesGrid.resetActiveCell(); + }, + resize: function () { + $('#parameter-provider-type-description') + .width($('#parameter-provider-description-container').innerWidth() - 1) + .text($('#parameter-provider-type-description').attr('title')) + .ellipsis(); + } + } + }); + }; + /** * Initializes the reporting tasks tab. */ @@ -1458,6 +2025,263 @@ $('#registries-table').data('gridInstance', registriesGrid); }; + /** + * Initializes the parameter providers tab. + */ + var initParameterProvidersTable = function () { + // initialize the new parameter provider dialog + initNewParameterProviderDialog(); + + var moreParameterProvidersDetails = function (row, cell, value, columnDef, dataContext) { + if (!dataContext.permissions.canRead) { + return ''; + } + + var markup = '
                      '; + + // always include a button to view the usage + markup += '
                      '; + + var hasErrors = !nfCommon.isEmpty(dataContext.component.validationErrors); + var hasBulletins = !nfCommon.isEmpty(dataContext.bulletins); + + if (hasErrors) { + markup += '
                      '; + } + + if (hasBulletins) { + markup += '
                      '; + } + + if (hasErrors || hasBulletins) { + markup += ''; + } + + return markup; + }; + + var parameterProvidersActionFormatter = function (row, cell, value, columnDef, dataContext) { + var markup = ''; + + var canWrite = dataContext.permissions.canWrite; + var canRead = dataContext.permissions.canRead; + + var hasErrors = canRead ? !nfCommon.isEmpty(dataContext.component.validationErrors) : null; + + var hasReadParameterContextsPermissions = true; + + if (canRead && dataContext.component.referencingParameterContexts) { + (dataContext.component.referencingParameterContexts).every(function (refParamContext) { + return hasReadParameterContextsPermissions = refParamContext.permissions.canRead; + }); + } + + if (canRead && canWrite) { + markup += '
                      '; + + if (hasReadParameterContextsPermissions && !hasErrors) { + markup += '
                      '; + } + } + + if (canRead && canWrite && nfCommon.canModifyController()) { + markup += '
                      '; + } + + // allow policy configuration conditionally + if (nfCanvasUtils.isManagedAuthorizer() && nfCommon.canAccessTenants()) { + markup += '
                      '; + } + + return markup; + }; + + // define the column model for the parameter providers table + var parameterProvidersColumnModel = [ + { + id: 'moreDetails', + name: ' ', + resizable: false, + formatter: moreParameterProvidersDetails, + 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 + } + ]; + + // action column should always be last + parameterProvidersColumnModel.push({ + id: 'actions', + name: ' ', + resizable: false, + formatter: parameterProvidersActionFormatter, + sortable: false, + width: 115, + maxWidth: 115 + }); + + // initialize the dataview + var parameterProvidersData = new Slick.Data.DataView({ + inlineFilters: false + }); + parameterProvidersData.setItems([]); + + // initialize the sort + sort({ + columnId: 'name', + sortAsc: true + }, parameterProvidersData); + + // initialize the grid + var parameterProvidersGrid = new Slick.Grid('#parameter-providers-table', parameterProvidersData, parameterProvidersColumnModel, gridOptions); + parameterProvidersGrid.setSelectionModel(new Slick.RowSelectionModel()); + parameterProvidersGrid.registerPlugin(new Slick.AutoTooltips()); + parameterProvidersGrid.setSortColumn('name', true); + parameterProvidersGrid.onSort.subscribe(function (e, args) { + sort({ + columnId: args.sortCol.id, + sortAsc: args.sortAsc + }, parameterProvidersData); + }); + + // configure a click listener + parameterProvidersGrid.onClick.subscribe(function (e, args) { + var target = $(e.target); + + // get the service at this row + var parameterProviderEntity = parameterProvidersData.getItem(args.row); + + // determine the desired action + if (parameterProvidersGrid.getColumns()[args.cell].id === 'actions') { + if (target.hasClass('edit-parameter-provider')) { + nfParameterProvider.showConfiguration(parameterProviderEntity); + } else if (target.hasClass('fetch-parameter-provider')) { + nfParameterProvider.showFetchDialog(parameterProviderEntity); + } else if (target.hasClass('delete-parameter-provider')) { + nfParameterProvider.promptToDeleteParameterProvider(parameterProviderEntity); + } else if (target.hasClass('edit-access-policies')) { + // show the policies for this service + nfPolicyManagement.showParameterProviderPolicy(parameterProviderEntity); + + // close the settings dialog + $('#shell-close-button').click(); + } + } else if (parameterProvidersGrid.getColumns()[args.cell].id === 'moreDetails') { + if (target.hasClass('view-parameter-provider')) { + nfParameterProvider.showDetails(parameterProviderEntity); + } else if (target.hasClass('parameter-provider-usage')) { + // close the settings dialog + $('#shell-close-button').click(); + + // open the documentation for this parameter provider + nfShell.showPage('../nifi-docs/documentation?' + $.param({ + select: parameterProviderEntity.component.type, + group: parameterProviderEntity.component.bundle.group, + artifact: parameterProviderEntity.component.bundle.artifact, + version: parameterProviderEntity.component.bundle.version + })).done(function () { + nfSettings.showSettings(); + }); + } + } + }); + + // wire up the dataview to the grid + parameterProvidersData.onRowCountChanged.subscribe(function (e, args) { + parameterProvidersGrid.updateRowCount(); + parameterProvidersGrid.render(); + }); + parameterProvidersData.onRowsChanged.subscribe(function (e, args) { + parameterProvidersGrid.invalidateRows(args.rows); + parameterProvidersGrid.render(); + }); + parameterProvidersData.syncGridSelection(parameterProvidersGrid, true); + + // hold onto an instance of the grid + $('#parameter-providers-table').data('gridInstance', parameterProvidersGrid).on('mouseenter', 'div.slick-cell', function (e) { + var errorIcon = $(this).find('div.has-errors'); + if (errorIcon.length && !errorIcon.data('qtip')) { + var providerId = $(this).find('span.row-id').text(); + + // get the provider item + var providerEntity = parameterProvidersData.getItemById(providerId); + + // format the errors + var tooltip = nfCommon.formatUnorderedList(providerEntity.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 providerId = $(this).find('span.row-id').text(); + + // get the provider item + var parameterProviderEntity = parameterProvidersData.getItemById(providerId); + + // format the tooltip + var bulletins = nfCommon.getFormattedBulletins(parameterProviderEntity.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' + } + } + })); + } + } + }); + }; + /** * Edits the specified registry entity. * @@ -1608,8 +2432,11 @@ // load the registries var registries = loadRegistries(); + // load the parameter providers + var parameterProviders = loadParameterProviders(); + // return a deferred for all parts of the settings - return $.when(settings, controllerServicesXhr, reportingTasks).done(function (settingsResult, controllerServicesResult) { + return $.when(settings, controllerServicesXhr, reportingTasks, parameterProviders).done(function (settingsResult, controllerServicesResult) { var controllerServicesResponse = controllerServicesResult[0]; // update the current time @@ -1674,6 +2501,37 @@ }); }; + /** + * Loads the parameter providers. + */ + var loadParameterProviders = function () { + return $.ajax({ + type: 'GET', + url: config.urls.parameterProviders, + dataType: 'json' + }).done(function (response) { + var providers = []; + $.each(response.parameterProviders, function (_, provider) { + providers.push($.extend({ + type: 'ParameterProvider', + bulletins: [] + }, provider)); + }); + + var parameterProvidersElement = $('#parameter-providers-table'); + nfCommon.cleanUpTooltips(parameterProvidersElement, 'div.has-errors'); + nfCommon.cleanUpTooltips(parameterProvidersElement, 'div.has-bulletins'); + + var parameterProvidersGrid = parameterProvidersElement.data('gridInstance'); + var parameterProvidersData = parameterProvidersGrid.getData(); + + // update the parameter providers + parameterProvidersData.setItems(providers); + parameterProvidersData.reSort(); + parameterProvidersGrid.invalidate(); + }); + }; + /** * Shows the process group configuration. */ @@ -1712,7 +2570,7 @@ name: 'General', tabContentId: 'general-settings-tab-content' }, { - name: 'Reporting Task Controller Services', + name: 'Management Controller Services', tabContentId: 'controller-services-tab-content' }, { name: 'Reporting Tasks', @@ -1720,6 +2578,9 @@ }, { name: 'Registry Clients', tabContentId: 'registries-tab-content' + }, { + name: 'Parameter Providers', + tabContentId: 'parameter-providers-tab-content' }], select: function () { var tab = $(this).text(); @@ -1740,15 +2601,18 @@ // update the tooltip on the button $('#new-service-or-task').attr('title', function () { - if (tab === 'Reporting Task Controller Services') { + if (tab === 'Management Controller Services') { $('#settings-save').hide(); - return 'Create a new reporting task controller service'; + return 'Create a new controller level 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 === 'Parameter Providers') { + $('#settings-save').hide(); + return 'Add a new parameter provider'; } }); } else { @@ -1756,9 +2620,9 @@ $('div.controller-settings-table').css('top', '0'); } - if (tab === 'Reporting Task Controller Services') { + if (tab === 'Management Controller Services') { $('#controller-cs-availability').show(); - } else if (tab === 'Reporting Tasks' || tab === 'Registry Clients') { + } else if (tab === 'Reporting Tasks' || tab === 'Registry Clients' || tab === 'Parameter Providers') { $('#controller-cs-availability').hide(); } @@ -1776,7 +2640,7 @@ // create a new controller service or reporting task $('#new-service-or-task').on('click', function () { var selectedTab = $('#settings-tabs li.selected-tab').text(); - if (selectedTab === 'Reporting Task Controller Services') { + if (selectedTab === 'Management Controller Services') { var controllerServicesUri = config.urls.api + '/controller/controller-services'; nfControllerServices.promptNewControllerService(controllerServicesUri, getControllerServicesTable()); } else if (selectedTab === 'Reporting Tasks') { @@ -1826,6 +2690,24 @@ // set the initial focus $('#registry-name').focus(); + } else if (selectedTab === 'Parameter Providers') { + $('#new-parameter-provider-dialog').modal('show'); + + var parameterProviderTypesGrid = $('#parameter-provider-types-table').data('gridInstance'); + if (nfCommon.isDefinedAndNotNull(parameterProviderTypesGrid)) { + var parameterProviderTypesData = parameterProviderTypesGrid.getData(); + + // reset the canvas size after the dialog is shown + parameterProviderTypesGrid.resizeCanvas(); + + // select the first row if possible + if (parameterProviderTypesData.getLength() > 0) { + nfFilteredDialogCommon.choseFirstRow(parameterProviderTypesGrid); + } + } + + // set the initial focus + $('#parameter-provider-type-filter').focus(); } }); @@ -1834,6 +2716,7 @@ nfControllerServices.init(getControllerServicesTable(), nfSettings.showSettings); initReportingTasks(); initRegistriesTable(); + initParameterProvidersTable(); }, /** @@ -1846,6 +2729,10 @@ if (nfCommon.isDefinedAndNotNull(reportingTasksGrid)) { reportingTasksGrid.resizeCanvas(); } + var parameterProvidersGrid = $('#parameter-providers-table').data('gridInstance'); + if (nfCommon.isDefinedAndNotNull(parameterProvidersGrid)) { + parameterProvidersGrid.resizeCanvas(); + } }, /** diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-processor-details.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-processor-details.js index fc2bcaaab5..49a3b1a7bb 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-processor-details.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-processor-details.js @@ -183,7 +183,7 @@ //apply the status bar if indicated if(config.supportsStatusBar){ - $("#processor-details-status-bar").statusbar(); + $("#processor-details-status-bar").statusbar('processor'); } // initialize the properties @@ -372,9 +372,17 @@ //Populate the status bar if the feature is enabled if (config.supportsStatusBar && nfCommon.isDefinedAndNotNull(config.nfCanvasUtils)){ + var formattedBulletins = nfCommon.getFormattedBulletins(processorResponse.bulletins); + var unorderedBulletins = nfCommon.formatUnorderedList(formattedBulletins); //initialize the canvas synchronization - $("#processor-details-status-bar").statusbar('observe',processor.id); + $("#processor-details-status-bar").statusbar( + 'observe', + { + processor: processor.id, + bulletins: unorderedBulletins + } + ); //Fetch the component as a selection from the canvas selection = config.nfCanvasUtils.getSelectionById(processor.id);