http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-component-version.js ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-component-version.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-component-version.js new file mode 100644 index 0000000..2100649 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-component-version.js @@ -0,0 +1,341 @@ +/* + * 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 */ + +/** + * Views state for a given component. + */ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + define(['jquery', + 'nf.ErrorHandler', + 'nf.Common', + 'nf.Client', + 'nf.CanvasUtils', + 'nf.ProcessGroupConfiguration', + 'nf.ng.Bridge'], + function ($, Slick, nfErrorHandler, nfCommon, nfClient, nfCanvasUtils, nfProcessGroupConfiguration, nfNgBridge) { + return (nf.ComponentState = factory($, nfErrorHandler, nfCommon, nfClient, nfCanvasUtils, nfProcessGroupConfiguration, nfNgBridge)); + }); + } else if (typeof exports === 'object' && typeof module === 'object') { + module.exports = (nf.ComponentState = + factory(require('jquery'), + require('nf.ErrorHandler'), + require('nf.Common', + require('nf.Client'), + require('nf.CanvasUtils'), + require('nf.ProcessGroupConfiguration'), + require('nf.ng.Bridge')))); + } else { + nf.ComponentVersion = factory(root.$, + root.nf.ErrorHandler, + root.nf.Common, + root.nf.Client, + root.nf.CanvasUtils, + root.nf.ProcessGroupConfiguration, + root.nf.ng.Bridge); + } +}(this, function ($, nfErrorHandler, nfCommon, nfClient, nfCanvasUtils, nfProcessGroupConfiguration, nfNgBridge) { + 'use strict'; + + var versionMap; + var nfSettings; + + /** + * Gets the URI for retrieving available types/bundles + * + * @param {object} componentEntity + * @returns {string} uri + */ + var getTypeUri = function (componentEntity) { + if (componentEntity.type === 'ReportingTask') { + return '../nifi-api/flow/reporting-task-types'; + } else if (componentEntity.type === 'ControllerService') { + return '../nifi-api/flow/controller-service-types'; + } else { + return '../nifi-api/flow/processor-types'; + } + }; + + /** + * Gets the field to use to access the returned types/bundles. + * + * @param {object} componentEntity + * @returns {string} field + */ + var getTypeField = function (componentEntity) { + if (componentEntity.type === 'ReportingTask') { + return 'reportingTaskTypes'; + } else if (componentEntity.type === 'ControllerService') { + return 'controllerServiceTypes'; + } else { + return 'processorTypes'; + } + }; + + /** + * Reset the dialog. + */ + var resetDialog = function () { + // clear the versions + var versions = versionMap.keys(); + $.each(versions, function (_, version) { + versionMap.remove(version); + }); + + // clear the service apis + $('#component-version-controller-service-apis').empty(); + $('#component-version-controller-service-apis-container').hide(); + + // clear the fields + $('#component-version-name').text(''); + $('#component-version-bundle').text(''); + $('#component-version-tags').text(''); + $('#component-version-restriction').removeClass('unset').text(''); + $('#component-version-description').text(''); + + // destroy the version combo + $('#component-version-selector').combo('destroy'); + + // removed the stored data + $('#component-version-dialog').removeData('component'); + }; + + /** + * Sets the specified option. + * + * @param {object} selectedOption + */ + var select = function (selectedOption) { + var documentedType = versionMap.get(selectedOption.value); + + // set any restriction + if (nfCommon.isDefinedAndNotNull(documentedType.usageRestriction)) { + $('#component-version-restriction').text(documentedType.usageRestriction); + } else { + $('#component-version-restriction').addClass('unset').text('No restriction'); + } + + // update the service apis if necessary + if (!nfCommon.isEmpty(documentedType.controllerServiceApis)) { + var formattedControllerServiceApis = nfCommon.getFormattedServiceApis(documentedType.controllerServiceApis); + var serviceTips = nfCommon.formatUnorderedList(formattedControllerServiceApis); + $('#component-version-controller-service-apis').empty().append(serviceTips); + $('#component-version-controller-service-apis-container').show(); + } + + // update the tags and description + $('#component-version-tags').text(documentedType.tags.join(', ')); + $('#component-version-description').text(documentedType.description); + }; + + return { + init: function (settings) { + versionMap = d3.map(); + nfSettings = settings; + + // initialize the component version dialog + $('#component-version-dialog').modal({ + scrollableContentStyle: 'scrollable', + headerText: 'Component Version', + buttons: [{ + buttonText: 'Apply', + color: { + base: '#728E9B', + hover: '#004849', + text: '#ffffff' + }, + handler: { + click: function () { + // get the selected version + var selectedOption = $('#component-version-selector').combo('getSelectedOption'); + var documentedType = versionMap.get(selectedOption.value); + + // get the current component + var componentEntity = $('#component-version-dialog').data('component'); + + // build the request entity + var requestEntity = { + 'revision': nfClient.getRevision(componentEntity), + 'component': { + 'id': componentEntity.id, + 'bundle': { + 'group': documentedType.bundle.group, + 'artifact': documentedType.bundle.artifact, + 'version': documentedType.bundle.version + } + } + }; + + // save the bundle + $.ajax({ + type: 'PUT', + url: componentEntity.uri, + data: JSON.stringify(requestEntity), + dataType: 'json', + contentType: 'application/json' + }).done(function (response) { + // set the response + if (componentEntity.type === 'Processor') { + // update the processor + nfCanvasUtils.getComponentByType(componentEntity.type).set(response); + + // inform Angular app values have changed + nfNgBridge.digest(); + } else if (componentEntity.type === 'ControllerService') { + var parentGroupId = componentEntity.component.parentGroupId; + + $.Deferred(function (deferred) { + if (nfCommon.isDefinedAndNotNull(parentGroupId)) { + if ($('#process-group-configuration').is(':visible')) { + nfProcessGroupConfiguration.loadConfiguration(parentGroupId).done(function () { + deferred.resolve(); + }); + } else { + nfProcessGroupConfiguration.showConfiguration(parentGroupId).done(function () { + deferred.resolve(); + }); + } + } else { + if ($('#settings').is(':visible')) { + // reload the settings + nfSettings.loadSettings().done(function () { + deferred.resolve(); + }); + } else { + // reload the settings and show + nfSettings.showSettings().done(function () { + deferred.resolve(); + }); + } + } + }).done(function () { + if (nfCommon.isDefinedAndNotNull(parentGroupId)) { + nfProcessGroupConfiguration.selectControllerService(componentEntity.id); + } else { + nfSettings.selectControllerService(componentEntity.id); + } + }); + } else if (componentEntity.type === 'ReportingTask') { + $.Deferred(function (deferred) { + if ($('#settings').is(':visible')) { + // reload the settings + nfSettings.loadSettings().done(function () { + deferred.resolve(); + }); + } else { + // reload the settings and show + nfSettings.showSettings().done(function () { + deferred.resolve(); + }); + } + }).done(function () { + nfSettings.selectReportingTask(componentEntity.id); + }); + } + }).fail(nfErrorHandler.handleAjaxError); + + // reset and hide the dialog + this.modal('hide'); + } + } + }, + { + buttonText: 'Cancel', + color: { + base: '#E3E8EB', + hover: '#C7D2D7', + text: '#004849' + }, + handler: { + click: function () { + this.modal('hide'); + } + } + }], + handler: { + close: function () { + resetDialog(); + } + } + }); + }, + + /** + * Prompts to change the version of a component. + * + * @param {object} componentEntity + */ + promptForVersionChange: function (componentEntity) { + return $.ajax({ + type: 'GET', + url: getTypeUri(componentEntity) + '?' + $.param({ + 'bundleGroupFilter': componentEntity.component.bundle.group, + 'bundleArtifactFilter': componentEntity.component.bundle.artifact, + 'typeFilter': componentEntity.component.type + }), + dataType: 'json' + }).done(function (response) { + var options = []; + var selectedOption; + + // go through each type + $.each(response[getTypeField(componentEntity)], function (i, documentedType) { + var type = documentedType.type; + + // store the documented type + versionMap.set(documentedType.bundle.version, documentedType); + + // create the option + var option = { + text: documentedType.bundle.version, + value: documentedType.bundle.version, + description: nfCommon.escapeHtml(documentedType.description) + }; + + // record the currently selected option + if (documentedType.bundle.version === componentEntity.component.bundle.version) { + selectedOption = option; + } + + // store this option + options.push(option); + }); + + // sort the text version visible to the user + options.sort(function (a, b) { + return -nfCommon.sortVersion(a.text, b.text); + }); + + // populate the name/description + $('#component-version-name').text(componentEntity.component.name); + $('#component-version-bundle').text(nfCommon.formatBundle(componentEntity.component.bundle)); + + // build the combo + $('#component-version-selector').combo({ + options: options, + selectedOption: selectedOption, + select: select + }); + + // show the dialog + $('#component-version-dialog').data('component', componentEntity).modal('show'); + }).fail(nfErrorHandler.handleAjaxError); + } + }; +})); \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-context-menu.js ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-context-menu.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-context-menu.js index 4013167..1c16626 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-context-menu.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-context-menu.js @@ -325,6 +325,28 @@ }; /** + * Determines whether the current selection is a processor with more than one version. + * + * @param {selection} selection + */ + var canChangeProcessorVersion = function (selection) { + // ensure the correct number of components are selected + if (selection.size() !== 1) { + return false; + } + if (nfCanvasUtils.canRead(selection) === false || nfCanvasUtils.canModify(selection) === false) { + return false; + } + + if (nfCanvasUtils.isProcessor(selection)) { + var processorData = selection.datum(); + return processorData.component.multipleVersionsAvailable === true; + } else { + return false; + } + }; + + /** * Determines whether the current selection is a process group. * * @param {selection} selection @@ -513,6 +535,7 @@ {condition: supportsStats, menuItem: {clazz: 'fa fa-area-chart', text: 'Status History', action: 'showStats'}}, {condition: canAccessProvenance, menuItem: {clazz: 'icon icon-provenance', imgStyle: 'context-menu-provenance', text: 'Data provenance', action: 'openProvenance'}}, {condition: isStatefulProcessor, menuItem: {clazz: 'fa fa-tasks', text: 'View state', action: 'viewState'}}, + {condition: canChangeProcessorVersion, menuItem: {clazz: 'fa fa-exchange', text: 'Change version', action: 'changeVersion'}}, {condition: canMoveToFront, menuItem: {clazz: 'fa fa-clone', text: 'Bring to front', action: 'toFront'}}, {condition: isConnection, menuItem: {clazz: 'fa fa-long-arrow-left', text: 'Go to source', action: 'showSource'}}, {condition: isConnection, menuItem: {clazz: 'fa fa-long-arrow-right', text: 'Go to destination', action: 'showDestination'}}, @@ -530,8 +553,8 @@ {condition: canEmptyQueue, menuItem: {clazz: 'fa fa-minus-circle', text: 'Empty queue', action: 'emptyQueue'}}, {condition: isDeletable, menuItem: {clazz: 'fa fa-trash', text: 'Delete', action: 'delete'}}, {condition: canManagePolicies, menuItem: {clazz: 'fa fa-key', text: 'Access policies', action: 'managePolicies'}}, - {condition: canAlign, menuItem: {clazz: 'fa fa-align-center', text: 'Align vertical', action: 'alignVertical'}}, - {condition: canAlign, menuItem: { clazz: 'fa fa-align-center fa-rotate-90', text: 'Align horizontal', action: 'alignHorizontal'}}, + {condition: canAlign, menuItem: {clazz: 'fa fa-align-center', text: 'Align vertically', action: 'alignVertical'}}, + {condition: canAlign, menuItem: { clazz: 'fa fa-align-center fa-rotate-90', text: 'Align horizontally', action: 'alignHorizontal'}}, {condition: canUploadTemplate, menuItem: {clazz: 'icon icon-template-import', text: 'Upload template', action: 'uploadTemplate'}}, {condition: canCreateTemplate, menuItem: {clazz: 'icon icon-template-save', text: 'Create template', action: 'template'}} ]; http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/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-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-service.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-service.js index 2bbc8c2..5acd3ca 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-service.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-service.js @@ -204,6 +204,7 @@ var controllerServiceData = controllerServiceGrid.getData(); var currentControllerServiceEntity = controllerServiceData.getItemById(controllerServiceEntity.id); controllerServiceData.updateItem(controllerServiceEntity.id, $.extend({ + type: 'ControllerService', bulletins: currentControllerServiceEntity.bulletins }, controllerServiceEntity)); }; @@ -1679,6 +1680,9 @@ // clear the comments nfCommon.clearField('read-only-controller-service-comments'); + // clear the compatible apis + $('#controller-service-compatible-apis').empty(); + // removed the cached controller service details $('#controller-service-configuration').removeData('controllerServiceDetails'); }, @@ -1844,10 +1848,20 @@ // populate the controller service settings nfCommon.populateField('controller-service-id', controllerService['id']); - nfCommon.populateField('controller-service-type', nfCommon.substringAfterLast(controllerService['type'], '.')); + nfCommon.populateField('controller-service-type', nfCommon.formatType(controllerService)); + nfCommon.populateField('controller-service-bundle', nfCommon.formatBundle(controllerService['bundle'])); $('#controller-service-name').val(controllerService['name']); $('#controller-service-comments').val(controllerService['comments']); + // set the implemented apis + if (!nfCommon.isEmpty(controllerService['controllerServiceApis'])) { + var formattedControllerServiceApis = nfCommon.getFormattedServiceApis(controllerService['controllerServiceApis']); + var serviceTips = nfCommon.formatUnorderedList(formattedControllerServiceApis); + $('#controller-service-compatible-apis').append(serviceTips); + } else { + $('#controller-service-compatible-apis').append('<span class="unset">None</span>'); + } + // get the reference container var referenceContainer = $('#controller-service-referencing-components'); @@ -2013,10 +2027,20 @@ // populate the controller service settings nfCommon.populateField('controller-service-id', controllerService['id']); - nfCommon.populateField('controller-service-type', nfCommon.substringAfterLast(controllerService['type'], '.')); + nfCommon.populateField('controller-service-type', nfCommon.formatType(controllerService)); + nfCommon.populateField('controller-service-bundle', nfCommon.formatBundle(controllerService['bundle'])); nfCommon.populateField('read-only-controller-service-name', controllerService['name']); nfCommon.populateField('read-only-controller-service-comments', controllerService['comments']); + // set the implemented apis + if (!nfCommon.isEmpty(controllerService['controllerServiceApis'])) { + var formattedControllerServiceApis = nfCommon.getFormattedServiceApis(controllerService['controllerServiceApis']); + var serviceTips = nfCommon.formatUnorderedList(formattedControllerServiceApis); + $('#controller-service-compatible-apis').append(serviceTips); + } else { + $('#controller-service-compatible-apis').append('<span class="unset">None</span>'); + } + // get the reference container var referenceContainer = $('#controller-service-referencing-components'); http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js index 9f1a26d..427ef35 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js @@ -33,9 +33,10 @@ 'nf.ProcessGroup', 'nf.PolicyManagement', 'nf.ComponentState', + 'nf.ComponentVersion', 'nf.ng.Bridge'], - function ($, d3, Slick, nfClient, nfShell, nfProcessGroupConfiguration, nfCanvasUtils, nfErrorHandler, nfDialog, nfCommon, nfControllerService, nfProcessGroup, nfPolicyManagement, nfComponentState, nfNgBridge) { - return (nf.ControllerServices = factory($, d3, Slick, nfClient, nfShell, nfProcessGroupConfiguration, nfCanvasUtils, nfErrorHandler, nfDialog, nfCommon, nfControllerService, nfProcessGroup, nfPolicyManagement, nfComponentState, nfNgBridge)); + function ($, d3, Slick, nfClient, nfShell, nfProcessGroupConfiguration, nfCanvasUtils, nfErrorHandler, nfDialog, nfCommon, nfControllerService, nfProcessGroup, nfPolicyManagement, nfComponentState, nfComponentVersion, nfNgBridge) { + return (nf.ControllerServices = factory($, d3, Slick, nfClient, nfShell, nfProcessGroupConfiguration, nfCanvasUtils, nfErrorHandler, nfDialog, nfCommon, nfControllerService, nfProcessGroup, nfPolicyManagement, nfComponentState, nfComponentVersion, nfNgBridge)); }); } else if (typeof exports === 'object' && typeof module === 'object') { module.exports = (nf.ControllerServices = @@ -53,6 +54,7 @@ require('nf.ProcessGroup'), require('nf.PolicyManagement'), require('nf.ComponentState'), + require('nf.ComponentVersion'), require('nf.ng.Bridge'))); } else { nf.ControllerServices = factory(root.$, @@ -69,9 +71,10 @@ root.nf.ProcessGroup, root.nf.PolicyManagement, root.nf.ComponentState, + root.nf.ComponentVersion, root.nf.ng.Bridge); } -}(this, function ($, d3, Slick, nfClient, nfShell, nfProcessGroupConfiguration, nfCanvasUtils, nfErrorHandler, nfDialog, nfCommon, nfControllerService, nfProcessGroup, nfPolicyManagement, nfComponentState, nfNgBridge) { +}(this, function ($, d3, Slick, nfClient, nfShell, nfProcessGroupConfiguration, nfCanvasUtils, nfErrorHandler, nfDialog, nfCommon, nfControllerService, nfProcessGroup, nfPolicyManagement, nfComponentState, nfComponentVersion, nfNgBridge) { 'use strict'; var dblClick = null; @@ -143,10 +146,11 @@ * Hides the selected controller service. */ var clearSelectedControllerService = function () { - $('#controller-service-type-description').text(''); - $('#controller-service-type-name').text(''); + $('#controller-service-type-description').attr('title', '').text(''); + $('#controller-service-type-name').attr('title', '').text(''); + $('#controller-service-type-bundle').attr('title', '').text(''); $('#selected-controller-service-name').text(''); - $('#selected-controller-service-type').text(''); + $('#selected-controller-service-type').text('').removeData('bundle'); $('#controller-service-description-container').hide(); }; @@ -183,8 +187,17 @@ } } + // determine if the row matches the selected source group + var matchesGroup = true; + if (matchesFilter && matchesTags) { + var bundleGroup = $('#controller-service-bundle-group-combo').combo('getSelectedOption'); + if (nfCommon.isDefinedAndNotNull(bundleGroup) && bundleGroup.value !== '') { + matchesGroup = (item.bundle.group === bundleGroup.value); + } + } + // determine if this row should be visible - var matches = matchesFilter && matchesTags; + var matches = matchesFilter && matchesTags && matchesGroup; // if this row is currently selected and its being filtered if (matches === false && $('#selected-controller-service-type').text() === item['type']) { @@ -254,6 +267,7 @@ */ var addSelectedControllerService = function (controllerServicesUri, serviceTable) { var selectedServiceType = $('#selected-controller-service-type').text(); + var selectedServiceBundle = $('#selected-controller-service-type').data('bundle'); // ensure something was selected if (selectedServiceType === '') { @@ -262,7 +276,7 @@ dialogContent: 'The type of controller service to create must be selected.' }); } else { - addControllerService(controllerServicesUri, serviceTable, selectedServiceType); + addControllerService(controllerServicesUri, serviceTable, selectedServiceType, selectedServiceBundle); } }; @@ -272,8 +286,9 @@ * @param {string} controllerServicesUri * @param {jQuery} serviceTable * @param {string} controllerServiceType + * @param {object} controllerServiceBundle */ - var addControllerService = function (controllerServicesUri, serviceTable, controllerServiceType) { + var addControllerService = function (controllerServicesUri, serviceTable, controllerServiceType, controllerServiceBundle) { // build the controller service entity var controllerServiceEntity = { 'revision': nfClient.getRevision({ @@ -282,7 +297,8 @@ } }), 'component': { - 'type': controllerServiceType + 'type': controllerServiceType, + 'bundle': controllerServiceBundle } }; @@ -297,7 +313,10 @@ // add the item var controllerServicesGrid = serviceTable.data('gridInstance'); var controllerServicesData = controllerServicesGrid.getData(); - controllerServicesData.addItem(controllerServiceEntity); + controllerServicesData.addItem($.extend({ + type: 'ControllerService', + bulletins: [] + }, controllerServiceEntity)); // resort controllerServicesData.reSort(); @@ -319,21 +338,29 @@ * Initializes the new controller service dialog. */ var initNewControllerServiceDialog = function () { - // initialize the processor type table + // initialize the controller service type table var controllerServiceTypesColumns = [ { id: 'type', name: 'Type', field: 'label', formatter: nfCommon.typeFormatter, - sortable: false, + sortable: true, + resizable: true + }, + { + id: 'version', + name: 'Version', + field: 'version', + formatter: nfCommon.typeVersionFormatter, + sortable: true, resizable: true }, { id: 'tags', name: 'Tags', field: 'tags', - sortable: false, + sortable: true, resizable: true } ]; @@ -348,11 +375,23 @@ }); controllerServiceTypesData.setFilter(filterControllerServiceTypes); + // initialize the sort + nfCommon.sortType({ + columnId: 'type', + sortAsc: true + }, controllerServiceTypesData); + // initialize the grid var controllerServiceTypesGrid = new Slick.Grid('#controller-service-types-table', controllerServiceTypesData, controllerServiceTypesColumns, gridOptions); controllerServiceTypesGrid.setSelectionModel(new Slick.RowSelectionModel()); controllerServiceTypesGrid.registerPlugin(new Slick.AutoTooltips()); controllerServiceTypesGrid.setSortColumn('type', true); + controllerServiceTypesGrid.onSort.subscribe(function (e, args) { + nfCommon.sortType({ + columnId: args.sortCol.field, + sortAsc: args.sortAsc + }, controllerServiceTypesData); + }); controllerServiceTypesGrid.onSelectedRowsChanged.subscribe(function (e, args) { if ($.isArray(args.rows) && args.rows.length === 1) { var controllerServiceTypeIndex = args.rows[0]; @@ -374,10 +413,14 @@ .ellipsis(); } + var bundle = nfCommon.formatBundle(controllerServiceType.bundle); + var type = nfCommon.formatType(controllerServiceType); + // populate the dom - $('#controller-service-type-name').text(controllerServiceType.label).ellipsis(); + $('#controller-service-type-name').text(type).attr('title', type); + $('#controller-service-type-bundle').text(bundle).attr('title', bundle); $('#selected-controller-service-name').text(controllerServiceType.label); - $('#selected-controller-service-type').text(controllerServiceType.type); + $('#selected-controller-service-type').text(controllerServiceType.type).data('bundle', controllerServiceType.bundle); // refresh the buttons based on the current selection $('#new-controller-service-dialog').modal('refreshButtons'); @@ -386,6 +429,7 @@ }); controllerServiceTypesGrid.onViewportChanged.subscribe(function (e, args) { nfCommon.cleanUpTooltips($('#controller-service-types-table'), 'div.view-usage-restriction'); + nfCommon.cleanUpTooltips($('#controller-service-types-table'), 'div.controller-service-apis'); }); // wire up the dataview to the grid @@ -427,6 +471,35 @@ })); } } + + var serviceApis = $(this).find('div.controller-service-apis'); + if (serviceApis.length && !serviceApis.data('qtip')) { + var rowId = $(this).find('span.row-id').text(); + + // get the status item + var item = controllerServiceTypesData.getItemById(rowId); + + // show the tooltip + if (!nfCommon.isEmpty(item.controllerServiceApis)) { + var formattedControllerServiceApis = nfCommon.getFormattedServiceApis(item.controllerServiceApis); + var serviceTips = nfCommon.formatUnorderedList(formattedControllerServiceApis); + + var tipContent = $('<div style="padding: 4px;"><p>Supports Controller Services</p><br/></div>').append(serviceTips); + + serviceApis.qtip($.extend({}, nfCommon.config.tooltipConfig, { + content: tipContent, + position: { + container: $('#summary'), + at: 'bottom right', + my: 'top left', + adjust: { + x: 4, + y: 4 + } + } + })); + } + } }); // load the available controller services @@ -437,17 +510,23 @@ }).done(function (response) { var id = 0; var tags = []; + var groups = d3.set(); // begin the update controllerServiceTypesData.beginUpdate(); // go through each controller service type $.each(response.controllerServiceTypes, function (i, documentedType) { + // record the group + groups.add(documentedType.bundle.group); + // add the documented type controllerServiceTypesData.addItem({ id: id++, label: nfCommon.substringAfterLast(documentedType.type, '.'), type: documentedType.type, + bundle: documentedType.bundle, + controllerServiceApis: documentedType.controllerServiceApis, description: nfCommon.escapeHtml(documentedType.description), usageRestriction: nfCommon.escapeHtml(documentedType.usageRestriction), tags: documentedType.tags.join(', ') @@ -459,9 +538,13 @@ }); }); - // end the udpate + // end the update controllerServiceTypesData.endUpdate(); + // resort + controllerServiceTypesData.reSort(); + controllerServiceTypesGrid.invalidate(); + // set the total number of processors $('#total-controller-service-types, #displayed-controller-service-types').text(response.controllerServiceTypes.length); @@ -471,6 +554,24 @@ select: applyControllerServiceTypeFilter, remove: applyControllerServiceTypeFilter }); + + // build the combo options + var options = [{ + text: 'all groups', + value: '' + }]; + groups.forEach(function (group) { + options.push({ + text: group, + value: group + }); + }); + + // initialize the bundle group combo + $('#controller-service-bundle-group-combo').combo({ + options: options, + select: applyControllerServiceTypeFilter + }); }).fail(nfErrorHandler.handleAjaxError); // initialize the controller service dialog @@ -488,6 +589,11 @@ // clear the tagcloud $('#controller-service-tag-cloud').tagcloud('clearSelectedTags'); + // reset the group combo + $('#controller-service-bundle-group-combo').combo('setSelectedOption', { + value: '' + }); + // reset the filter applyControllerServiceTypeFilter(); @@ -525,24 +631,6 @@ }; /** - * Formatter for the type column. - * - * @param {type} row - * @param {type} cell - * @param {type} value - * @param {type} columnDef - * @param {type} dataContext - * @returns {String} - */ - var typeFormatter = function (row, cell, value, columnDef, dataContext) { - if (!dataContext.permissions.canRead) { - return ''; - } - - return nfCommon.substringAfterLast(dataContext.component.type, '.'); - }; - - /** * Formatter for the name column. * * @param {type} row @@ -774,15 +862,19 @@ if (nfCommon.isEmpty(dataContext.component.validationErrors)) { markup += '<div class="pointer enable-controller-service fa fa-flash" title="Enable" style="margin-top: 2px; margin-right: 3px;"></div>'; } + + if (dataContext.component.multipleVersionsAvailable === true) { + markup += '<div title="Change Version" class="pointer change-version-controller-service fa fa-exchange" style="margin-top: 2px; margin-right: 3px;" ></div>'; + } + + if (canWriteControllerServiceParent(dataContext)) { + markup += '<div class="pointer delete-controller-service fa fa-trash" title="Remove" style="margin-top: 2px; margin-right: 3px;" ></div>'; + } } if (dataContext.component.persistsState === true) { markup += '<div title="View State" class="pointer view-state-controller-service fa fa-tasks" style="margin-top: 2px; margin-right: 3px;" ></div>'; } - - if (canWriteControllerServiceParent(dataContext)) { - markup += '<div class="pointer delete-controller-service fa fa-trash" title="Remove" style="margin-top: 2px; margin-right: 3px;" ></div>'; - } } else { markup += '<div class="pointer go-to-controller-service fa fa-long-arrow-right" title="Go To" style="margin-top: 2px; margin-right: 3px;" ></div>'; } @@ -818,7 +910,14 @@ { id: 'type', name: 'Type', - formatter: typeFormatter, + formatter: nfCommon.instanceTypeFormatter, + sortable: true, + resizable: true + }, + { + id: 'bundle', + name: 'Bundle', + formatter: nfCommon.instanceBundleFormatter, sortable: true, resizable: true }, @@ -884,6 +983,8 @@ nfControllerService.promptToDeleteController(serviceTable, controllerServiceEntity); } else if (target.hasClass('view-state-controller-service')) { nfComponentState.showState(controllerServiceEntity, controllerServiceEntity.state === 'DISABLED'); + } else if (target.hasClass('change-version-controller-service')) { + nfComponentVersion.promptForVersionChange(controllerServiceEntity); } else if (target.hasClass('edit-access-policies')) { // show the policies for this service nfPolicyManagement.showControllerServicePolicy(controllerServiceEntity); @@ -1028,6 +1129,7 @@ var services = []; $.each(response.controllerServices, function (_, service) { services.push($.extend({ + type: 'ControllerService', bulletins: [] }, service)); }); @@ -1075,6 +1177,7 @@ promptNewControllerService: function (controllerServicesUri, serviceTable) { // get the grid reference var grid = $('#controller-service-types-table').data('gridInstance'); + var dataview = grid.getData(); // update the keyhandler $('#controller-service-type-filter').off('keyup').on('keyup', function (e) { @@ -1110,7 +1213,7 @@ var item = grid.getDataItem(selected[0]); return isSelectable(item) === false; } else { - return grid.getData().getLength() === 0; + return dataview.getLength() === 0; } }, handler: { @@ -1132,27 +1235,27 @@ } }]).modal('show'); - var controllerServiceTypesGrid = $('#controller-service-types-table').data('gridInstance'); - // remove previous dbl click handler if (dblClick !== null) { - controllerServiceTypesGrid.onDblClick.unsubscribe(dblClick); + grid.onDblClick.unsubscribe(dblClick); } // update the dbl click handler and subsrcibe dblClick = function(e, args) { - var controllerServiceType = controllerServiceTypesGrid.getDataItem(args.row); + var controllerServiceType = grid.getDataItem(args.row); if (isSelectable(controllerServiceType)) { - addControllerService(controllerServicesUri, serviceTable, controllerServiceType.type); + addControllerService(controllerServicesUri, serviceTable, controllerServiceType.type, controllerServiceType.bundle); } }; - controllerServiceTypesGrid.onDblClick.subscribe(dblClick); + grid.onDblClick.subscribe(dblClick); // reset the canvas size after the dialog is shown - if (nfCommon.isDefinedAndNotNull(controllerServiceTypesGrid)) { - controllerServiceTypesGrid.setSelectedRows([0]); - controllerServiceTypesGrid.resizeCanvas(); + grid.resizeCanvas(); + + // auto select the first row if possible + if (dataview.getLength() > 0) { + grid.setSelectedRows([0]); } // set the initial focus http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-configuration.js ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-configuration.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-configuration.js index c26969e..1a26f5a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-configuration.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-configuration.js @@ -672,7 +672,8 @@ // populate the processor settings $('#processor-id').text(processor['id']); - $('#processor-type').text(nfCommon.substringAfterLast(processor['type'], '.')); + $('#processor-type').text(nfCommon.formatType(processor)); + $('#processor-bundle').text(nfCommon.formatBundle(processor['bundle'])); $('#processor-name').val(processor['name']); $('#processor-enabled').removeClass('checkbox-unchecked checkbox-checked').addClass(processorEnableStyle); $('#penalty-duration').val(processor.config['penaltyDuration']); http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor.js ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor.js index 4f25699..bc09526 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor.js @@ -136,8 +136,8 @@ // processor name processor.append('text') .attr({ - 'x': 72, - 'y': 23, + 'x': 75, + 'y': 18, 'width': 210, 'height': 14, 'class': 'processor-name' @@ -198,6 +198,9 @@ updated.select('rect.border') .classed('unauthorized', function (d) { return d.permissions.canRead === false; + }) + .classed('ghost', function (d) { + return d.permissions.canRead === true && d.component.extensionMissing === true; }); // processor body authorization @@ -230,9 +233,19 @@ details.append('text') .attr({ 'class': 'processor-type', - 'x': 72, - 'y': 37, - 'width': 236, + 'x': 75, + 'y': 32, + 'width': 230, + 'height': 12 + }); + + // processor type + details.append('text') + .attr({ + 'class': 'processor-bundle', + 'x': 75, + 'y': 45, + 'width': 230, 'height': 12 }); @@ -490,7 +503,7 @@ details.append('text') .attr({ 'class': 'active-thread-count-icon', - 'y': 42 + 'y': 45 }) .text('\ue83f'); @@ -498,7 +511,7 @@ details.append('text') .attr({ 'class': 'active-thread-count', - 'y': 42 + 'y': 45 }); // --------- @@ -540,8 +553,8 @@ // apply ellipsis to the processor name as necessary nfCanvasUtils.ellipsis(processorName, d.component.name); }).append('title').text(function (d) { - return d.component.name; - }); + return d.component.name; + }); // update the processor type processor.select('text.processor-type') @@ -552,16 +565,33 @@ processorType.text(null).selectAll('title').remove(); // apply ellipsis to the processor type as necessary - nfCanvasUtils.ellipsis(processorType, nfCommon.substringAfterLast(d.component.type, '.')); + nfCanvasUtils.ellipsis(processorType, nfCommon.formatType(d.component)); }).append('title').text(function (d) { - return nfCommon.substringAfterLast(d.component.type, '.'); - }); + return nfCommon.formatType(d.component); + }); + + // update the processor bundle + processor.select('text.processor-bundle') + .each(function (d) { + var processorBundle = d3.select(this); + + // reset the processor type to handle any previous state + processorBundle.text(null).selectAll('title').remove(); + + // apply ellipsis to the processor type as necessary + nfCanvasUtils.ellipsis(processorBundle, nfCommon.formatBundle(d.component.bundle)); + }).append('title').text(function (d) { + return nfCommon.formatBundle(d.component.bundle); + }); } else { // clear the processor name processor.select('text.processor-name').text(null); // clear the processor type processor.select('text.processor-type').text(null); + + // clear the processor bundle + processor.select('text.processor-bundle').text(null); } // populate the stats http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-reporting-task.js ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-reporting-task.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-reporting-task.js index bb1b07c..5525874 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-reporting-task.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-reporting-task.js @@ -230,6 +230,7 @@ var reportingTaskData = reportingTaskGrid.getData(); var currentReportingTask = reportingTaskData.getItemById(reportingTaskEntity.id); reportingTaskData.updateItem(reportingTaskEntity.id, $.extend({ + type: 'ReportingTask', bulletins: currentReportingTask.bulletins }, reportingTaskEntity)); }; @@ -478,7 +479,8 @@ // populate the reporting task settings nfCommon.populateField('reporting-task-id', reportingTask['id']); - nfCommon.populateField('reporting-task-type', nfCommon.substringAfterLast(reportingTask['type'], '.')); + nfCommon.populateField('reporting-task-type', nfCommon.formatType(reportingTask)); + nfCommon.populateField('reporting-task-bundle', nfCommon.formatBundle(reportingTask['bundle'])); $('#reporting-task-name').val(reportingTask['name']); $('#reporting-task-enabled').removeClass('checkbox-unchecked checkbox-checked').addClass(reportingTaskEnableStyle); $('#reporting-task-comments').val(reportingTask['comments']); @@ -677,6 +679,7 @@ // populate the reporting task settings nfCommon.populateField('reporting-task-id', reportingTask['id']); nfCommon.populateField('reporting-task-type', nfCommon.substringAfterLast(reportingTask['type'], '.')); + nfCommon.populateField('reporting-task-bundle', nfCommon.formatBundle(reportingTask['bundle'])); nfCommon.populateField('read-only-reporting-task-name', reportingTask['name']); nfCommon.populateField('read-only-reporting-task-comments', reportingTask['comments']); http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js index fa7afbd..667a675 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js @@ -31,9 +31,10 @@ 'nf.ReportingTask', 'nf.Shell', 'nf.ComponentState', + 'nf.ComponentVersion', 'nf.PolicyManagement'], - function ($, Slick, d3, nfClient, nfDialog, nfCommon, nfCanvasUtils, nfControllerServices, nfErrorHandler, nfReportingTask, nfShell, nfComponentState, nfPolicyManagement) { - return (nf.Settings = factory($, Slick, d3, nfClient, nfDialog, nfCommon, nfCanvasUtils, nfControllerServices, nfErrorHandler, nfReportingTask, nfShell, nfComponentState, nfPolicyManagement)); + function ($, Slick, d3, nfClient, nfDialog, nfCommon, nfCanvasUtils, nfControllerServices, nfErrorHandler, nfReportingTask, nfShell, nfComponentState, nfComponentVersion, nfPolicyManagement) { + return (nf.Settings = factory($, Slick, d3, nfClient, nfDialog, nfCommon, nfCanvasUtils, nfControllerServices, nfErrorHandler, nfReportingTask, nfShell, nfComponentState, nfComponentVersion, nfPolicyManagement)); }); } else if (typeof exports === 'object' && typeof module === 'object') { module.exports = (nf.Settings = @@ -49,6 +50,7 @@ require('nf.ReportingTask'), require('nf.Shell'), require('nf.ComponentState'), + require('nf.ComponentVersion'), require('nf.PolicyManagement'))); } else { nf.Settings = factory(root.$, @@ -63,9 +65,10 @@ root.nf.ReportingTask, root.nf.Shell, root.nf.ComponentState, + root.nf.ComponentVersion, root.nf.PolicyManagement); } -}(this, function ($, Slick, d3, nfClient, nfDialog, nfCommon, nfCanvasUtils, nfControllerServices, nfErrorHandler, nfReportingTask, nfShell, nfComponentState, nfPolicyManagement) { +}(this, function ($, Slick, d3, nfClient, nfDialog, nfCommon, nfCanvasUtils, nfControllerServices, nfErrorHandler, nfReportingTask, nfShell, nfComponentState, nfComponentVersion, nfPolicyManagement) { 'use strict'; @@ -233,24 +236,6 @@ }; /** - * Formatter for the type column. - * - * @param {type} row - * @param {type} cell - * @param {type} value - * @param {type} columnDef - * @param {type} dataContext - * @returns {String} - */ - var typeFormatter = function (row, cell, value, columnDef, dataContext) { - if (!dataContext.permissions.canRead) { - return ''; - } - - return nfCommon.substringAfterLast(dataContext.component.type, '.'); - }; - - /** * Sorts the specified data using the specified sort details. * * @param {object} sortDetails @@ -345,10 +330,11 @@ * Hides the selected reporting task. */ var clearSelectedReportingTask = function () { - $('#reporting-task-type-description').text(''); - $('#reporting-task-type-name').text(''); + $('#reporting-task-type-description').attr('title', '').text(''); + $('#reporting-task-type-name').attr('title', '').text(''); + $('#reporting-task-type-bundle').attr('title', '').text(''); $('#selected-reporting-task-name').text(''); - $('#selected-reporting-task-type').text(''); + $('#selected-reporting-task-type').text('').removeData('bundle'); $('#reporting-task-description-container').hide(); }; @@ -385,8 +371,17 @@ } } + // determine if the row matches the selected source group + var matchesGroup = true; + if (matchesFilter && matchesTags) { + var bundleGroup = $('#reporting-task-bundle-group-combo').combo('getSelectedOption'); + if (nfCommon.isDefinedAndNotNull(bundleGroup) && bundleGroup.value !== '') { + matchesGroup = (item.bundle.group === bundleGroup.value); + } + } + // determine if this row should be visible - var matches = matchesFilter && matchesTags; + var matches = matchesFilter && matchesTags && matchesGroup; // if this row is currently selected and its being filtered if (matches === false && $('#selected-reporting-task-type').text() === item['type']) { @@ -401,6 +396,7 @@ */ var addSelectedReportingTask = function () { var selectedTaskType = $('#selected-reporting-task-type').text(); + var selectedTaskBundle = $('#selected-reporting-task-type').data('bundle'); // ensure something was selected if (selectedTaskType === '') { @@ -409,7 +405,7 @@ dialogContent: 'The type of reporting task to create must be selected.' }); } else { - addReportingTask(selectedTaskType); + addReportingTask(selectedTaskType, selectedTaskBundle); } }; @@ -417,8 +413,9 @@ * Adds a new reporting task of the specified type. * * @param {string} reportingTaskType + * @param {object} reportingTaskBundle */ - var addReportingTask = function (reportingTaskType) { + var addReportingTask = function (reportingTaskType, reportingTaskBundle) { // build the reporting task entity var reportingTaskEntity = { 'revision': nfClient.getRevision({ @@ -427,7 +424,8 @@ } }), 'component': { - 'type': reportingTaskType + 'type': reportingTaskType, + 'bundle': reportingTaskBundle } }; @@ -442,7 +440,10 @@ // add the item var reportingTaskGrid = $('#reporting-tasks-table').data('gridInstance'); var reportingTaskData = reportingTaskGrid.getData(); - reportingTaskData.addItem(reportingTaskEntity); + reportingTaskData.addItem($.extend({ + type: 'ReportingTask', + bulletins: [] + }, reportingTaskEntity)); // resort reportingTaskData.reSort(); @@ -484,21 +485,29 @@ } }); - // initialize the processor type table + // initialize the reporting task type table var reportingTaskTypesColumns = [ { id: 'type', name: 'Type', field: 'label', formatter: nfCommon.typeFormatter, - sortable: false, + sortable: true, + resizable: true + }, + { + id: 'version', + name: 'Version', + field: 'version', + formatter: nfCommon.typeVersionFormatter, + sortable: true, resizable: true }, { id: 'tags', name: 'Tags', field: 'tags', - sortable: false, + sortable: true, resizable: true } ]; @@ -513,11 +522,23 @@ }); reportingTaskTypesData.setFilter(filterReportingTaskTypes); + // initialize the sort + nfCommon.sortType({ + columnId: 'type', + sortAsc: true + }, reportingTaskTypesData); + // initialize the grid var reportingTaskTypesGrid = new Slick.Grid('#reporting-task-types-table', reportingTaskTypesData, reportingTaskTypesColumns, gridOptions); reportingTaskTypesGrid.setSelectionModel(new Slick.RowSelectionModel()); reportingTaskTypesGrid.registerPlugin(new Slick.AutoTooltips()); reportingTaskTypesGrid.setSortColumn('type', true); + reportingTaskTypesGrid.onSort.subscribe(function (e, args) { + nfCommon.sortType({ + columnId: args.sortCol.field, + sortAsc: args.sortAsc + }, reportingTaskTypesData); + }); reportingTaskTypesGrid.onSelectedRowsChanged.subscribe(function (e, args) { if ($.isArray(args.rows) && args.rows.length === 1) { var reportingTaskTypeIndex = args.rows[0]; @@ -539,10 +560,14 @@ .ellipsis(); } + var bundle = nfCommon.formatBundle(reportingTaskType.bundle); + var type = nfCommon.formatType(reportingTaskType); + // populate the dom - $('#reporting-task-type-name').text(reportingTaskType.label).ellipsis(); + $('#reporting-task-type-name').text(type).attr('title', type); + $('#reporting-task-type-bundle').text(bundle).attr('title', bundle); $('#selected-reporting-task-name').text(reportingTaskType.label); - $('#selected-reporting-task-type').text(reportingTaskType.type); + $('#selected-reporting-task-type').text(reportingTaskType.type).data('bundle', reportingTaskType.bundle); // refresh the buttons based on the current selection $('#new-reporting-task-dialog').modal('refreshButtons'); @@ -553,7 +578,7 @@ var reportingTaskType = reportingTaskTypesGrid.getDataItem(args.row); if (isSelectable(reportingTaskType)) { - addReportingTask(reportingTaskType.type); + addReportingTask(reportingTaskType.type, reportingTaskType.bundle); } }); reportingTaskTypesGrid.onViewportChanged.subscribe(function (e, args) { @@ -609,17 +634,22 @@ }).done(function (response) { var id = 0; var tags = []; + var groups = d3.set(); // begin the update reportingTaskTypesData.beginUpdate(); // go through each reporting task type $.each(response.reportingTaskTypes, function (i, documentedType) { + // record the group + groups.add(documentedType.bundle.group); + // add the documented type reportingTaskTypesData.addItem({ id: id++, label: nfCommon.substringAfterLast(documentedType.type, '.'), type: documentedType.type, + bundle: documentedType.bundle, description: nfCommon.escapeHtml(documentedType.description), usageRestriction: nfCommon.escapeHtml(documentedType.usageRestriction), tags: documentedType.tags.join(', ') @@ -631,9 +661,13 @@ }); }); - // end the udpate + // end the update reportingTaskTypesData.endUpdate(); + // resort + reportingTaskTypesData.reSort(); + reportingTaskTypesGrid.invalidate(); + // set the total number of processors $('#total-reporting-task-types, #displayed-reporting-task-types').text(response.reportingTaskTypes.length); @@ -643,6 +677,24 @@ select: applyReportingTaskTypeFilter, remove: applyReportingTaskTypeFilter }); + + // build the combo options + var options = [{ + text: 'all groups', + value: '' + }]; + groups.forEach(function (group) { + options.push({ + text: group, + value: group + }); + }); + + // initialize the bundle group combo + $('#reporting-task-bundle-group-combo').combo({ + options: options, + select: applyReportingTaskTypeFilter + }); }).fail(nfErrorHandler.handleAjaxError); // initialize the reporting task dialog @@ -697,6 +749,11 @@ // clear the tagcloud $('#reporting-task-tag-cloud').tagcloud('clearSelectedTags'); + // reset the group combo + $('#reporting-task-bundle-group-combo').combo('setSelectedOption', { + value: '' + }); + // reset the filter applyReportingTaskTypeFilter(); @@ -797,6 +854,14 @@ if (dataContext.component.state === 'STOPPED' && nfCommon.isEmpty(dataContext.component.validationErrors)) { markup += '<div title="Start" class="pointer start-reporting-task fa fa-play" style="margin-top: 2px; margin-right: 3px;"></div>'; } + + if (dataContext.component.multipleVersionsAvailable === true) { + markup += '<div title="Change Version" class="pointer change-version-reporting-task fa fa-exchange" style="margin-top: 2px; margin-right: 3px;" ></div>'; + } + + if (nfCommon.canModifyController()) { + markup += '<div title="Remove" class="pointer delete-reporting-task fa fa-trash" style="margin-top: 2px; margin-right: 3px;" ></div>'; + } } if (dataContext.component.persistsState === true) { @@ -804,10 +869,6 @@ } } - if (dataContext.permissions.canWrite && nfCommon.canModifyController()) { - markup += '<div title="Remove" class="pointer delete-reporting-task fa fa-trash" style="margin-top: 2px; margin-right: 3px;" ></div>'; - } - // allow policy configuration conditionally if (nfCanvasUtils.isConfigurableAuthorizer() && nfCommon.canAccessTenants()) { markup += '<div title="Access Policies" class="pointer edit-access-policies fa fa-key" style="margin-top: 2px;"></div>'; @@ -828,8 +889,27 @@ maxWidth: 90, toolTip: 'Sorts based on presence of bulletins' }, - {id: 'name', name: 'Name', sortable: true, resizable: true, formatter: nameFormatter}, - {id: 'type', name: 'Type', sortable: true, resizable: true, formatter: typeFormatter}, + { + id: 'name', + name: 'Name', + sortable: true, + resizable: true, + formatter: nameFormatter + }, + { + id: 'type', + name: 'Type', + formatter: nfCommon.instanceTypeFormatter, + sortable: true, + resizable: true + }, + { + id: 'bundle', + name: 'Bundle', + formatter: nfCommon.instanceBundleFormatter, + sortable: true, + resizable: true + }, { id: 'state', name: 'Run Status', @@ -894,6 +974,8 @@ } else if (target.hasClass('view-state-reporting-task')) { var canClear = reportingTaskEntity.component.state === 'STOPPED' && reportingTaskEntity.component.activeThreadCount === 0; nfComponentState.showState(reportingTaskEntity, canClear); + } else if (target.hasClass('change-version-reporting-task')) { + nfComponentVersion.promptForVersionChange(reportingTaskEntity); } else if (target.hasClass('edit-access-policies')) { // show the policies for this service nfPolicyManagement.showReportingTaskPolicy(reportingTaskEntity); @@ -1081,6 +1163,7 @@ var tasks = []; $.each(response.reportingTasks, function (_, task) { tasks.push($.extend({ + type: 'ReportingTask', bulletins: [] }, task)); }); @@ -1201,11 +1284,17 @@ } else if (selectedTab === 'Reporting Tasks') { $('#new-reporting-task-dialog').modal('show'); - // reset the canvas size after the dialog is shown var reportingTaskTypesGrid = $('#reporting-task-types-table').data('gridInstance'); if (nfCommon.isDefinedAndNotNull(reportingTaskTypesGrid)) { - reportingTaskTypesGrid.setSelectedRows([0]); + var reportingTaskTypesData = reportingTaskTypesGrid.getData(); + + // reset the canvas size after the dialog is shown reportingTaskTypesGrid.resizeCanvas(); + + // select the first row if possible + if (reportingTaskTypesData.getLength() > 0) { + reportingTaskTypesGrid.setSelectedRows([0]); + } } // set the initial focus @@ -1264,6 +1353,24 @@ }, /** + * Selects the specified reporting task. + * + * @param {string} reportingTaskId + */ + selectReportingTask: function (reportingTaskId) { + var reportingTaskGrid = $('#reporting-tasks-table').data('gridInstance'); + var reportingTaskData = reportingTaskGrid.getData(); + + // select the desired service + var row = reportingTaskData.getRowById(reportingTaskId); + reportingTaskGrid.setSelectedRows([row]); + reportingTaskGrid.scrollRowIntoView(row); + + // select the controller services tab + $('#settings-tabs').find('li:eq(2)').click(); + }, + + /** * Sets the controller service and reporting task bulletins in their respective tables. * * @param {object} controllerServiceBulletins http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-common.js ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-common.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-common.js index 682ad4c..a039d3b 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-common.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-common.js @@ -185,6 +185,124 @@ currentUser: undefined, /** + * Sorts the specified version strings. + * + * @param aRawVersion version string + * @param bRawVersion version string + * @returns {number} negative if a before b, positive if a after b, 0 otherwise + */ + sortVersion: function (aRawVersion, bRawVersion) { + if (aRawVersion === bRawVersion) { + return 0; + } + + // attempt to parse the raw strings + var aTokens = aRawVersion.split(/-/); + var bTokens = bRawVersion.split(/-/); + + // ensure there is at least one token + if (aTokens.length >= 1 && bTokens.length >= 1) { + var aVersionTokens = aTokens[0].split(/\./); + var bVersionTokens = bTokens[0].split(/\./); + + // ensure both versions have at least one token + if (aVersionTokens.length >= 1 && bVersionTokens.length >= 1) { + // find the number of tokens a and b have in common + var commonTokenLength = Math.min(aVersionTokens.length, bVersionTokens.length); + + // consider all tokens in common + for (var i = 0; i < commonTokenLength; i++) { + var aVersionSegment = parseInt(aVersionTokens[i], 10); + var bVersionSegment = parseInt(bVersionTokens[i], 10); + + // if both are non numeric, consider the next token + if (isNaN(aVersionSegment) && isNaN(bVersionSegment)) { + continue; + } else if (isNaN(aVersionSegment)) { + // NaN is considered less + return -1; + } else if (isNaN(bVersionSegment)) { + // NaN is considered less + return 1; + } + + // if a version at any point does not match + if (aVersionSegment !== bVersionSegment) { + return aVersionSegment - bVersionSegment; + } + } + + if (aVersionTokens.length === bVersionTokens.length) { + if (aTokens.length === bTokens.length) { + // same version for all tokens so consider the trailing bits (1.1-RC vs 1.1-SNAPSHOT) + var aExtraBits = nfCommon.substringAfterFirst(aRawVersion, aTokens[0]); + var bExtraBits = nfCommon.substringAfterFirst(bRawVersion, bTokens[0]); + return aExtraBits === bExtraBits ? 0 : aExtraBits > bExtraBits ? 1 : -1; + } else { + // in this case, extra bits means it's consider less than no extra bits (1.1 vs 1.1-SNAPSHOT) + return bTokens.length - aTokens.length; + } + } else { + // same version for all tokens in common (ie 1.1 vs 1.1.1) + return aVersionTokens.length - bVersionTokens.length; + } + } else if (aVersionTokens.length >= 1) { + // presence of version tokens is considered greater + return 1; + } else if (bVersionTokens.length >= 1) { + // presence of version tokens is considered greater + return -1; + } else { + return 0; + } + } else if (aTokens.length >= 1) { + // presence of tokens is considered greater + return 1; + } else if (bTokens.length >= 1) { + // presence of tokens is considered greater + return -1; + } else { + return 0; + } + }, + + /** + * Sorts the specified type data using the specified sort details. + * + * @param {object} sortDetails + * @param {object} data + */ + sortType: function (sortDetails, data) { + // compares two bundles + var compareBundle = function (a, b) { + var aBundle = nfCommon.formatBundle(a.bundle); + var bBundle = nfCommon.formatBundle(b.bundle); + return aBundle === bBundle ? 0 : aBundle > bBundle ? 1 : -1; + }; + + // defines a function for sorting + var comparer = function (a, b) { + if (sortDetails.columnId === 'version') { + var aVersion = nfCommon.isDefinedAndNotNull(a.bundle[sortDetails.columnId]) ? a.bundle[sortDetails.columnId] : ''; + var bVersion = nfCommon.isDefinedAndNotNull(b.bundle[sortDetails.columnId]) ? b.bundle[sortDetails.columnId] : ''; + var versionResult = nfCommon.sortVersion(aVersion, bVersion); + return versionResult === 0 ? compareBundle(a, b) : versionResult; + } else if (sortDetails.columnId === 'type') { + var aType = nfCommon.substringAfterLast(a[sortDetails.columnId], '.'); + var bType = nfCommon.substringAfterLast(b[sortDetails.columnId], '.'); + return aType === bType ? 0 : aType > bType ? 1 : -1; + } else { + var aString = nfCommon.isDefinedAndNotNull(a[sortDetails.columnId]) ? a[sortDetails.columnId] : ''; + var bString = nfCommon.isDefinedAndNotNull(b[sortDetails.columnId]) ? b[sortDetails.columnId] : ''; + return aString === bString ? compareBundle(a, b) : aString > bString ? 1 : -1; + } + }; + + // perform the sort + data.sort(comparer, sortDetails.sortAsc); + }, + + /** * Formats type of a component for a new instance dialog. * * @param row @@ -205,12 +323,116 @@ } // type - markup += value; + markup += nfCommon.escapeHtml(value); return markup; }, /** + * Formats the bundle of a component type for the new instance dialog. + * + * @param row + * @param cell + * @param value + * @param columnDef + * @param dataContext + * @returns {string} + */ + typeBundleFormatter: function (row, cell, value, columnDef, dataContext) { + return nfCommon.escapeHtml(nfCommon.formatBundle(dataContext.bundle)); + }, + + /** + * Formats the bundle of a component type for the new instance dialog. + * + * @param row + * @param cell + * @param value + * @param columnDef + * @param dataContext + * @returns {string} + */ + typeVersionFormatter: function (row, cell, value, columnDef, dataContext) { + var markup = ''; + + if (nfCommon.isDefinedAndNotNull(dataContext.bundle)) { + markup += ('<div style="float: left;">' + nfCommon.escapeHtml(dataContext.bundle.version) + '</div>'); + } else { + markup += '<div style="float: left;">unversioned</div>'; + } + + if (!nfCommon.isEmpty(dataContext.controllerServiceApis)) { + markup += '<div class="controller-service-apis fa fa-list" title="Compatible Controller Service" style="margin-top: 2px; margin-left: 4px;"></div><span class="hidden row-id">' + nfCommon.escapeHtml(dataContext.id) + '</span>'; + } + + markup += '<div class="clear"></div>'; + + return markup; + }, + + /** + * Formatter for the type column. + * + * @param {type} row + * @param {type} cell + * @param {type} value + * @param {type} columnDef + * @param {type} dataContext + * @returns {String} + */ + instanceTypeFormatter: function (row, cell, value, columnDef, dataContext) { + if (!dataContext.permissions.canRead) { + return ''; + } + + return nfCommon.escapeHtml(nfCommon.formatType(dataContext.component)); + }, + + /** + * Formats the bundle of a component instance for the component listing table. + * + * @param row + * @param cell + * @param value + * @param columnDef + * @param dataContext + * @returns {string} + */ + instanceBundleFormatter: function (row, cell, value, columnDef, dataContext) { + if (!dataContext.permissions.canRead) { + return ''; + } + + return nfCommon.typeBundleFormatter(row, cell, value, columnDef, dataContext.component); + }, + + /** + * Formats the type of this component. + * + * @param dataContext component datum + */ + formatType: function (dataContext) { + var typeString = nfCommon.substringAfterLast(dataContext.type, '.'); + if (dataContext.bundle.version !== 'unversioned') { + typeString += (' ' + dataContext.bundle.version); + } + return typeString; + }, + + /** + * Formats the bundle label. + * + * @param bundle + */ + formatBundle: function (bundle) { + var groupString = ''; + if (bundle.group !== 'default') { + groupString = bundle.group + ' - '; + } + return groupString + bundle.artifact; + }, + + /** * Sets the current user. * * @param currentUser @@ -588,6 +810,14 @@ if (!nfCommon.isBlank(propertyDescriptor.supportsEl)) { tipContent.push('<b>Supports expression language:</b> ' + nfCommon.escapeHtml(propertyDescriptor.supportsEl)); } + if (!nfCommon.isBlank(propertyDescriptor.identifiesControllerService)) { + var formattedType = nfCommon.formatType({ + 'type': propertyDescriptor.identifiesControllerService, + 'bundle': propertyDescriptor.identifiesControllerServiceBundle + }); + var formattedBundle = nfCommon.formatBundle(propertyDescriptor.identifiesControllerServiceBundle); + tipContent.push('<b>Requires Controller Service:</b> ' + nfCommon.escapeHtml(formattedType + ' from ' + formattedBundle)); + } } if (nfCommon.isDefinedAndNotNull(propertyHistory)) { @@ -1252,6 +1482,25 @@ return formattedBulletinEntities; }, + /** + * Formats the specified controller service list. + * + * @param {array} controllerServiceApis + * @returns {array} + */ + getFormattedServiceApis: function (controllerServiceApis) { + var formattedControllerServiceApis = []; + $.each(controllerServiceApis, function (i, controllerServiceApi) { + var formattedType = nfCommon.formatType({ + 'type': controllerServiceApi.type, + 'bundle': controllerServiceApi.bundle + }); + var formattedBundle = nfCommon.formatBundle(controllerServiceApi.bundle); + formattedControllerServiceApis.push($('<div></div>').text(formattedType + ' from ' + formattedBundle)); + }); + return formattedControllerServiceApis; + }, + getPolicyTypeListing: function (value) { var nest = d3.nest() .key(function (d) { http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-processor-details.js ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-processor-details.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-processor-details.js index 1b6b28a..69969e3 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-processor-details.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-processor-details.js @@ -179,7 +179,8 @@ // populate the processor settings nfCommon.populateField('read-only-processor-id', details['id']); - nfCommon.populateField('read-only-processor-type', nfCommon.substringAfterLast(details['type'], '.')); + nfCommon.populateField('read-only-processor-type', nfCommon.formatType(details)); + nfCommon.populateField('read-only-processor-bundle', nfCommon.formatBundle(details['bundle'])); nfCommon.populateField('read-only-processor-name', details['name']); nfCommon.populateField('read-only-concurrently-schedulable-tasks', details.config['concurrentlySchedulableTaskCount']); nfCommon.populateField('read-only-scheduling-period', details.config['schedulingPeriod']); http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/pom.xml ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/pom.xml index 6d7d94b..f803a36 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/pom.xml +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/pom.xml @@ -41,6 +41,7 @@ <module>nifi-documentation</module> <module>nifi-authorizer</module> <module>nifi-properties-loader</module> + <module>nifi-standard-prioritizers</module> </modules> <dependencies> <dependency>
