blob: 13ce96f0af33a8d471c12a52c62a2246231873e2 [file] [log] [blame]
/*
* 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',
'd3',
'nf.ErrorHandler',
'nf.Common',
'nf.Dialog',
'nf.Storage',
'nf.Client',
'nf.ProcessGroup',
'nf.Shell',
'nf.CanvasUtils'],
function ($, d3, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfProcessGroup, nfShell, nfCanvasUtils) {
return (nf.ProcessGroupConfiguration = factory($, d3, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfProcessGroup, nfShell, nfCanvasUtils));
});
} else if (typeof exports === 'object' && typeof module === 'object') {
module.exports = (nf.ProcessGroupConfiguration =
factory(require('jquery'),
require('d3'),
require('nf.ErrorHandler'),
require('nf.Common'),
require('nf.Dialog'),
require('nf.Storage'),
require('nf.Client'),
require('nf.ProcessGroup'),
require('nf.Shell'),
require('nf.CanvasUtils')));
} else {
nf.ProcessGroupConfiguration = factory(root.$,
root.d3,
root.nf.ErrorHandler,
root.nf.Common,
root.nf.Dialog,
root.nf.Storage,
root.nf.Client,
root.nf.ProcessGroup,
root.nf.Shell,
root.nf.CanvasUtils);
}
}(this, function ($, d3, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfProcessGroup, nfShell, nfCanvasUtils) {
'use strict';
var nfControllerServices;
var nfParameterContexts;
var nfBackpressureDefaults;
var config = {
urls: {
api: '../nifi-api',
parameterContexts: '../nifi-api/flow/parameter-contexts'
}
};
/**
* Initializes the general tab.
*/
var initGeneral = function () {
};
/**
* Gets the controller services table.
*
* @returns {*|jQuery|HTMLElement}
*/
var getControllerServicesTable = function () {
return $('#process-group-controller-services-table');
};
/**
* Saves the configuration for the specified group.
*
* @param version
* @param groupId
*/
var saveConfiguration = function (version, groupId) {
// build the entity
var entity = {
'revision': nfClient.getRevision({
'revision': {
'version': version
}
}),
'disconnectedNodeAcknowledged': nfStorage.isDisconnectionAcknowledged(),
'component': {
'id': groupId,
'name': $('#process-group-name').val(),
'comments': $('#process-group-comments').val(),
'parameterContext': {
'id': $('#process-group-parameter-context-combo').combo('getSelectedOption').value
},
'flowfileConcurrency': $('#process-group-flowfile-concurrency-combo').combo('getSelectedOption').value,
'flowfileOutboundPolicy': $('#process-group-outbound-policy-combo').combo('getSelectedOption').value,
'defaultFlowFileExpiration': $('#process-group-default-flowfile-expiration').val(),
'defaultBackPressureObjectThreshold': $('#process-group-default-back-pressure-object-threshold').val(),
'defaultBackPressureDataSizeThreshold': $('#process-group-default-back-pressure-data-size-threshold').val()
}
};
// update the selected component
$.ajax({
type: 'PUT',
data: JSON.stringify(entity),
url: config.urls.api + '/process-groups/' + encodeURIComponent(groupId),
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// refresh the process group if necessary
if (response.permissions.canRead && response.component.parentGroupId === nfCanvasUtils.getGroupId()) {
nfProcessGroup.set(response);
}
// show the result dialog
nfDialog.showOkDialog({
headerText: 'Process Group Configuration',
dialogContent: 'Process group configuration successfully saved.'
});
// update the click listener for the updated revision
$('#process-group-configuration-save').off('click').on('click', function () {
saveConfiguration(response.revision.version, groupId);
});
var controllerServicesUri = config.urls.api + '/flow/process-groups/' + encodeURIComponent(groupId) + '/controller-services';
$.ajax({
type: 'GET',
url: controllerServicesUri,
dataType: 'json'
}).done(function (response) {
var serviceTable = getControllerServicesTable();
nfCommon.cleanUpTooltips(serviceTable, 'div.has-errors');
var controllerServicesGrid = serviceTable.data('gridInstance');
var controllerServicesData = controllerServicesGrid.getData();
$.each(response.controllerServices, function (_, controllerServiceEntity) {
controllerServicesData.updateItem(controllerServiceEntity.id, controllerServiceEntity);
});
});
nfCanvasUtils.reload();
}).fail(nfErrorHandler.handleConfigurationUpdateAjaxError);
};
/**
* Loads the configuration for the specified process group.
*
* @param {string} groupId
*/
var loadConfiguration = function (groupId) {
var setUnauthorizedText = function () {
$('#read-only-process-group-name').text('Unauthorized');
$('#read-only-process-group-comments').text('Unauthorized');
$('#read-only-process-group-default-flowfile-expiration').text('Unauthorized');
$('#read-only-process-group-default-back-pressure-object-threshold').text('Unauthorized');
$('#read-only-process-group-default-back-pressure-data-size-threshold').text('Unauthorized');
};
var setEditable = function (editable) {
if (editable) {
$('#process-group-configuration div.editable').show();
$('#process-group-configuration div.read-only').hide();
$('#process-group-configuration-save').show();
} else {
$('#process-group-configuration div.editable').hide();
$('#process-group-configuration div.read-only').show();
$('#process-group-configuration-save').hide();
}
};
// record the group id
$('#process-group-id').text(groupId);
// update the click listener
$('#process-group-configuration-refresh-button').off('click').on('click', function () {
loadConfiguration(groupId);
});
// update the new controller service click listener
$('#add-process-group-configuration-controller-service').off('click').on('click', function () {
var selectedTab = $('#process-group-configuration-tabs li.selected-tab').text();
if (selectedTab === 'Controller Services') {
var controllerServicesUri = config.urls.api + '/process-groups/' + encodeURIComponent(groupId) + '/controller-services';
nfControllerServices.promptNewControllerService(controllerServicesUri, getControllerServicesTable());
}
});
var processGroup = $.Deferred(function (deferred) {
$.ajax({
type: 'GET',
url: config.urls.api + '/process-groups/' + encodeURIComponent(groupId),
dataType: 'json'
}).done(function (response) {
// store the process group
$('#process-group-configuration').data('process-group', response);
var processGroup = response.component;
if (response.permissions.canWrite) {
// populate the process group settings
$('#process-group-name').removeClass('unset').val(processGroup.name);
$('#process-group-comments').removeClass('unset').val(processGroup.comments);
$('#process-group-flowfile-concurrency-combo').removeClass('unset').combo({
options: [{
text: 'Single FlowFile Per Node',
value: 'SINGLE_FLOWFILE_PER_NODE',
description: 'Only a single FlowFile is to be allowed to enter the Process Group at a time on each node in the cluster. While that FlowFile may be split into many or '
+ 'spawn many children, no additional FlowFiles will be allowed to enter the Process Group through a Local Input Port until the previous FlowFile '
+ '- and all of its child/descendent FlowFiles - have been processed.'
}, {
text: 'Single Batch Per Node',
value: "SINGLE_BATCH_PER_NODE",
description: 'When an Input Port pulls a FlowFile into the Process Group, FlowFiles will continue to be ingested into the Process Group until all input queues '
+ 'have been emptied. At that point, no additional FlowFiles will be allowed to enter the Process Group through a Local Input Port until the entire batch '
+ 'of FlowFiles has been processed.'
},{
text: 'Unbounded',
value: 'UNBOUNDED',
description: 'The number of FlowFiles that can be processed concurrently is unbounded.'
}],
selectedOption: {
value: processGroup.flowfileConcurrency
}
});
$('#process-group-outbound-policy-combo').removeClass('unset').combo({
options: [{
text: 'Stream When Available',
value: 'STREAM_WHEN_AVAILABLE',
description: 'FlowFiles that are queued up to be transferred out of a Process Group by an Output Port will be transferred out '
+ 'of the Process Group as soon as they are available.'
}, {
text: 'Batch Output',
value: 'BATCH_OUTPUT',
description: 'FlowFiles that are queued up to be transferred out of a Process Group by an Output Port will remain queued until '
+ 'all FlowFiles in the Process Group are ready to be transferred out of the group. The FlowFiles will then be transferred '
+ 'out of the group. This setting will be ignored if the FlowFile Concurrency is Unbounded.'
}],
selectedOption: {
value: processGroup.flowfileOutboundPolicy
}
});
$('#process-group-default-flowfile-expiration').removeClass('unset').val(processGroup.defaultFlowFileExpiration);
$('#process-group-default-back-pressure-object-threshold').removeClass('unset').val(processGroup.defaultBackPressureObjectThreshold);
$('#process-group-default-back-pressure-data-size-threshold').removeClass('unset').val(processGroup.defaultBackPressureDataSizeThreshold);
// populate the header
$('#process-group-configuration-header-text').text(processGroup.name + ' Configuration');
setEditable(true);
// register the click listener for the save button
$('#process-group-configuration-save').off('click').on('click', function () {
saveConfiguration(response.revision.version, response.id);
});
} else {
if (response.permissions.canRead) {
// populate the process group settings
$('#read-only-process-group-name').text(processGroup.name);
$('#read-only-process-group-comments').text(processGroup.comments);
// Determine the user-friendly name for the selected FlowFile Concurrency
var concurrencyName;
if (processGroup.flowfileConcurrency == "UNBOUNDED") {
concurrencyName = "Unbounded";
} else if (processGroup.flowfileConcurrency == "SINGLE_FLOWFILE_PER_NODE") {
concurrencyName = "Single FlowFile Per Node";
} else if (processGroup.flowfileConcurrency == "SINGLE_BATCH_PER_NODE") {
concurrencyName = "Single Batch Per Node";
} else {
concurrencyName = "Unknown";
}
$('#read-only-process-group-flowfile-concurrency').text(concurrencyName);
var outboundPolicyName = processGroup.flowfileOutboundPolicy == "BATCH_OUTPUT" ? "Batch Output" : "Stream When Available";
$('#read-only-process-group-outbound-policy').text(outboundPolicyName);
// populate the header
$('#process-group-configuration-header-text').text(processGroup.name + ' Configuration');
// backpressure settings
$('#process-group-default-flowfile-expiration').text(processGroup.defaultFlowFileExpiration);
$('#process-group-default-back-pressure-object-threshold').text(processGroup.defaultBackPressureObjectThreshold);
$('#process-group-default-back-pressure-data-size-threshold').text(processGroup.defaultBackPressureDataSizeThreshold);
$('#read-only-process-group-default-flowfile-expiration').text(processGroup.defaultFlowFileExpiration);
$('#read-only-process-group-default-back-pressure-object-threshold').text(processGroup.defaultBackPressureObjectThreshold);
$('#read-only-process-group-default-back-pressure-data-size-threshold').text(processGroup.defaultBackPressureDataSizeThreshold);
} else {
setUnauthorizedText();
}
setEditable(false);
}
deferred.resolve(response);
}).fail(function (xhr, status, error) {
if (xhr.status === 403) {
var unauthorizedGroup;
if (groupId === nfCanvasUtils.getGroupId()) {
unauthorizedGroup = {
'permissions': {
canRead: false,
canWrite: nfCanvasUtils.canWriteCurrentGroup()
}
};
} else {
unauthorizedGroup = nfProcessGroup.get(groupId);
}
$('#process-group-configuration').data('process-group', unauthorizedGroup);
setUnauthorizedText();
setEditable(false);
deferred.resolve(unauthorizedGroup);
} else {
deferred.reject(xhr, status, error);
}
});
}).promise();
// load the controller services
var controllerServicesUri = config.urls.api + '/flow/process-groups/' + encodeURIComponent(groupId) + '/controller-services';
var controllerServices = nfControllerServices.loadControllerServices(controllerServicesUri, getControllerServicesTable());
var parameterContexts = $.ajax({
type: 'GET',
url: config.urls.parameterContexts,
dataType: 'json'
});
// wait for everything to complete
return $.when(processGroup, controllerServices, parameterContexts).done(function (processGroupResult, controllerServicesResult, parameterContextsResult) {
var controllerServicesResponse = controllerServicesResult[0];
var parameterContextsResponse = parameterContextsResult[0];
// update the current time
$('#process-group-configuration-last-refreshed').text(controllerServicesResponse.currentTime);
var parameterContexts = parameterContextsResponse.parameterContexts;
var options = [{
text: 'No parameter context',
value: null
}];
var authorizedParameterContexts = parameterContexts.filter(function (parameterContext) {
return parameterContext.permissions.canRead;
});
var unauthorizedParameterContexts = parameterContexts.filter(function (parameterContext) {
return !parameterContext.permissions.canRead;
});
//sort alphabetically
var sortedAuthorizedParameterContexts = authorizedParameterContexts.sort(function (a, b) {
if (a.component.name < b.component.name) {
return -1;
}
if (a.component.name > b.component.name) {
return 1;
}
return 0;
});
//sort alphabetically
var sortedUnauthorizedParameterContexts = unauthorizedParameterContexts.sort(function (a, b) {
if (a.id < b.id) {
return -1;
}
if (a.id > b.id) {
return 1;
}
return 0;
});
var sortedParameterContexts = sortedAuthorizedParameterContexts.concat(sortedUnauthorizedParameterContexts);
sortedParameterContexts.forEach(function (parameterContext) {
var option;
if (parameterContext.permissions.canRead) {
option = {
'text': parameterContext.component.name,
'value': parameterContext.id,
'description': parameterContext.component.description
};
} else {
option = {
'disabled': true,
'text': parameterContext.id,
'value': parameterContext.id
}
}
options.push(option);
});
var createNewParameterContextOption = {
text: 'Create new parameter context...',
value: undefined,
optionClass: 'unset'
};
if (nfCommon.canModifyParameterContexts()) {
options.push(createNewParameterContextOption);
}
var comboOptions = {
options: options,
select: function (option) {
var combo = this;
if (typeof option.value === 'undefined') {
$('#parameter-context-dialog').modal('setHeaderText', 'Add Parameter Context').modal('setButtonModel', [{
buttonText: 'Apply',
color: {
base: '#728E9B',
hover: '#004849',
text: '#ffffff'
},
disabled: function () {
if ($('#parameter-context-name').val() !== '') {
return false;
}
return true;
},
handler: {
click: function () {
nfParameterContexts.addParameterContext(function (parameterContextEntity) {
options.pop();
var option = {
'text': parameterContextEntity.component.name,
'value': parameterContextEntity.component.id,
'description': parameterContextEntity.component.description
};
options.push(option);
if (nfCommon.canModifyParameterContexts()) {
options.push(createNewParameterContextOption);
}
comboOptions.selectedOption = {
value: parameterContextEntity.component.id
};
combo.combo('destroy').combo(comboOptions);
});
}
}
}, {
buttonText: 'Cancel',
color: {
base: '#E3E8EB',
hover: '#C7D2D7',
text: '#004849'
},
handler: {
click: function () {
$(this).modal('hide');
}
}
}]).modal('show');
// make sure the edit mode is properly set
if ($('#parameter-context-dialog').hasClass('read-only')) {
$('#parameter-context-dialog').removeClass('read-only');
$('#parameter-context-dialog').addClass('edit-mode');
}
// there is no id yet, make sure the id field isn't shown
if (!$('#parameter-context-id-setting').hasClass('hidden')) {
$('#parameter-context-id-setting').addClass('hidden');
}
// set the initial focus
$('#parameter-context-name').focus();
}
}
};
// populate the parameter context
if (nfCommon.isDefinedAndNotNull(processGroupResult.parameterContext)) {
comboOptions.selectedOption = {
value: processGroupResult.parameterContext.id
};
}
// initialize the parameter context combo
$('#process-group-parameter-context-combo').combo('destroy').combo(comboOptions);
}).fail(nfErrorHandler.handleAjaxError);
};
/**
* Shows the process group configuration.
*/
var showConfiguration = function () {
// show the configuration dialog
nfShell.showContent('#process-group-configuration').done(function () {
reset();
});
//reset content to account for possible policy changes
$('#process-group-configuration-tabs').find('.selected-tab').click();
// adjust the table size
nfProcessGroupConfiguration.resetTableSize();
};
/**
* Resets the process group configuration dialog.
*/
var reset = function () {
$('#process-group-configuration').removeData('process-group');
// reset button state
$('#process-group-configuration-save').mouseout();
// reset the fields
$('#process-group-id').text('');
$('#process-group-name').val('');
$('#process-group-comments').val('');
$('#process-group-default-flowfile-expiration').val('');
$('#process-group-default-back-pressure-object-threshold').val('');
$('#process-group-default-back-pressure-data-size-threshold').val('');
// reset the header
$('#process-group-configuration-header-text').text('Process Group Configuration');
};
var nfProcessGroupConfiguration = {
/**
* Initialize the process group configuration.
*
* @param nfControllerServicesRef The nfControllerServices module.
* @param nfParameterContextsRef The nfParameterContexts module.
*/
init: function (nfControllerServicesRef, nfParameterContextsRef) {
nfControllerServices = nfControllerServicesRef;
nfParameterContexts = nfParameterContextsRef;
// initialize the process group configuration tabs
$('#process-group-configuration-tabs').tabbs({
tabStyle: 'tab',
selectedTabStyle: 'selected-tab',
scrollableTabContentStyle: 'scrollable',
tabs: [{
name: 'General',
tabContentId: 'general-process-group-configuration-tab-content'
}, {
name: 'Controller Services',
tabContentId: 'process-group-controller-services-tab-content'
}],
select: function () {
var processGroup = $('#process-group-configuration').data('process-group');
var canWrite = nfCommon.isDefinedAndNotNull(processGroup) ? processGroup.permissions.canWrite : false;
var tab = $(this).text();
if (tab === 'General') {
$('#flow-cs-availability').hide();
$('#add-process-group-configuration-controller-service').hide();
if (canWrite) {
$('#process-group-configuration-save').show();
} else {
$('#process-group-configuration-save').hide();
}
} else {
$('#flow-cs-availability').show();
$('#process-group-configuration-save').hide();
if (canWrite) {
$('#add-process-group-configuration-controller-service').show();
$('#process-group-controller-services-tab-content').css('top', '32px');
} else {
$('#add-process-group-configuration-controller-service').hide();
$('#process-group-controller-services-tab-content').css('top', '0');
}
// resize the table
nfProcessGroupConfiguration.resetTableSize();
}
}
});
// initialize each tab
initGeneral();
nfControllerServices.init(getControllerServicesTable());
},
/**
* Update the size of the grid based on its container's current size.
*/
resetTableSize: function () {
nfControllerServices.resetTableSize(getControllerServicesTable());
},
/**
* Shows the settings dialog.
*/
showConfiguration: function (groupId) {
return loadConfiguration(groupId).done(showConfiguration);
},
/**
* Loads the configuration for the specified process group.
*
* @param groupId
*/
loadConfiguration: function (groupId) {
return loadConfiguration(groupId);
},
/**
* Selects the specified controller service.
*
* @param {string} controllerServiceId
*/
selectControllerService: function (controllerServiceId) {
var controllerServiceGrid = getControllerServicesTable().data('gridInstance');
var controllerServiceData = controllerServiceGrid.getData();
// select the desired service
var row = controllerServiceData.getRowById(controllerServiceId);
controllerServiceGrid.setSelectedRows([row]);
controllerServiceGrid.scrollRowIntoView(row);
// select the controller services tab
$('#process-group-configuration-tabs').find('li:eq(1)').click();
}
};
return nfProcessGroupConfiguration;
}));