rfellows commented on a change in pull request #3606: [WIP] Nifi 6282 URL: https://github.com/apache/nifi/pull/3606#discussion_r316399026
########## File path: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-parameter-contexts.js ########## @@ -0,0 +1,2233 @@ +/* + * 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', + 'd3', + 'nf.Client', + 'nf.Dialog', + 'nf.Storage', + 'nf.Common', + 'nf.CanvasUtils', + 'nf.ng.Bridge', + 'nf.ErrorHandler', + 'nf.FilteredDialogCommon', + 'nf.Shell', + 'nf.ComponentState', + 'nf.ComponentVersion', + 'nf.PolicyManagement', + 'nf.Processor', + 'nf.ProcessGroup', + 'nf.ProcessGroupConfiguration'], + function ($, Slick, d3, nfClient, nfDialog, nfStorage, nfCommon, nfCanvasUtils, nfNgBridge, nfErrorHandler, nfFilteredDialogCommon, nfShell, nfComponentState, nfComponentVersion, nfPolicyManagement, nfProcessor, nfProcessGroup, nfProcessGroupConfiguration) { + return (nf.ParameterContexts = factory($, Slick, d3, nfClient, nfDialog, nfStorage, nfCommon, nfCanvasUtils, nfNgBridge, nfErrorHandler, nfFilteredDialogCommon, nfShell, nfComponentState, nfComponentVersion, nfPolicyManagement, nfProcessor, nfProcessGroup, nfProcessGroupConfiguration)); + }); + } else if (typeof exports === 'object' && typeof module === 'object') { + module.exports = (nf.ParameterContexts = + factory(require('jquery'), + require('Slick'), + require('d3'), + require('nf.Client'), + require('nf.Dialog'), + require('nf.Storage'), + require('nf.Common'), + require('nf.CanvasUtils'), + require('nf.ng.Bridge'), + require('nf.ErrorHandler'), + require('nf.FilteredDialogCommon'), + require('nf.Shell'), + require('nf.ComponentState'), + require('nf.ComponentVersion'), + require('nf.PolicyManagement'), + require('nf.Processor'), + require('nf.ProcessGroup'), + require('nf.ProcessGroupConfiguration'))); + } else { + nf.ParameterContexts = factory(root.$, + root.Slick, + root.d3, + root.nf.Client, + root.nf.Dialog, + root.nf.Storage, + root.nf.Common, + root.nf.CanvasUtils, + root.nf.ng.Bridge, + root.nf.ErrorHandler, + root.nf.FilteredDialogCommon, + root.nf.Shell, + root.nf.ComponentState, + root.nf.ComponentVersion, + root.nf.PolicyManagement, + root.nf.Processor, + root.nf.ProcessGroup, + root.nf.ProcessGroupConfiguration); + } +}(this, function ($, Slick, d3, nfClient, nfDialog, nfStorage, nfCommon, nfCanvasUtils, nfNgBridge, nfErrorHandler, nfFilteredDialogCommon, nfShell, nfComponentState, nfComponentVersion, nfPolicyManagement, nfProcessor, nfProcessGroup, nfProcessGroupConfiguration) { + 'use strict'; + + var config = { + urls: { + parameterContexts: '../nifi-api/parameter-contexts' + } + }; + + var parameterContextsGridOptions = { + forceFitColumns: true, + enableTextSelectionOnCells: true, + enableCellNavigation: true, + enableColumnReorder: false, + autoEdit: false, + multiSelect: false, + rowHeight: 24 + }; + + var parametersGridOptions = { + forceFitColumns: true, + enableTextSelectionOnCells: true, + enableCellNavigation: true, + enableColumnReorder: false, + editable: false, + enableAddRow: false, + autoEdit: false, + multiSelect: false, + rowHeight: 24 + }; + + /** + * Formatter for the name column. + * + * @param {type} row + * @param {type} cell + * @param {type} value + * @param {type} columnDef + * @param {type} dataContext + * @returns {String} + */ + var nameFormatter = function (row, cell, value, columnDef, dataContext) { + if (!dataContext.permissions.canRead) { + return '<span class="blank">' + nfCommon.escapeHtml(dataContext.id) + '</span>'; + } + + return nfCommon.escapeHtml(dataContext.component.name); + }; + + /** + * Sorts the specified data using the specified sort details. + * + * @param {object} sortDetails + * @param {object} data + */ + var sort = function (sortDetails, data) { + // defines a function for sorting + var comparer = function (a, b) { + if (a.permissions.canRead && b.permissions.canRead) { + var aString = nfCommon.isDefinedAndNotNull(a.component[sortDetails.columnId]) ? a.component[sortDetails.columnId] : ''; + var bString = nfCommon.isDefinedAndNotNull(b.component[sortDetails.columnId]) ? b.component[sortDetails.columnId] : ''; + return aString === bString ? 0 : aString > bString ? 1 : -1; + } else { + if (!a.permissions.canRead && !b.permissions.canRead) { + return 0; + } + if (a.permissions.canRead) { + return 1; + } else { + return -1; + } + } + }; + + // perform the sort + data.sort(comparer, sortDetails.sortAsc); + }; + + var lastSelectedId = 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) { + if (sortDetails.columnId === 'name') { + var aString = nfCommon.isDefinedAndNotNull(a[sortDetails.columnId]) ? a[sortDetails.columnId] : ''; + var bString = nfCommon.isDefinedAndNotNull(b[sortDetails.columnId]) ? b[sortDetails.columnId] : ''; + return aString === bString ? 0 : aString > bString ? 1 : -1; + } + }; + + // perform the sort + data.sort(comparer, sortDetails.sortAsc); + }; + + /** + * Reset the dialog. + */ + var resetDialog = function () { + $('#parameter-context-name').val(''); + $('#parameter-context-description-field').val(''); + $('#parameter-table, #add-parameter').show(); + $('#parameter-context-tabs').show(); + $('#parameter-context-tabs').find('.tab')[0].click(); + $('#parameter-context-update-status').hide(); + + $('#process-group-parameter').text(''); + $('#parameter-process-group-id').text('').removeData('revision'); + $('#parameter-affected-components-context').removeClass('unset').text(''); + + var parameterGrid = $('#parameter-table').data('gridInstance'); + var parameterData = parameterGrid.getData(); + parameterData.setItems([]); + + var affectedProcessorContainer = $('#parameter-context-affected-processors'); + nfCommon.cleanUpTooltips(affectedProcessorContainer, 'div.referencing-component-state'); + nfCommon.cleanUpTooltips(affectedProcessorContainer, 'div.referencing-component-bulletins'); + affectedProcessorContainer.empty(); + + var affectedControllerServicesContainer = $('#parameter-context-affected-controller-services'); + nfCommon.cleanUpTooltips(affectedControllerServicesContainer, 'div.referencing-component-state'); + nfCommon.cleanUpTooltips(affectedControllerServicesContainer, 'div.referencing-component-bulletins'); + affectedControllerServicesContainer.empty(); + + $('#parameter-context-affected-unauthorized-components').empty(); + $('#parameter-referencing-components-container').empty(); + + // reset the last selected parameter + lastSelectedId = null; + + // reset the current parameter context + currentParameterContextEntity = null; + + // clean up any tooltips that may have been generated + nfCommon.cleanUpTooltips($('#parameter-table'), 'div.fa-question-circle'); + }; + + /** + * Marshals the parameters in the table. + */ + var marshalParameters = function () { + var parameters = []; + var table = $('#parameter-table'); + var parameterGrid = table.data('gridInstance'); + var parameterData = parameterGrid.getData(); + $.each(parameterData.getItems(), function () { + var parameter = { + 'name': this.name + }; + + // if the parameter has been deleted + if (this.hidden === true && this.previousValue !== null) { + // hidden parameters were removed by the user, clear the value + parameters.push({ + 'parameter': parameter + }); + } else if (this.isModified === true) { // the parameter is modified + // check if the value has changed + if (this.value !== this.previousValue) { + parameter['sensitive'] = this.sensitive; + + // for non-sensitive values we always include the value + if (!this.sensitive) { + parameter['value'] = this.value; + } else { + // for sensitive parameters we don't know it's value so we only include the + // value if it has changed or if the empty string set checkbox has been checked + if (!nfCommon.isBlank(this.value) || this.isEmptyStringSet === true) { + parameter['value'] = this.value; + } + } + + parameter['description'] = this.description; + } else if (this.value === this.previousValue && this.sensitive === true) { + // if the user sets the sensitive parameter's value to the mask returned by the server + parameter['value'] = this.value; + parameter['sensitive'] = this.sensitive; + parameter['description'] = this.description; + } else if (this.description !== this.previousDescription) { + parameter['value'] = this.value; + parameter['sensitive'] = this.sensitive; + parameter['description'] = this.description; + } + + parameters.push({ + 'parameter': parameter + }); + } + }); + + return parameters; + }; + + /** + * Handles outstanding changes. + * + * @returns {deferred} + */ + var handleOutstandingChanges = function () { + if (!$('#parameter-dialog').hasClass('hidden')) { + // commit the current edit + addNewParameter(); + } + + return $.Deferred(function (deferred) { + if ($('#parameter-context-update-status').is(':visible')) { + close(); + deferred.resolve(); + } else { + var parameters = marshalParameters(); + + // if there are no parameters there is nothing to save + if ($.isEmptyObject(parameters)) { + close(); + deferred.resolve(); + } else { + // see if those changes should be saved + nfDialog.showYesNoDialog({ + headerText: 'Parameters', + dialogContent: 'Save changes before leaving parameter context configuration?', + noHandler: function () { + close(); + deferred.resolve(); + }, + yesHandler: function () { + updateParameterContext(currentParameterContextEntity).done(function () { + deferred.resolve(); + }).fail(function () { + deferred.reject(); + }); + } + }); + } + } + + }).promise(); + }; + + /** + * Adds a border to the controller service 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'); + } + }; + + /** + * Cancels adding a new parameter context. + */ + var close = function () { + $('#parameter-context-dialog').modal('hide'); + }; + + /** + * Renders the specified affected component. + * + * @param {object} affectedProcessorEntity + * @param {jQuery} container + */ + var renderAffectedProcessor = function (affectedProcessorEntity, container) { + var affectedProcessorContainer = $('<li class="affected-component-container"></li>').appendTo(container); + var affectedProcessor = affectedProcessorEntity.component; + + // processor state + $('<div class="referencing-component-state"></div>').addClass(function () { + if (nfCommon.isDefinedAndNotNull(affectedProcessor.state)) { + var icon = $(this); + + var state = affectedProcessor.state.toLowerCase(); + if (state === 'stopped' && !nfCommon.isEmpty(affectedProcessor.validationErrors)) { + state = 'invalid'; + + // build the validation error listing + var list = nfCommon.formatUnorderedList(affectedProcessor.validationErrors); + + // add tooltip for the warnings + icon.qtip($.extend({}, + nfCanvasUtils.config.systemTooltipConfig, + { + content: list + })); + } + + return state; + } else { + return ''; + } + }).appendTo(affectedProcessorContainer); + + + // processor name + $('<span class="referencing-component-name link"></span>').text(affectedProcessor.name).on('click', function () { + // check if there are outstanding changes + handleOutstandingChanges().done(function () { + // close the shell + $('#shell-dialog').modal('hide'); + + // show the component in question + nfCanvasUtils.showComponent(affectedProcessor.processGroupId, affectedProcessor.id); + }); + }).appendTo(affectedProcessorContainer); + + // bulletin + $('<div class="referencing-component-bulletins"></div>').addClass(affectedProcessor.id + '-affected-bulletins').appendTo(affectedProcessorContainer); + + // processor active threads + $('<span class="referencing-component-active-thread-count"></span>').text(function () { + if (nfCommon.isDefinedAndNotNull(affectedProcessor.activeThreadCount) && affectedProcessor.activeThreadCount > 0) { + return '(' + affectedProcessor.activeThreadCount + ')'; + } else { + return ''; + } + }).appendTo(affectedProcessorContainer); + }; + + /** + * Renders the specified affect controller service. + * + * @param {object} affectedControllerServiceEntity + * @param {jQuery} container + */ + var renderAffectedControllerService = function (affectedControllerServiceEntity, container) { + var affectedControllerServiceContainer = $('<li class="affected-component-container"></li>').appendTo(container); + var affectedControllerService = affectedControllerServiceEntity.component; + + // controller service state + $('<div class="referencing-component-state"></div>').addClass(function () { + if (nfCommon.isDefinedAndNotNull(affectedControllerService.state)) { + var icon = $(this); + + var state = affectedControllerService.state === 'ENABLED' ? 'enabled' : 'disabled'; + if (state === 'disabled' && !nfCommon.isEmpty(affectedControllerService.validationErrors)) { + state = 'invalid'; + + // build the error listing + var list = nfCommon.formatUnorderedList(affectedControllerService.validationErrors); + + // add tooltip for the warnings + icon.qtip($.extend({}, + nfCanvasUtils.config.systemTooltipConfig, + { + content: list + })); + } + return state; + } else { + return ''; + } + }).appendTo(affectedControllerServiceContainer); + + // bulletin + $('<div class="referencing-component-bulletins"></div>').addClass(affectedControllerService.id + '-affected-bulletins').appendTo(affectedControllerServiceContainer); + + // controller service name + $('<span class="referencing-component-name link"></span>').text(affectedControllerService.name).on('click', function () { + // check if there are outstanding changes + handleOutstandingChanges().done(function () { + // close the shell + $('#shell-dialog').modal('hide'); + + // show the component in question + nfProcessGroupConfiguration.showConfiguration(affectedControllerService.processGroupId).done(function () { + nfProcessGroupConfiguration.selectControllerService(affectedControllerService.id); + }); + }); + }).appendTo(affectedControllerServiceContainer); + }; + + /** + * Populates the affected components for the specified parameter context. + * + * @param {object} affectedComponents + */ + var populateAffectedComponents = function (affectedComponents) { + // 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 affectedProcessors = []; + var affectedControllerServices = []; + var unauthorizedAffectedComponents = []; + + // clear the affected components from the previous selection + var affectedProcessorContainer = $('.parameter-context-affected-processors'); + nfCommon.cleanUpTooltips(affectedProcessorContainer, 'div.referencing-component-state'); + nfCommon.cleanUpTooltips(affectedProcessorContainer, 'div.referencing-component-bulletins'); + affectedProcessorContainer.empty(); + + var affectedControllerServiceContainer = $('.parameter-context-affected-controller-services'); + nfCommon.cleanUpTooltips(affectedControllerServiceContainer, 'div.referencing-component-state'); + nfCommon.cleanUpTooltips(affectedControllerServiceContainer, 'div.referencing-component-bulletins'); + affectedControllerServiceContainer.empty(); + + var unauthorizedComponentsContainer = $('.parameter-context-affected-unauthorized-components'); + unauthorizedComponentsContainer.empty(); + + var parameterReferencingComponentsContainer = $('#parameter-referencing-components-container').empty(); + + // affected component will be undefined when a new parameter is added + if (nfCommon.isUndefined(affectedComponents)) { + // set to pending + $('<div class="affected-component-container"><span class="unset">Pending Apply</span></div>').appendTo(parameterReferencingComponentsContainer); + } else { + var referencingComponentsForBulletinRetrieval = []; + + // bin the affected components according to their type + $.each(affectedComponents, function (_, affectedComponentEntity) { + if (affectedComponentEntity.permissions.canRead === true && affectedComponentEntity.permissions.canWrite === true) { + referencingComponentsForBulletinRetrieval.push(affectedComponentEntity.id); + + if (affectedComponentEntity.component.referenceType === 'PROCESSOR') { + affectedProcessors.push(affectedComponentEntity); + } else { + affectedControllerServices.push(affectedComponentEntity); + } + } else { + // if we're unauthorized only because the user is lacking write permissions, we can still query for bulletins + if (affectedComponentEntity.permissions.canRead === true) { + referencingComponentsForBulletinRetrieval.push(affectedComponentEntity.id); + } + + unauthorizedAffectedComponents.push(affectedComponentEntity); + } + }); + + var affectedProcessGroups = {}; + + // bin the affected processors according to their PG + $.each(affectedProcessors, function (_, affectedProcessorEntity) { + if (affectedProcessGroups[affectedProcessorEntity.component.processGroupId]) { + affectedProcessGroups[affectedProcessorEntity.component.processGroupId].affectedProcessors.push(affectedProcessorEntity); + } else { + affectedProcessGroups[affectedProcessorEntity.component.processGroupId] = { + affectedProcessors: [], + affectedControllerServices: [], + unauthorizedAffectedComponents: [] + }; + + affectedProcessGroups[affectedProcessorEntity.component.processGroupId].affectedProcessors.push(affectedProcessorEntity); + } + }); + + // bin the affected CS according to their PG + $.each(affectedControllerServices, function (_, affectedControllerServiceEntity) { + if (affectedProcessGroups[affectedControllerServiceEntity.component.processGroupId]) { + affectedProcessGroups[affectedControllerServiceEntity.component.processGroupId].affectedControllerServices.push(affectedControllerServiceEntity); + } else { + affectedProcessGroups[affectedControllerServiceEntity.component.processGroupId] = { + affectedProcessors: [], + affectedControllerServices: [], + unauthorizedAffectedComponents: [] + }; + + affectedProcessGroups[affectedControllerServiceEntity.component.processGroupId].affectedControllerServices.push(affectedControllerServiceEntity); + } + }); + + // bin the affected unauthorized components according to their PG + $.each(unauthorizedAffectedComponents, function (_, unauthorizedAffectedComponentEntity) { + if (unauthorizedAffectedComponentEntity.permissions.canRead === true) { + if (affectedProcessGroups[unauthorizedAffectedComponentEntity.component.processGroupId]) { + affectedProcessGroups[unauthorizedAffectedComponentEntity.component.processGroupId].unauthorizedAffectedComponents.push(unauthorizedAffectedComponentEntity); + } else { + affectedProcessGroups[unauthorizedAffectedComponentEntity.component.processGroupId] = { + affectedProcessors: [], + affectedControllerServices: [], + unauthorizedAffectedComponents: [] + }; + + affectedProcessGroups[unauthorizedAffectedComponentEntity.component.processGroupId].unauthorizedAffectedComponents.push(unauthorizedAffectedComponentEntity); + } + } + }); + + var parameterReferencingComponentsContainer = $('#parameter-referencing-components-container'); + var groups = $('<ul class="referencing-component-listing clear"></ul>'); + for (var key in affectedProcessGroups) { + if (affectedProcessGroups.hasOwnProperty(key)) { + // container for this pg's references + var referencingPgReferencesContainer = $('<div class="referencing-component-references"></div>'); + parameterReferencingComponentsContainer.append(referencingPgReferencesContainer); + + // create the collapsable listing for each PG + var createReferenceBlock = function (titleText, list) { + var twist = $('<div class="expansion-button collapsed"></div>'); + var title = $('<span class="referencing-component-title"></span>').text(titleText); + var count = $('<span class="referencing-component-count"></span>').text('(' + (affectedProcessGroups[key].affectedProcessors.length + affectedProcessGroups[key].affectedControllerServices.length + affectedProcessGroups[key].unauthorizedAffectedComponents.length) + ')'); + var referencingComponents = $('#referencing-components-template').clone(); + referencingComponents.removeAttr('id'); + referencingComponents.removeClass('hidden'); + + // create the reference block + var groupTwist = $('<div class="referencing-component-block pointer unselectable"></div>').data('processGroupId', key).on('click', function () { + if (twist.hasClass('collapsed')) { + groupTwist.append(referencingComponents); + + var processorContainer = groupTwist.find('.parameter-context-affected-processors'); + nfCommon.cleanUpTooltips(processorContainer, 'div.referencing-component-state'); + nfCommon.cleanUpTooltips(processorContainer, 'div.referencing-component-bulletins'); + processorContainer.empty(); + + var controllerServiceContainer = groupTwist.find('.parameter-context-affected-controller-services'); + nfCommon.cleanUpTooltips(controllerServiceContainer, 'div.referencing-component-state'); + nfCommon.cleanUpTooltips(controllerServiceContainer, 'div.referencing-component-bulletins'); + controllerServiceContainer.empty(); + + var unauthorizedComponentsContainer = groupTwist.find('.parameter-context-affected-unauthorized-components').empty(); + + if (affectedProcessGroups[$(this).data('processGroupId')].affectedProcessors.length === 0) { + $('<li class="affected-component-container"><span class="unset">None</span></li>').appendTo(processorContainer); + } else { + // sort the affected processors + affectedProcessGroups[$(this).data('processGroupId')].affectedProcessors.sort(nameComparator); + + // render each and register a click handler + $.each(affectedProcessGroups[$(this).data('processGroupId')].affectedProcessors, function (_, affectedProcessorEntity) { + renderAffectedProcessor(affectedProcessorEntity, processorContainer); + }); + } + + if (affectedProcessGroups[$(this).data('processGroupId')].affectedControllerServices.length === 0) { + $('<li class="affected-component-container"><span class="unset">None</span></li>').appendTo(controllerServiceContainer); + } else { + // sort the affected controller services + affectedProcessGroups[$(this).data('processGroupId')].affectedControllerServices.sort(nameComparator); + + // render each and register a click handler + $.each(affectedProcessGroups[$(this).data('processGroupId')].affectedControllerServices, function (_, affectedControllerServiceEntity) { + renderAffectedControllerService(affectedControllerServiceEntity, controllerServiceContainer); + }); + } + + if (affectedProcessGroups[$(this).data('processGroupId')].unauthorizedAffectedComponents.length === 0) { + $('<li class="affected-component-container"><span class="unset">None</span></li>').appendTo(unauthorizedComponentsContainer); + } else { + // sort the unauthorized affected components + affectedProcessGroups[$(this).data('processGroupId')].unauthorizedAffectedComponents.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(affectedProcessGroups[$(this).data('processGroupId')].unauthorizedAffectedComponents, function (_, unauthorizedAffectedComponentEntity) { + if (unauthorizedAffectedComponentEntity.permissions.canRead === true) { + if (unauthorizedAffectedComponentEntity.component.referenceType === 'PROCESSOR') { + renderAffectedProcessor(unauthorizedAffectedComponentEntity, unauthorizedComponentsContainer); + } else { + renderAffectedControllerService(unauthorizedAffectedComponentEntity, unauthorizedComponentsContainer); + } + } else { + var affectedUnauthorizedComponentContainer = $('<li class="affected-component-container"></li>').appendTo(unauthorizedComponentsContainer); + $('<span class="unset"></span>').text(unauthorizedAffectedComponentEntity.id).appendTo(affectedUnauthorizedComponentContainer); + } + }); + } + + // query for the bulletins + if (referencingComponentsForBulletinRetrieval.length > 0) { + nfCanvasUtils.queryBulletins(referencingComponentsForBulletinRetrieval).done(function (response) { + var bulletins = response.bulletinBoard.bulletins; + + var bulletinsBySource = d3.nest() + .key(function (d) { + return d.sourceId; + }) + .map(bulletins, d3.map); + + bulletinsBySource.each(function (sourceBulletins, sourceId) { + $('div.' + sourceId + '-affected-bulletins').each(function () { + var bulletinIcon = $(this); + + // if there are bulletins update them + if (sourceBulletins.length > 0) { + // format the new bulletins + var formattedBulletins = nfCommon.getFormattedBulletins(sourceBulletins); + + var list = nfCommon.formatUnorderedList(formattedBulletins); + + // update existing tooltip or initialize a new one if appropriate + bulletinIcon.addClass('has-bulletins').show().qtip($.extend({}, + nfCanvasUtils.config.systemTooltipConfig, + { + content: list + })); + } + }); + }); + }); + } + } else { + groupTwist.find('.referencing-components-template').remove(); + } + + // toggle this block + toggle(twist, list); + + // update the border if necessary + updateReferencingComponentsBorder($('#parameter-referencing-components-container')); + }).append(twist).append(title).append(count).appendTo(referencingPgReferencesContainer); + + // add the listing + list.appendTo(referencingPgReferencesContainer); + }; + + // get process group and show name or UUID based on user permissions + var pg = nfProcessGroup.get(key); + if (!nfCommon.isUndefinedOrNull(pg)) { + if (pg.permissions.canRead === true) { + // create block for this process group + createReferenceBlock(pg.component.name, groups); + } else { + // create block for this process group + createReferenceBlock(key, groups); + } + } else { + var processGroupName = key; + + // attempt to resolve the group name + var breadcrumbs = nfNgBridge.injector.get('breadcrumbsCtrl').getBreadcrumbs(); + $.each(breadcrumbs, function (_, breadcrumbEntity) { + if (breadcrumbEntity.id === key) { + processGroupName = breadcrumbEntity.label; + return false; + } + }); + // create block for this process group + createReferenceBlock(processGroupName, groups); + } + } + } + } + }; + + /** + * 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); + }; + + const parameterKeyRegex = /^[a-zA-Z0-9-_. ]+/; + + /** + * Adds a new parameter. + */ + var addNewParameter = function () { + var parameterName = $.trim($('#parameter-name').val()); + + // ensure the parameter name is specified + if (parameterName !== '' && parameterKeyRegex.test(parameterName)) { + var parameterGrid = $('#parameter-table').data('gridInstance'); + var parameterData = parameterGrid.getData(); + + // ensure the parameter name is unique + var matchingParameter = null; + $.each(parameterData.getItems(), function (_, item) { + if (parameterName === item.name) { Review comment: I am not sure about this, but I wanted to bring it up. Should we account for deleted items when verifying a parameter name is unique? If you delete a param `param 1` then add a new one with the same name (`param 1`), the user is warned that it already exists. Is that what we expect? We could effectively remove the hidden/deleted designation and let them edit it... but they wouldn't be able to change the sensitive property if that is truly what they were trying to do. Currently it prevents the user from getting into that situation by forcing them to apply the update to the context before re-adding a param with the same name. That might just be the acceptable answer. However, when you are adding a new param, set the sensitive properly wrong, then delete it and try to re-add it correctly (without ever having saved the original param) the usage is a bit wonky IMO. ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org With regards, Apache Git Services