You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by ma...@apache.org on 2015/04/10 15:43:41 UTC
[06/62] [abbrv] incubator-nifi git commit: Squashed commit of the
following:
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e9647717/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-service.js
----------------------------------------------------------------------
diff --git a/nifi/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/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-service.js
new file mode 100644
index 0000000..7fb3eba
--- /dev/null
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-service.js
@@ -0,0 +1,1730 @@
+/*
+ * 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 nf, d3 */
+
+nf.ControllerService = (function () {
+
+ var config = {
+ edit: 'edit',
+ readOnly: 'read-only',
+ serviceOnly: 'SERVICE_ONLY',
+ serviceAndReferencingComponents: 'SERVICE_AND_REFERENCING_COMPONENTS'
+ };
+
+ /**
+ * Handle any expected controller service configuration errors.
+ *
+ * @argument {object} xhr The XmlHttpRequest
+ * @argument {string} status The status of the request
+ * @argument {string} error The error
+ */
+ var handleControllerServiceConfigurationError = function (xhr, status, error) {
+ if (xhr.status === 400) {
+ var errors = xhr.responseText.split('\n');
+
+ var content;
+ if (errors.length === 1) {
+ content = $('<span></span>').text(errors[0]);
+ } else {
+ content = nf.Common.formatUnorderedList(errors);
+ }
+
+ nf.Dialog.showOkDialog({
+ dialogContent: content,
+ overlayBackground: false,
+ headerText: 'Configuration Error'
+ });
+ } else {
+ nf.Common.handleAjaxError(xhr, status, error);
+ }
+ };
+
+ /**
+ * Determines whether the user has made any changes to the controller service configuration
+ * that needs to be saved.
+ */
+ var isSaveRequired = function () {
+ var details = $('#controller-service-configuration').data('controllerServiceDetails');
+
+ // determine if any controller service settings have changed
+
+ if ($('#controller-service-name').val() !== details['name']) {
+ return true;
+ }
+ if ($('#controller-service-comments').val() !== details['comments']) {
+ return true;
+ }
+
+ if ($('#controller-service-enabled').hasClass('checkbox-checked') && details['state'] === 'DISABLED') {
+ return true;
+ } else if ($('#controller-service-enabled').hasClass('checkbox-unchecked') && details['state'] === 'ENABLED') {
+ return true;
+ }
+
+ // defer to the properties
+ return $('#controller-service-properties').propertytable('isSaveRequired');
+ };
+
+ /**
+ * Marshals the data that will be used to update the contr oller service's configuration.
+ */
+ var marshalDetails = function () {
+ // properties
+ var properties = $('#controller-service-properties').propertytable('marshalProperties');
+
+ // create the controller service dto
+ var controllerServiceDto = {};
+ controllerServiceDto['id'] = $('#controller-service-id').text();
+ controllerServiceDto['name'] = $('#controller-service-name').val();
+ controllerServiceDto['comments'] = $('#controller-service-comments').val();
+
+ // set the properties
+ if ($.isEmptyObject(properties) === false) {
+ controllerServiceDto['properties'] = properties;
+ }
+
+ // mark the controller service enabled if appropriate
+ if ($('#controller-service-enabled').hasClass('checkbox-unchecked')) {
+ controllerServiceDto['state'] = 'DISABLED';
+ } else if ($('#controller-service-enabled').hasClass('checkbox-checked')) {
+ controllerServiceDto['state'] = 'ENABLED';
+ }
+
+ // create the controller service entity
+ var controllerServiceEntity = {};
+ controllerServiceEntity['revision'] = nf.Client.getRevision();
+ controllerServiceEntity['controllerService'] = controllerServiceDto;
+
+ // return the marshaled details
+ return controllerServiceEntity;
+ };
+
+ /**
+ * Validates the specified details.
+ *
+ * @argument {object} details The details to validate
+ */
+ var validateDetails = function (details) {
+ return true;
+ };
+
+ /**
+ * Reloads the specified controller service. It's referencing and referenced
+ * components are NOT reloaded.
+ *
+ * @param {string} id
+ */
+ var reloadControllerService = function (id) {
+ // get the table and update the row accordingly
+ var controllerServiceGrid = $('#controller-services-table').data('gridInstance');
+ var controllerServiceData = controllerServiceGrid.getData();
+ var controllerService = controllerServiceData.getItemById(id);
+
+ // this may happen if controller service A references another controller
+ // service B that has been removed. attempting to enable/disable/remove A
+ // will attempt to reload B which is no longer a known service
+ if (nf.Common.isUndefined(controllerService)) {
+ return $.Deferred(function (deferred) {
+ deferred.reject();
+ }).promise();
+ }
+
+ return $.ajax({
+ type: 'GET',
+ url: controllerService.uri,
+ dataType: 'json'
+ }).done(function (response) {
+ renderControllerService(response.controllerService);
+ }).fail(nf.Common.handleAjaxError);
+ };
+
+ /**
+ * Renders the specified controller service.
+ *
+ * @param {object} controllerService
+ */
+ var renderControllerService = function (controllerService) {
+ // get the table and update the row accordingly
+ var controllerServiceGrid = $('#controller-services-table').data('gridInstance');
+ var controllerServiceData = controllerServiceGrid.getData();
+ controllerServiceData.updateItem(controllerService.id, controllerService);
+ };
+
+ /**
+ * Reloads the specified controller services and all of its referencing
+ * and referenced components.
+ *
+ * @param {type} controllerService
+ */
+ var reloadControllerServiceAndReferencingComponents = function (controllerService) {
+ reloadControllerService(controllerService.id).done(function(response) {
+ reloadControllerServiceReferences(response.controllerService);
+ });
+ };
+
+ /**
+ * Reloads components that reference this controller service as well as
+ * other services that this controller service references.
+ *
+ * @param {object} controllerService
+ */
+ var reloadControllerServiceReferences = function (controllerService) {
+ // reload all dependent processors if they are currently visible
+ $.each(controllerService.referencingComponents, function (_, reference) {
+ if (reference.referenceType === 'Processor') {
+ // reload the processor on the canvas if appropriate
+ if (nf.Canvas.getGroupId() === reference.groupId) {
+ var processor = nf.Processor.get(reference.id);
+ nf.Processor.reload(processor.component);
+ }
+
+ // update the current active thread count
+ $('div.' + reference.id + '-active-threads').text(reference.activeThreadCount);
+
+ // update the current state of this processor
+ var referencingComponentState = $('div.' + reference.id + '-state');
+ if (referencingComponentState.length) {
+ updateReferencingSchedulableComponentState(referencingComponentState, reference);
+ }
+ } else if (reference.referenceType === 'ReportingTask') {
+ // reload the referencing reporting tasks
+ nf.ReportingTask.reload(reference.id);
+
+ // update the current active thread count
+ $('div.' + reference.id + '-active-threads').text(reference.activeThreadCount);
+
+ // update the current state of this reporting task
+ var referencingComponentState = $('div.' + reference.id + '-state');
+ if (referencingComponentState.length) {
+ updateReferencingSchedulableComponentState(referencingComponentState, reference);
+ }
+ } else {
+ // reload the referencing services
+ reloadControllerService(reference.id);
+
+ // update the current state of this service
+ var referencingComponentState = $('div.' + reference.id + '-state');
+ if (referencingComponentState.length) {
+ updateReferencingServiceState(referencingComponentState, reference);
+ }
+
+ // consider it's referencing components if appropriate
+ if (reference.referenceCycle === false) {
+ reloadControllerServiceReferences(reference);
+ }
+ }
+ });
+
+ // see if this controller service references another controller service
+ // in order to update the referenced service referencing components
+ nf.ControllerService.reloadReferencedServices(controllerService);
+ };
+
+ /**
+ * 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 > referenceContainer.innerHeight() ||
+ referenceContainer.get(0).scrollWidth > referenceContainer.innerWidth();
+
+ // draw the border if necessary
+ if (referenceContainer.is(':visible') && tooBig) {
+ referenceContainer.css('border-width', '1px');
+ } else {
+ referenceContainer.css('border-width', '0px');
+ }
+ };
+
+ /**
+ * Updates the referencingComponentState using the specified referencingComponent.
+ *
+ * @param {jQuery} referencingComponentState
+ * @param {object} referencingComponent
+ */
+ var updateReferencingSchedulableComponentState = function (referencingComponentState, referencingComponent) {
+ referencingComponentState.removeClass('disabled stopped running invalid').addClass(function() {
+ var icon = $(this);
+
+ var state = referencingComponent.state.toLowerCase();
+ if (state === 'stopped' && !nf.Common.isEmpty(referencingComponent.validationErrors)) {
+ state = 'invalid';
+
+ // add tooltip for the warnings
+ var list = nf.Common.formatUnorderedList(referencingComponent.validationErrors);
+ if (icon.data('qtip')) {
+ icon.qtip('option', 'content.text', list);
+ } else {
+ icon.qtip($.extend({
+ content: list
+ }, nf.CanvasUtils.config.systemTooltipConfig));
+ }
+ } else if (icon.data('qtip')) {
+ icon.qtip('destroy');
+ }
+ return state;
+ });
+ };
+
+ /**
+ * Updates the referencingServiceState using the specified referencingService.
+ *
+ * @param {jQuery} referencingServiceState
+ * @param {object} referencingService
+ */
+ var updateReferencingServiceState = function (referencingServiceState, referencingService) {
+ referencingServiceState.removeClass('disabled enabled invalid').addClass(function() {
+ var icon = $(this);
+
+ var state = referencingService.state === 'ENABLED' ? 'enabled' : 'disabled';
+ if (state === 'disabled' && !nf.Common.isEmpty(referencingService.validationErrors)) {
+ state = 'invalid';
+
+ // add tooltip for the warnings
+ var list = nf.Common.formatUnorderedList(referencingService.validationErrors);
+ if (icon.data('qtip')) {
+ icon.qtip('option', 'content.text', list);
+ } else {
+ icon.qtip($.extend({
+ content: list
+ }, nf.CanvasUtils.config.systemTooltipConfig));
+ }
+ } else if (icon.data('qtip')) {
+ icon.qtip('destroy');
+ }
+ return state;
+ });
+ };
+
+ /**
+ * Adds the specified reference for this controller service.
+ *
+ * @param {jQuery} referenceContainer
+ * @param {array} referencingComponents
+ */
+ var createReferencingComponents = function (referenceContainer, referencingComponents) {
+ if (nf.Common.isEmpty(referencingComponents)) {
+ referenceContainer.append('<div class="unset">No referencing components.</div>');
+ 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 processors = $('<ul class="referencing-component-listing clear"></ul>');
+ var services = $('<ul class="referencing-component-listing clear"></ul>');
+ var tasks = $('<ul class="referencing-component-listing clear"></ul>');
+ $.each(referencingComponents, function (_, referencingComponent) {
+ if (referencingComponent.referenceType === 'Processor') {
+ var processorLink = $('<span class="referencing-component-name link"></span>').text(referencingComponent.name).on('click', function () {
+ // show the component
+ nf.CanvasUtils.showComponent(referencingComponent.groupId, referencingComponent.id);
+
+ // close the dialog and shell
+ referenceContainer.closest('.dialog').modal('hide');
+ $('#shell-close-button').click();
+ });
+
+ // state
+ var processorState = $('<div class="referencing-component-state"></div>').addClass(referencingComponent.id + '-state');
+ updateReferencingSchedulableComponentState(processorState, referencingComponent);
+
+ // type
+ var processorType = $('<span class="referencing-component-type"></span>').text(nf.Common.substringAfterLast(referencingComponent.type, '.'));
+
+ // active thread count
+ var processorActiveThreadCount = $('<span class="referencing-component-active-thread-count"></span>').addClass(referencingComponent.id + '-active-threads');
+ if (nf.Common.isDefinedAndNotNull(referencingComponent.activeThreadCount) && referencingComponent.activeThreadCount > 0) {
+ processorActiveThreadCount.text('(' + referencingComponent.activeThreadCount + ')');
+ }
+
+ // processor
+ var processorItem = $('<li></li>').append(processorState).append(processorLink).append(processorType).append(processorActiveThreadCount);
+ processors.append(processorItem);
+ } else if (referencingComponent.referenceType === 'ControllerService') {
+ var serviceLink = $('<span class="referencing-component-name link"></span>').text(referencingComponent.name).on('click', function () {
+ var controllerServiceGrid = $('#controller-services-table').data('gridInstance');
+ var controllerServiceData = controllerServiceGrid.getData();
+
+ // select the selected row
+ var row = controllerServiceData.getRowById(referencingComponent.id);
+ controllerServiceGrid.setSelectedRows([row]);
+
+ // close the dialog and shell
+ referenceContainer.closest('.dialog').modal('hide');
+ });
+
+ // container for this service's references
+ var referencingServiceReferencesContainer = $('<div class="referencing-component-references hidden"></div>');
+ var serviceTwist = $('<span class="service expansion-button collapsed pointer"></span>').on('click', function() {
+ if (serviceTwist.hasClass('collapsed')) {
+ var controllerServiceGrid = $('#controller-services-table').data('gridInstance');
+ var controllerServiceData = controllerServiceGrid.getData();
+ var referencingService = controllerServiceData.getItemById(referencingComponent.id);
+
+ // create the markup for the references
+ createReferencingComponents(referencingServiceReferencesContainer, referencingService.referencingComponents);
+ } else {
+ referencingServiceReferencesContainer.empty();
+ }
+
+ // toggle visibility
+ toggle(serviceTwist, referencingServiceReferencesContainer);
+
+ // update borders as necessary
+ updateReferencingComponentsBorder(referenceContainer);
+ });
+
+ // state
+ var serviceState = $('<div class="referencing-component-state"></div>').addClass(referencingComponent.id + '-state');
+ updateReferencingServiceState(serviceState, referencingComponent);
+
+ // type
+ var serviceType = $('<span class="referencing-component-type"></span>').text(nf.Common.substringAfterLast(referencingComponent.type, '.'));
+
+ // service
+ var serviceItem = $('<li></li>').append(serviceTwist).append(serviceState).append(serviceLink).append(serviceType).append(referencingServiceReferencesContainer);
+
+ services.append(serviceItem);
+ } else if (referencingComponent.referenceType === 'ReportingTask') {
+ var reportingTaskLink = $('<span class="referencing-component-name link"></span>').text(referencingComponent.name).on('click', function () {
+ var reportingTaskGrid = $('#reporting-tasks-table').data('gridInstance');
+ var reportingTaskData = reportingTaskGrid.getData();
+
+ // select the selected row
+ var row = reportingTaskData.getRowById(referencingComponent.id);
+ reportingTaskGrid.setSelectedRows([row]);
+
+ // select the reporting task tab
+ $('#settings-tabs').find('li:last').click();
+
+ // close the dialog and shell
+ referenceContainer.closest('.dialog').modal('hide');
+ });
+
+ // state
+ var reportingTaskState = $('<div class="referencing-component-state"></div>').addClass(referencingComponent.id + '-state');
+ updateReferencingSchedulableComponentState(reportingTaskState, referencingComponent);
+
+ // type
+ var reportingTaskType = $('<span class="referencing-component-type"></span>').text(nf.Common.substringAfterLast(referencingComponent.type, '.'));
+
+ // active thread count
+ var reportingTaskActiveThreadCount = $('<span class="referencing-component-active-thread-count"></span>').addClass(referencingComponent.id + '-active-threads');
+ if (nf.Common.isDefinedAndNotNull(referencingComponent.activeThreadCount) && referencingComponent.activeThreadCount > 0) {
+ reportingTaskActiveThreadCount.text('(' + referencingComponent.activeThreadCount + ')');
+ }
+
+ // reporting task
+ var reportingTaskItem = $('<li></li>').append(reportingTaskState).append(reportingTaskLink).append(reportingTaskType).append(reportingTaskActiveThreadCount);
+ tasks.append(reportingTaskItem);
+ }
+ });
+
+ // create the collapsable listing for each type
+ var createReferenceBlock = function (titleText, list) {
+ if (list.is(':empty')) {
+ list.remove();
+ return;
+ }
+
+ var twist = $('<span class="expansion-button expanded"></span>');
+ var title = $('<span class="referencing-component-title"></span>').text(titleText);
+ var count = $('<span class="referencing-component-count"></span>').text('(' + list.children().length + ')');
+
+ // create the reference block
+ $('<div class="referencing-component-block pointer unselectable"></div>').on('click', function () {
+ // toggle this block
+ toggle(twist, list);
+
+ // update the border if necessary
+ updateReferencingComponentsBorder(referenceContainer);
+ }).append(twist).append(title).append(count).appendTo(referenceContainer);
+
+ // add the listing
+ list.appendTo(referenceContainer);
+ };
+
+ // create blocks for each type of component
+ createReferenceBlock('Processors', processors);
+ createReferenceBlock('Reporting Tasks', tasks);
+ createReferenceBlock('Controller Services', services);
+ };
+
+ /**
+ * Sets whether the specified controller service is enabled.
+ *
+ * @param {object} controllerService
+ * @param {boolean} enabled
+ * @param {function} pollCondition
+ */
+ var setEnabled = function (controllerService, enabled, pollCondition) {
+ var revision = nf.Client.getRevision();
+
+ var updated = $.ajax({
+ type: 'PUT',
+ url: controllerService.uri,
+ data: {
+ clientId: revision.clientId,
+ version: revision.version,
+ state: enabled === true ? 'ENABLED' : 'DISABLED'
+ },
+ dataType: 'json'
+ }).done(function (response) {
+ nf.Client.setRevision(response.revision);
+ }).fail(nf.Common.handleAjaxError);
+
+ // wait unil the polling of each service finished
+ return $.Deferred(function(deferred) {
+ updated.done(function() {
+ var serviceUpdated = pollService(controllerService, function (service) {
+ // the condition is met once the service is ENABLED/DISABLED
+ if (enabled) {
+ return service.state === 'ENABLED';
+ } else {
+ return service.state === 'DISABLED';
+ }
+ }, pollCondition);
+
+ // once the service has updated, resolve and render the updated service
+ serviceUpdated.done(function () {
+ deferred.resolve();
+ }).fail(function() {
+ deferred.reject();
+ });
+ }).fail(function() {
+ deferred.reject();
+ });
+ }).promise();
+ };
+
+ /**
+ * Gets the id's of all controller services referencing the specified controller service.
+ *
+ * @param {object} controllerService
+ */
+ var getReferencingControllerServiceIds = function (controllerService) {
+ var ids = d3.set();
+ ids.add(controllerService.id);
+
+ var checkReferencingServices = function (referencingComponents) {
+ $.each(referencingComponents, function (_, referencingComponent) {
+ if (referencingComponent.referenceType === 'ControllerService') {
+ // add the id
+ ids.add(referencingComponent.id);
+
+ // consider it's referencing components if appropriate
+ if (referencingComponent.referenceCycle === false) {
+ checkReferencingServices(referencingComponent.referencingComponents);
+ }
+ }
+ });
+ };
+
+ // check the referencing servcies
+ checkReferencingServices(controllerService.referencingComponents);
+ return ids;
+ };
+
+ /**
+ * Updates the scheduled state of the processors/reporting tasks referencing
+ * the specified controller service.
+ *
+ * @param {object} controllerService
+ * @param {boolean} running
+ * @param {function} pollCondition
+ */
+ var updateReferencingSchedulableComponents = function (controllerService, running, pollCondition) {
+ var revision = nf.Client.getRevision();
+
+ // issue the request to update the referencing components
+ var updated = $.ajax({
+ type: 'PUT',
+ url: controllerService.uri + '/references',
+ data: {
+ clientId: revision.clientId,
+ version: revision.version,
+ state: running ? 'RUNNING' : 'STOPPED'
+ },
+ dataType: 'json'
+ }).done(function (response) {
+ nf.Client.setRevision(response.revision);
+ }).fail(nf.Common.handleAjaxError);
+
+ // wait unil the polling of each service finished
+ return $.Deferred(function(deferred) {
+ updated.done(function(response) {
+ // update the controller service
+ controllerService.referencingComponents = response.controllerServiceReferencingComponents;
+
+ // if we're just starting schedulable components we're done when the update is finished
+ if (running) {
+ deferred.resolve();
+ } else {
+ // identify all referencing services
+ var services = getReferencingControllerServiceIds(controllerService);
+
+ // get the controller service grid
+ var controllerServiceGrid = $('#controller-services-table').data('gridInstance');
+ var controllerServiceData = controllerServiceGrid.getData();
+
+ // start polling for each controller service
+ var polling = [];
+ services.forEach(function(controllerServiceId) {
+ var referencingService = controllerServiceData.getItemById(controllerServiceId);
+ polling.push(stopReferencingSchedulableComponents(referencingService, pollCondition));
+ });
+
+ // wait until polling has finished
+ $.when.apply(window, polling).done(function () {
+ deferred.resolve();
+ }).fail(function() {
+ deferred.reject();
+ });
+ }
+ }).fail(function() {
+ deferred.reject();
+ });
+ }).promise();
+ };
+
+ /**
+ * Polls the specified services referencing components to see if the
+ * specified condition is satisfied.
+ *
+ * @param {object} controllerService
+ * @param {function} completeCondition
+ * @param {function} pollCondition
+ */
+ var pollService = function (controllerService, completeCondition, pollCondition) {
+ // we want to keep polling until the condition is met
+ return $.Deferred(function(deferred) {
+ var current = 2;
+ var getTimeout = function () {
+ var val = current;
+
+ // update the current timeout for the next time
+ current = Math.max(current * 2, 8);
+
+ return val * 1000;
+ };
+
+ // polls for the current status of the referencing components
+ var poll = function() {
+ $.ajax({
+ type: 'GET',
+ url: controllerService.uri,
+ dataType: 'json'
+ }).done(function (response) {
+ conditionMet(response.controllerService);
+ }).fail(function (xhr, status, error) {
+ deferred.reject();
+ nf.Common.handleAjaxError(xhr, status, error);
+ });
+ };
+
+ // tests to if the condition has been met
+ var conditionMet = function (service) {
+ if (completeCondition(service)) {
+ deferred.resolve();
+ } else {
+ if (typeof pollCondition === 'function' && pollCondition()) {
+ setTimeout(poll(), getTimeout());
+ } else {
+ deferred.reject();
+ }
+ }
+ };
+
+ // poll for the status of the referencing components
+ conditionMet(controllerService);
+ }).promise();
+ };
+
+ /**
+ * Continues to poll the specified controller service until all referencing schedulable
+ * components are stopped (not scheduled and 0 active threads).
+ *
+ * @param {object} controllerService
+ * @param {function} pollCondition
+ */
+ var stopReferencingSchedulableComponents = function (controllerService, pollCondition) {
+ // continue to poll the service until all schedulable components have stopped
+ return pollService(controllerService, function (service) {
+ var referencingComponents = service.referencingComponents;
+
+ var stillRunning = false;
+ $.each(referencingComponents, function(_, referencingComponent) {
+ if (referencingComponent.referenceType === 'Processor' || referencingComponent.referenceType === 'ReportingTask') {
+ if (referencingComponent.state !== 'STOPPED' || referencingComponent.activeThreadCount > 0) {
+ stillRunning = true;
+ }
+
+ // update the current active thread count
+ $('div.' + referencingComponent.id + '-active-threads').text(referencingComponent.activeThreadCount);
+
+ // update the current state of this component
+ var referencingComponentState = $('div.' + referencingComponent.id + '-state');
+ updateReferencingSchedulableComponentState(referencingComponentState, referencingComponent);
+ }
+ });
+
+ // condition is met once all referencing are not running
+ return stillRunning === false;
+ }, pollCondition);
+ };
+
+ /**
+ * Continues to poll until all referencing services are enabled.
+ *
+ * @param {object} controllerService
+ * @param {function} pollCondition
+ */
+ var enableReferencingServices = function (controllerService, pollCondition) {
+ // continue to poll the service until all referencing services are enabled
+ return pollService(controllerService, function (service) {
+ var referencingComponents = service.referencingComponents;
+
+ var notEnabled = false;
+ $.each(referencingComponents, function(_, referencingComponent) {
+ if (referencingComponent.referenceType === 'ControllerService') {
+ if (referencingComponent.state !== 'ENABLED') {
+ notEnabled = true;
+ }
+
+ // update the state of the referencing service
+ var referencingServiceState = $('div.' + referencingComponent.id + '-state');
+ updateReferencingServiceState(referencingServiceState, referencingComponent);
+ }
+ });
+
+ // condition is met once all referencing are not disabled
+ return notEnabled === false;
+ }, pollCondition);
+ };
+
+ /**
+ * Continues to poll until all referencing services are disabled.
+ *
+ * @param {object} controllerService
+ * @param {function} pollCondition
+ */
+ var disableReferencingServices = function (controllerService, pollCondition) {
+ // continue to poll the service until all referencing services are disabled
+ return pollService(controllerService, function (service) {
+ var referencingComponents = service.referencingComponents;
+
+ var notDisabled = false;
+ $.each(referencingComponents, function(_, referencingComponent) {
+ if (referencingComponent.referenceType === 'ControllerService') {
+ if (referencingComponent.state !== 'DISABLED') {
+ notDisabled = true;
+ }
+
+ // update the state of the referencing service
+ var referencingServiceState = $('div.' + referencingComponent.id + '-state');
+ updateReferencingServiceState(referencingServiceState, referencingComponent);
+ }
+ });
+
+ // condition is met once all referencing are not enabled
+ return notDisabled === false;
+ }, pollCondition);
+ };
+
+ /**
+ * Updates the referencing services with the specified state.
+ *
+ * @param {object} controllerService
+ * @param {boolean} enabled
+ * @param {function} pollCondition
+ */
+ var updateReferencingServices = function (controllerService, enabled, pollCondition) {
+ var revision = nf.Client.getRevision();
+
+ // issue the request to update the referencing components
+ var updated = $.ajax({
+ type: 'PUT',
+ url: controllerService.uri + '/references',
+ data: {
+ clientId: revision.clientId,
+ version: revision.version,
+ state: enabled ? 'ENABLED' : 'DISABLED'
+ },
+ dataType: 'json'
+ }).done(function (response) {
+ nf.Client.setRevision(response.revision);
+ }).fail(nf.Common.handleAjaxError);
+
+ // wait unil the polling of each service finished
+ return $.Deferred(function(deferred) {
+ updated.done(function(response) {
+ // update the controller service
+ controllerService.referencingComponents = response.controllerServiceReferencingComponents;
+
+ // identify all referencing services
+ var services = getReferencingControllerServiceIds(controllerService);
+
+ // get the controller service grid
+ var controllerServiceGrid = $('#controller-services-table').data('gridInstance');
+ var controllerServiceData = controllerServiceGrid.getData();
+
+ // start polling for each controller service
+ var polling = [];
+ services.forEach(function(controllerServiceId) {
+ var referencingService = controllerServiceData.getItemById(controllerServiceId);
+
+ if (enabled) {
+ polling.push(enableReferencingServices(referencingService, pollCondition));
+ } else {
+ polling.push(disableReferencingServices(referencingService, pollCondition));
+ }
+ });
+
+ $.when.apply(window, polling).done(function () {
+ deferred.resolve();
+ }).fail(function() {
+ deferred.reject();
+ });
+ }).fail(function() {
+ deferred.reject();
+ });
+ }).promise();
+ };
+
+ /**
+ * Shows the dialog for disabling a controller service.
+ *
+ * @argument {object} controllerService The controller service to disable
+ */
+ var showDisableControllerServiceDialog = function (controllerService) {
+ // populate the disable controller service dialog
+ $('#disable-controller-service-id').text(controllerService.id);
+ $('#disable-controller-service-name').text(controllerService.name);
+
+ // load the controller referencing components list
+ var referencingComponentsContainer = $('#disable-controller-service-referencing-components');
+ createReferencingComponents(referencingComponentsContainer, controllerService.referencingComponents);
+
+ // show the dialog
+ $('#disable-controller-service-dialog').modal('show');
+
+ // update the border if necessary
+ updateReferencingComponentsBorder(referencingComponentsContainer);
+ };
+
+ /**
+ * Shows the dialog for enabling a controller service.
+ *
+ * @param {object} controllerService
+ */
+ var showEnableControllerServiceDialog = function (controllerService) {
+ // populate the disable controller service dialog
+ $('#enable-controller-service-id').text(controllerService.id);
+ $('#enable-controller-service-name').text(controllerService.name);
+
+ // load the controller referencing components list
+ var referencingComponentsContainer = $('#enable-controller-service-referencing-components');
+ createReferencingComponents(referencingComponentsContainer, controllerService.referencingComponents);
+
+ // show the dialog
+ $('#enable-controller-service-dialog').modal('show');
+
+ // update the border if necessary
+ updateReferencingComponentsBorder(referencingComponentsContainer);
+ };
+
+ /**
+ * Used to handle closing a modal dialog
+ */
+ var closeModal = function() {
+ $(this).modal('hide');
+ };
+
+ /**
+ * Handles the disable action of the disable controller service dialog.
+ */
+ var disableHandler = function() {
+ var disableDialog = $(this);
+ var canceled = false;
+
+ // only provide a cancel option
+ disableDialog.modal('setButtonModel', [{
+ buttonText: 'Cancel',
+ handler: {
+ click: function () {
+ canceled = true;
+ }
+ }
+ }]);
+
+ // show the progress
+ $('#disable-controller-service-service-container').hide();
+ $('#disable-controller-service-scope-container').hide();
+ $('#disable-controller-service-progress-container').show();
+
+ // get the controller service
+ var controllerServiceId = $('#disable-controller-service-id').text();
+ var controllerServiceGrid = $('#controller-services-table').data('gridInstance');
+ var controllerServiceData = controllerServiceGrid.getData();
+ var controllerService = controllerServiceData.getItemById(controllerServiceId);
+
+ // whether or not to continue polling
+ var continuePolling = function () {
+ return canceled === false;
+ };
+
+ // sets the close button on the dialog
+ var setCloseButton = function () {
+ disableDialog.modal('setButtonModel', [{
+ buttonText: 'Close',
+ handler: {
+ click: closeModal
+ }
+ }]);
+ };
+
+ $('#disable-progress-label').text('Steps to disable ' + controllerService.name);
+ var disableReferencingSchedulable = $('#disable-referencing-schedulable').addClass('ajax-loading');
+
+ $.Deferred(function (deferred) {
+ // stop all referencing schedulable components
+ var stopped = updateReferencingSchedulableComponents(controllerService, false, continuePolling);
+
+ // once everything has stopped
+ stopped.done(function () {
+ disableReferencingSchedulable.removeClass('ajax-loading').addClass('ajax-complete');
+ var disableReferencingServices = $('#disable-referencing-services').addClass('ajax-loading');
+
+ // disable all referencing services
+ var disabled = updateReferencingServices(controllerService, false, continuePolling);
+
+ // everything is disabled
+ disabled.done(function () {
+ disableReferencingServices.removeClass('ajax-loading').addClass('ajax-complete');
+ var disableControllerService = $('#disable-controller-service').addClass('ajax-loading');
+
+ // disable this service
+ setEnabled(controllerService, false, continuePolling).done(function () {
+ deferred.resolve();
+ disableControllerService.removeClass('ajax-loading').addClass('ajax-complete');
+ }).fail(function () {
+ deferred.reject();
+ disableControllerService.removeClass('ajax-loading').addClass('ajax-error');
+ });
+ }).fail(function () {
+ deferred.reject();
+ disableReferencingServices.removeClass('ajax-loading').addClass('ajax-error');
+ });
+ }).fail(function () {
+ deferred.reject();
+ disableReferencingSchedulable.removeClass('ajax-loading').addClass('ajax-error');
+ });
+ }).always(function () {
+ reloadControllerServiceAndReferencingComponents(controllerService);
+ setCloseButton();
+ });
+ };
+
+ /**
+ * Handles the enable action of the enable controller service dialog.
+ */
+ var enableHandler = function() {
+ var enableDialog = $(this);
+ var canceled = false;
+
+ // only provide a cancel option
+ enableDialog.modal('setButtonModel', [{
+ buttonText: 'Cancel',
+ handler: {
+ click: function () {
+ canceled = true;
+ }
+ }
+ }]);
+
+ // determine if we want to also activate referencing components
+ var scope = $('#enable-controller-service-scope').combo('getSelectedOption').value;
+ if (scope === config.serviceOnly) {
+ $('#enable-controller-service-progress li.referencing-component').hide();
+ }
+
+ // show the progress
+ $('#enable-controller-service-service-container').hide();
+ $('#enable-controller-service-scope-container').hide();
+ $('#enable-controller-service-progress-container').show();
+
+ // get the controller service
+ var controllerServiceId = $('#enable-controller-service-id').text();
+ var controllerServiceGrid = $('#controller-services-table').data('gridInstance');
+ var controllerServiceData = controllerServiceGrid.getData();
+ var controllerService = controllerServiceData.getItemById(controllerServiceId);
+
+ // whether or not to continue polling
+ var continuePolling = function () {
+ return canceled === false;
+ };
+
+ // sets the button to close
+ var setCloseButton = function () {
+ enableDialog.modal('setButtonModel', [{
+ buttonText: 'Close',
+ handler: {
+ click: closeModal
+ }
+ }]);
+ };
+
+ $('#enable-progress-label').text('Steps to enable ' + controllerService.name);
+ var enableControllerService = $('#enable-controller-service').addClass('ajax-loading');
+
+ $.Deferred(function (deferred) {
+ // enable this controller service
+ var enable = setEnabled(controllerService, true, continuePolling);
+
+ if (scope === config.serviceAndReferencingComponents) {
+ // once the service is enabled, activate all referencing components
+ enable.done(function() {
+ enableControllerService.removeClass('ajax-loading').addClass('ajax-complete');
+ var enableReferencingServices = $('#enable-referencing-services').addClass('ajax-loading');
+
+ // enable the referencing services
+ var servicesEnabled = updateReferencingServices(controllerService, true, continuePolling);
+
+ // once all the referencing services are enbled
+ servicesEnabled.done(function () {
+ enableReferencingServices.removeClass('ajax-loading').addClass('ajax-complete');
+ var enableReferencingSchedulable = $('#enable-referencing-schedulable').addClass('ajax-loading');
+
+ // start all referencing schedulable components
+ updateReferencingSchedulableComponents(controllerService, true, continuePolling).done(function() {
+ deferred.resolve();
+ enableReferencingSchedulable.removeClass('ajax-loading').addClass('ajax-complete');
+ }).fail(function () {
+ deferred.reject();
+ enableReferencingSchedulable.removeClass('ajax-loading').addClass('ajax-error');
+ });
+ }).fail(function () {
+ deferred.reject();
+ enableReferencingServices.removeClass('ajax-loading').addClass('ajax-error');
+ });
+ }).fail(function () {
+ deferred.reject();
+ enableControllerService.removeClass('ajax-loading').addClass('ajax-error');
+ });
+ } else {
+ enable.done(function() {
+ deferred.resolve();
+ enableControllerService.removeClass('ajax-loading').addClass('ajax-complete');
+ }).fail(function () {
+ deferred.reject();
+ enableControllerService.removeClass('ajax-loading').addClass('ajax-error');
+ });
+ }
+ }).always(function () {
+ reloadControllerServiceAndReferencingComponents(controllerService);
+ setCloseButton();
+ });
+ };
+
+ /**
+ * Gets a property descriptor for the controller service currently being configured.
+ *
+ * @param {type} propertyName
+ */
+ var getControllerServicePropertyDescriptor = function (propertyName) {
+ var details = $('#controller-service-configuration').data('controllerServiceDetails');
+ return $.ajax({
+ type: 'GET',
+ url: details.uri + '/descriptors',
+ data: {
+ propertyName: propertyName
+ },
+ dataType: 'json'
+ }).fail(nf.Common.handleAjaxError);
+ };
+
+ /**
+ * Identifies the descriptors that identify controller services.
+ *
+ * @param {object} component
+ */
+ var identifyReferencedServiceDescriptors = function (component) {
+ var referencedServiceDescriptors = [];
+
+ $.each(component.descriptors, function(_, descriptor) {
+ if (descriptor.identifiesControllerService === true) {
+ referencedServiceDescriptors.push(descriptor);
+ }
+ });
+
+ return referencedServiceDescriptors;
+ };
+
+ /**
+ * Identifies descritpors that reference controller services.
+ *
+ * @param {object} component
+ */
+ var getReferencedServices = function (component) {
+ var referencedServices = [];
+
+ $.each(identifyReferencedServiceDescriptors(component), function(_, descriptor) {
+ var referencedServiceId = component.properties[descriptor.name];
+
+ // ensure the property is configured
+ if (nf.Common.isDefinedAndNotNull(referencedServiceId) && $.trim(referencedServiceId).length > 0) {
+ referencedServices.push(referencedServiceId);
+ }
+ });
+
+ return referencedServices;
+ };
+
+ return {
+ /**
+ * Initializes the controller service configuration dialog.
+ */
+ init: function () {
+ // initialize the configuration dialog tabs
+ $('#controller-service-configuration-tabs').tabbs({
+ tabStyle: 'tab',
+ selectedTabStyle: 'selected-tab',
+ tabs: [{
+ name: 'Settings',
+ tabContentId: 'controller-service-standard-settings-tab-content'
+ }, {
+ name: 'Properties',
+ tabContentId: 'controller-service-properties-tab-content'
+ }, {
+ name: 'Comments',
+ tabContentId: 'controller-service-comments-tab-content'
+ }],
+ select: function () {
+ // update the property table size in case this is the first time its rendered
+ if ($(this).text() === 'Properties') {
+ $('#controller-service-properties').propertytable('resetTableSize');
+ }
+
+ // close all fields currently being edited
+ $('#controller-service-properties').propertytable('saveRow');
+
+ // show the border around the processor relationships if necessary
+ var referenceContainer = $('#controller-service-referencing-components');
+ updateReferencingComponentsBorder(referenceContainer);
+ }
+ });
+
+ // we clustered we need to show the controls for editing the availability
+ if (nf.Canvas.isClustered()) {
+ $('#controller-service-availability-setting-container').show();
+ }
+
+ // initialize the conroller service configuration dialog
+ $('#controller-service-configuration').data('mode', config.edit).modal({
+ headerText: 'Configure Controller Service',
+ overlayBackground: false,
+ handler: {
+ close: function () {
+ // empty the referencing components list
+ var referencingComponents = $('#controller-service-referencing-components');
+ nf.Common.cleanUpTooltips(referencingComponents, 'div.referencing-component-state');
+ referencingComponents.css('border-width', '0').empty();
+
+ // cancel any active edits
+ $('#controller-service-properties').propertytable('cancelEdit');
+
+ // clear the tables
+ $('#controller-service-properties').propertytable('clear');
+
+ // clear the comments
+ nf.Common.clearField('read-only-controller-service-comments');
+
+ // removed the cached controller service details
+ $('#controller-service-configuration').removeData('controllerServiceDetails');
+ }
+ }
+ }).draggable({
+ containment: 'parent',
+ handle: '.dialog-header'
+ });
+
+ // initialize the property table
+ $('#controller-service-properties').propertytable({
+ readOnly: false,
+ newPropertyDialogContainer: '#new-controller-service-property-container',
+ descriptorDeferred: getControllerServicePropertyDescriptor
+ });
+
+ // initialize the disable service dialog
+ $('#disable-controller-service-dialog').modal({
+ headerText: 'Disable Controller Service',
+ overlayBackground: false,
+ buttons: [{
+ buttonText: 'Disable',
+ handler: {
+ click: disableHandler
+ }
+ }, {
+ buttonText: 'Cancel',
+ handler: {
+ click: closeModal
+ }
+ }],
+ handler: {
+ close: function() {
+ var disableDialog = $(this);
+
+ // reset visibility
+ $('#disable-controller-service-service-container').show();
+ $('#disable-controller-service-scope-container').show();
+ $('#disable-controller-service-progress-container').hide();
+
+ // clear the dialog
+ $('#disable-controller-service-id').text('');
+ $('#disable-controller-service-name').text('');
+
+ // reset progress
+ $('div.disable-referencing-components').removeClass('ajax-loading ajax-complete ajax-error');
+
+ // referencing components
+ var referencingComponents = $('#disable-controller-service-referencing-components');
+ nf.Common.cleanUpTooltips(referencingComponents, 'div.referencing-component-state');
+ referencingComponents.css('border-width', '0').empty();
+
+ // reset dialog
+ disableDialog.modal('setButtonModel', [{
+ buttonText: 'Disable',
+ handler: {
+ click: disableHandler
+ }
+ }, {
+ buttonText: 'Cancel',
+ handler: {
+ click: closeModal
+ }
+ }]);
+ }
+ }
+ }).draggable({
+ containment: 'parent',
+ handle: '.dialog-header'
+ });
+
+ // initialize the enable scope combo
+ $('#enable-controller-service-scope').combo({
+ options: [{
+ text: 'Service only',
+ value: config.serviceOnly,
+ description: 'Enable only this controller service'
+ }, {
+ text: 'Service and referencing components',
+ value: config.serviceAndReferencingComponents,
+ description: 'Enable this controller service and enable/start all referencing components'
+ }]
+ });
+
+ // initialize the enable service dialog
+ $('#enable-controller-service-dialog').modal({
+ headerText: 'Enable Controller Service',
+ overlayBackground: false,
+ buttons: [{
+ buttonText: 'Enable',
+ handler: {
+ click: enableHandler
+ }
+ }, {
+ buttonText: 'Cancel',
+ handler: {
+ click: closeModal
+ }
+ }],
+ handler: {
+ close: function() {
+ var enableDialog = $(this);
+
+ // reset visibility
+ $('#enable-controller-service-service-container').show();
+ $('#enable-controller-service-scope-container').show();
+ $('#enable-controller-service-progress-container').hide();
+ $('#enable-controller-service-progress li.referencing-component').show();
+
+ // clear the dialog
+ $('#enable-controller-service-id').text('');
+ $('#enable-controller-service-name').text('');
+
+ // reset progress
+ $('div.enable-referencing-components').removeClass('ajax-loading ajax-complete ajax-error');
+
+ // referencing components
+ var referencingComponents = $('#enable-controller-service-referencing-components');
+ nf.Common.cleanUpTooltips(referencingComponents, 'div.referencing-component-state');
+ referencingComponents.css('border-width', '0').empty();
+
+ // reset dialog
+ enableDialog.modal('setButtonModel', [{
+ buttonText: 'Enable',
+ handler: {
+ click: enableHandler
+ }
+ }, {
+ buttonText: 'Cancel',
+ handler: {
+ click: closeModal
+ }
+ }]);
+ }
+ }
+ }).draggable({
+ containment: 'parent',
+ handle: '.dialog-header'
+ });
+ },
+
+ /**
+ * Shows the configuration dialog for the specified controller service.
+ *
+ * @argument {object} controllerService The controller service
+ */
+ showConfiguration: function (controllerService) {
+ var controllerServiceDialog = $('#controller-service-configuration');
+ if (controllerServiceDialog.data('mode') === config.readOnly) {
+ // update the visibility
+ $('#controller-service-configuration .controller-service-read-only').hide();
+ $('#controller-service-configuration .controller-service-editable').show();
+
+ // initialize the property table
+ $('#controller-service-properties').propertytable('destroy').propertytable({
+ readOnly: false,
+ newPropertyDialogContainer: '#new-controller-service-property-container',
+ descriptorDeferred: getControllerServicePropertyDescriptor
+ });
+
+ // update the mode
+ controllerServiceDialog.data('mode', config.edit);
+ }
+
+ // reload the service in case the property descriptors have changed
+ var reloadService = $.ajax({
+ type: 'GET',
+ url: controllerService.uri,
+ dataType: 'json'
+ });
+
+ // get the controller service history
+ var loadHistory = $.ajax({
+ type: 'GET',
+ url: '../nifi-api/controller/history/controller-services/' + encodeURIComponent(controllerService.id),
+ dataType: 'json'
+ });
+
+ // once everything is loaded, show the dialog
+ $.when(reloadService, loadHistory).done(function (serviceResponse, historyResponse) {
+ // get the updated controller service
+ controllerService = serviceResponse[0].controllerService;
+
+ // get the controller service history
+ var controllerServiceHistory = historyResponse[0].componentHistory;
+
+ // record the controller service details
+ controllerServiceDialog.data('controllerServiceDetails', controllerService);
+
+ // determine if the enabled checkbox is checked or not
+ var controllerServiceEnableStyle = 'checkbox-checked';
+ if (controllerService['state'] === 'DISABLED') {
+ controllerServiceEnableStyle = 'checkbox-unchecked';
+ }
+
+ // populate the controller service settings
+ nf.Common.populateField('controller-service-id', controllerService['id']);
+ nf.Common.populateField('controller-service-type', nf.Common.substringAfterLast(controllerService['type'], '.'));
+ $('#controller-service-name').val(controllerService['name']);
+ $('#controller-service-enabled').removeClass('checkbox-checked checkbox-unchecked').addClass(controllerServiceEnableStyle);
+ $('#controller-service-comments').val(controllerService['comments']);
+
+ // select the availability when appropriate
+ if (nf.Canvas.isClustered()) {
+ if (controllerService['availability'] === 'node') {
+ $('#controller-service-availability').text('Node');
+ } else {
+ $('#controller-service-availability').text('Cluster Manager');
+ }
+ }
+
+ // get the reference container
+ var referenceContainer = $('#controller-service-referencing-components');
+
+ // load the controller referencing components list
+ createReferencingComponents(referenceContainer, controllerService.referencingComponents);
+
+ var buttons = [{
+ buttonText: 'Apply',
+ handler: {
+ click: function () {
+ // close all fields currently being edited
+ $('#controller-service-properties').propertytable('saveRow');
+
+ // marshal the settings and properties and update the controller service
+ var updatedControllerService = marshalDetails();
+
+ // ensure details are valid as far as we can tell
+ if (validateDetails(updatedControllerService)) {
+ var previouslyReferencedServiceIds = [];
+ $.each(identifyReferencedServiceDescriptors(controllerService), function (_, descriptor) {
+ var modifyingService = !nf.Common.isUndefined(updatedControllerService.controllerService.properties) && !nf.Common.isUndefined(updatedControllerService.controllerService.properties[descriptor.name]);
+ var isCurrentlyConfigured = nf.Common.isDefinedAndNotNull(controllerService.properties[descriptor.name]);
+
+ // if we are attempting to update a controller service reference
+ if (modifyingService && isCurrentlyConfigured) {
+ // record the current value if set
+ previouslyReferencedServiceIds.push(controllerService.properties[descriptor.name]);
+ }
+ });
+
+ // update the selected component
+ $.ajax({
+ type: 'PUT',
+ data: JSON.stringify(updatedControllerService),
+ url: controllerService.uri,
+ dataType: 'json',
+ processData: false,
+ contentType: 'application/json'
+ }).done(function (response) {
+ if (nf.Common.isDefinedAndNotNull(response.controllerService)) {
+ nf.Client.setRevision(response.revision);
+
+ // reload the controller service
+ renderControllerService(response.controllerService);
+ reloadControllerServiceReferences(response.controllerService);
+
+ // reload all previously referenced controller services
+ $.each(previouslyReferencedServiceIds, function(_, oldServiceReferenceId) {
+ reloadControllerService(oldServiceReferenceId);
+ });
+
+ // close the details panel
+ controllerServiceDialog.modal('hide');
+ }
+ }).fail(handleControllerServiceConfigurationError);
+ }
+ }
+ }
+ }, {
+ buttonText: 'Cancel',
+ handler: {
+ click: function () {
+ controllerServiceDialog.modal('hide');
+ }
+ }
+ }];
+
+ // determine if we should show the advanced button
+ if (nf.Common.isDefinedAndNotNull(controllerService.customUiUrl) && controllerService.customUiUrl !== '') {
+ buttons.push({
+ buttonText: 'Advanced',
+ handler: {
+ click: function () {
+ var openCustomUi = function () {
+ // reset state and close the dialog manually to avoid hiding the faded background
+ controllerServiceDialog.modal('hide');
+
+ // close the settings dialog since the custom ui is also opened in the shell
+ $('#shell-close-button').click();
+
+ // show the custom ui
+ nf.CustomUi.showCustomUi($('#controller-service-id').text(), controllerService.customUiUrl, true).done(function () {
+ // once the custom ui is closed, reload the controller service
+ reloadControllerServiceAndReferencingComponents(controllerService);
+
+ // show the settings
+ nf.Settings.showSettings();
+ });
+ };
+
+ // close all fields currently being edited
+ $('#controller-service-properties').propertytable('saveRow');
+
+ // determine if changes have been made
+ if (isSaveRequired()) {
+ // see if those changes should be saved
+ nf.Dialog.showYesNoDialog({
+ dialogContent: 'Save changes before opening the advanced configuration?',
+ overlayBackground: false,
+ noHandler: openCustomUi,
+ yesHandler: function () {
+ // marshal the settings and properties and update the controller service
+ var updatedControllerService = marshalDetails();
+
+ // ensure details are valid as far as we can tell
+ if (validateDetails(updatedControllerService)) {
+ var previouslyReferencedServiceIds = [];
+ $.each(identifyReferencedServiceDescriptors(controllerService), function (_, descriptor) {
+ var modifyingService = !nf.Common.isUndefined(updatedControllerService.controllerService.properties) && !nf.Common.isUndefined(updatedControllerService.controllerService.properties[descriptor.name]);
+ var isCurrentlyConfigured = nf.Common.isDefinedAndNotNull(controllerService.properties[descriptor.name]);
+
+ // if we are attempting to update a controller service reference
+ if (modifyingService && isCurrentlyConfigured) {
+
+ // record the current value if set
+ previouslyReferencedServiceIds.push(controllerService.properties[descriptor.name]);
+ }
+ });
+
+ // update the selected component
+ $.ajax({
+ type: 'PUT',
+ data: JSON.stringify(updatedControllerService),
+ url: controllerService.uri,
+ dataType: 'json',
+ processData: false,
+ contentType: 'application/json'
+ }).done(function (response) {
+ if (nf.Common.isDefinedAndNotNull(response.controllerService)) {
+ // update the revision
+ nf.Client.setRevision(response.revision);
+
+ // reload all previously referenced controller services
+ $.each(previouslyReferencedServiceIds, function(_, oldServiceReferenceId) {
+ reloadControllerService(oldServiceReferenceId);
+ });
+
+ // open the custom ui
+ openCustomUi();
+ }
+ }).fail(handleControllerServiceConfigurationError);
+ }
+ }
+ });
+ } else {
+ // if there were no changes, simply open the custom ui
+ openCustomUi();
+ }
+ }
+ }
+ });
+ }
+
+ // set the button model
+ controllerServiceDialog.modal('setButtonModel', buttons);
+
+ // load the property table
+ $('#controller-service-properties').propertytable('loadProperties', controllerService.properties, controllerService.descriptors, controllerServiceHistory.propertyHistory);
+
+ // show the details
+ controllerServiceDialog.modal('show');
+
+ // show the border if necessary
+ updateReferencingComponentsBorder(referenceContainer);
+ }).fail(nf.Common.handleAjaxError);
+ },
+
+ /**
+ * Shows the controller service details in a read only dialog.
+ *
+ * @param {object} controllerService
+ */
+ showDetails: function(controllerService) {
+ var controllerServiceDialog = $('#controller-service-configuration');
+ if (controllerServiceDialog.data('mode') === config.edit) {
+ // update the visibility
+ $('#controller-service-configuration .controller-service-read-only').show();
+ $('#controller-service-configuration .controller-service-editable').hide();
+
+ // initialize the property table
+ $('#controller-service-properties').propertytable('destroy').propertytable({
+ readOnly: true
+ });
+
+ // update the mode
+ controllerServiceDialog.data('mode', config.readOnly);
+ }
+
+ // reload the service in case the property descriptors have changed
+ var reloadService = $.ajax({
+ type: 'GET',
+ url: controllerService.uri,
+ dataType: 'json'
+ });
+
+ // get the controller service history
+ var loadHistory = $.ajax({
+ type: 'GET',
+ url: '../nifi-api/controller/history/controller-services/' + encodeURIComponent(controllerService.id),
+ dataType: 'json'
+ });
+
+ // once everything is loaded, show the dialog
+ $.when(reloadService, loadHistory).done(function (serviceResponse, historyResponse) {
+ // get the updated controller service
+ controllerService = serviceResponse[0].controllerService;
+
+ // get the controller service history
+ var controllerServiceHistory = historyResponse[0].componentHistory;
+
+ // record the controller service details
+ controllerServiceDialog.data('controllerServiceDetails', controllerService);
+
+ // populate the controller service settings
+ nf.Common.populateField('controller-service-id', controllerService['id']);
+ nf.Common.populateField('controller-service-type', nf.Common.substringAfterLast(controllerService['type'], '.'));
+ nf.Common.populateField('read-only-controller-service-name', controllerService['name']);
+ nf.Common.populateField('read-only-controller-service-comments', controllerService['comments']);
+
+ // select the availability when appropriate
+ if (nf.Canvas.isClustered()) {
+ if (controllerService['availability'] === 'node') {
+ $('#controller-service-availability').text('Node');
+ } else {
+ $('#controller-service-availability').text('Cluster Manager');
+ }
+ }
+
+ // get the reference container
+ var referenceContainer = $('#controller-service-referencing-components');
+
+ // load the controller referencing components list
+ createReferencingComponents(referenceContainer, controllerService.referencingComponents);
+
+ var buttons = [{
+ buttonText: 'Ok',
+ handler: {
+ click: function () {
+ // hide the dialog
+ controllerServiceDialog.modal('hide');
+ }
+ }
+ }];
+
+ // determine if we should show the advanced button
+ if (nf.Common.isDefinedAndNotNull(nf.CustomUi) && nf.Common.isDefinedAndNotNull(controllerService.customUiUrl) && controllerService.customUiUrl !== '') {
+ buttons.push({
+ buttonText: 'Advanced',
+ handler: {
+ click: function () {
+ // reset state and close the dialog manually to avoid hiding the faded background
+ controllerServiceDialog.modal('hide');
+
+ // close the settings dialog since the custom ui is also opened in the shell
+ $('#shell-close-button').click();
+
+ // show the custom ui
+ nf.CustomUi.showCustomUi(controllerService.id, controllerService.customUiUrl, false).done(function () {
+ nf.Settings.showSettings();
+ });
+ }
+ }
+ });
+ }
+
+ // show the dialog
+ controllerServiceDialog.modal('setButtonModel', buttons);
+
+ // load the property table
+ $('#controller-service-properties').propertytable('loadProperties', controllerService.properties, controllerService.descriptors, controllerServiceHistory.propertyHistory);
+
+ // show the details
+ controllerServiceDialog.modal('show');
+
+ // show the border if necessary
+ updateReferencingComponentsBorder(referenceContainer);
+ });
+ },
+
+ /**
+ * Enables the specified controller service.
+ *
+ * @param {object} controllerService
+ */
+ enable: function(controllerService) {
+ if (nf.Common.isEmpty(controllerService.referencingComponents)) {
+ setEnabled(controllerService, true).always(function () {
+ reloadControllerServiceAndReferencingComponents(controllerService);
+ });
+ } else {
+ showEnableControllerServiceDialog(controllerService);
+ }
+ },
+
+ /**
+ * Disables the specified controller service.
+ *
+ * @param {object} controllerService
+ */
+ disable: function(controllerService) {
+ if (nf.Common.isEmpty(controllerService.referencingComponents)) {
+ setEnabled(controllerService, false).always(function () {
+ reloadControllerServiceAndReferencingComponents(controllerService);
+ });
+ } else {
+ showDisableControllerServiceDialog(controllerService);
+ }
+ },
+
+ /**
+ * Reloads the services that the specified comonent references. This is
+ * necessary because the specified component state is reflected in the
+ * referenced service referencing components.
+ *
+ * @param {object} component
+ */
+ reloadReferencedServices: function(component) {
+ $.each(getReferencedServices(component), function (_, referencedServiceId) {
+ reloadControllerService(referencedServiceId);
+ });
+ },
+
+ /**
+ * Deletes the specified controller service.
+ *
+ * @param {object} controllerService
+ */
+ remove: function(controllerService) {
+ // prompt for removal?
+
+ var revision = nf.Client.getRevision();
+ $.ajax({
+ type: 'DELETE',
+ url: controllerService.uri + '?' + $.param({
+ version: revision.version,
+ clientId: revision.clientId
+ }),
+ dataType: 'json'
+ }).done(function (response) {
+ nf.Client.setRevision(response.revision);
+
+ // remove the service
+ var controllerServiceGrid = $('#controller-services-table').data('gridInstance');
+ var controllerServiceData = controllerServiceGrid.getData();
+ controllerServiceData.deleteItem(controllerService.id);
+
+ // reload the as necessary
+ reloadControllerServiceReferences(controllerService);
+ }).fail(nf.Common.handleAjaxError);
+ }
+ };
+}());
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e9647717/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-custom-processor-ui.js
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-custom-processor-ui.js b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-custom-processor-ui.js
deleted file mode 100644
index 7d98f40..0000000
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-custom-processor-ui.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.
- */
-nf.CustomProcessorUi = {
- /**
- * Shows the custom ui.
- *
- * @argument {string} processorId The processor id
- * @argument {string} uri The uri for the custom ui
- * @argument {boolean} editable Whether the custom ui should support editing
- */
- showCustomUi: function (processorId, uri, editable) {
-
- // record the processor id
- $('#shell-close-button');
-
- var revision = nf.Client.getRevision();
-
- // build the customer ui params
- var customUiParams = {
- 'processorId': processorId,
- 'revision': revision.version,
- 'clientId': revision.clientId,
- 'editable': editable
- };
-
- // show the shell
- return nf.Shell.showPage('..' + uri + '?' + $.param(customUiParams), false);
- }
-};
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e9647717/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-custom-ui.js
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-custom-ui.js b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-custom-ui.js
new file mode 100644
index 0000000..365831a
--- /dev/null
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-custom-ui.js
@@ -0,0 +1,47 @@
+/*
+ * 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 nf */
+
+nf.CustomUi = {
+ /**
+ * Shows the custom ui.
+ *
+ * @argument {string} id The component id
+ * @argument {string} uri The uri for the custom ui
+ * @argument {boolean} editable Whether the custom ui should support editing
+ */
+ showCustomUi: function (id, uri, editable) {
+
+ // record the processor id
+ $('#shell-close-button');
+
+ var revision = nf.Client.getRevision();
+
+ // build the customer ui params
+ var customUiParams = {
+ 'id': id,
+ 'processorId': id, // deprecated
+ 'revision': revision.version,
+ 'clientId': revision.clientId,
+ 'editable': editable
+ };
+
+ // show the shell
+ return nf.Shell.showPage('..' + uri + '?' + $.param(customUiParams), false);
+ }
+};
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e9647717/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-draggable.js
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-draggable.js b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-draggable.js
index 1858e60..d44f1ed 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-draggable.js
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-draggable.js
@@ -14,6 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+/* global nf, d3 */
+
nf.Draggable = (function () {
var drag;