You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by mc...@apache.org on 2015/01/27 19:53:24 UTC

[1/3] incubator-nifi git commit: NIFI-250: - Creating a jQuery plugin for rendering a table of properties (since we now want to configure processors, controller services, and reporting tasks).

Repository: incubator-nifi
Updated Branches:
  refs/heads/NIFI-250 ea17dbec6 -> 2d7c700d1


http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/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/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/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-configuration.js
index 14ffa95..106542f 100644
--- a/nifi/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/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-configuration.js
@@ -220,7 +220,7 @@ nf.ProcessorConfiguration = (function () {
         }
 
         // defer to the property and relationship grids
-        return nf.ProcessorPropertyTable.isSaveRequired();
+        return $('#processor-properties').propertytable('isSaveRequired');
     };
 
     /**
@@ -275,7 +275,7 @@ nf.ProcessorConfiguration = (function () {
         processorConfigDto['autoTerminatedRelationships'] = marshalRelationships();
 
         // properties
-        var properties = nf.ProcessorPropertyTable.marshalProperties();
+        var properties = $('#processor-properties').propertytable('marshalProperties');
 
         // set the properties
         if ($.isEmptyObject(properties) === false) {
@@ -389,25 +389,25 @@ nf.ProcessorConfiguration = (function () {
                 selectedTabStyle: 'selected-tab',
                 tabs: [{
                         name: 'Settings',
-                        tabContentId: 'configuration-standard-settings-tab-content'
+                        tabContentId: 'processor-standard-settings-tab-content'
                     }, {
                         name: 'Scheduling',
-                        tabContentId: 'configuration-scheduling-tab-content'
+                        tabContentId: 'processor-scheduling-tab-content'
                     }, {
                         name: 'Properties',
-                        tabContentId: 'configuration-processor-properties-tab-content'
+                        tabContentId: 'processor-properties-tab-content'
                     }, {
                         name: 'Comments',
-                        tabContentId: 'configuration-comments-tab-content'
+                        tabContentId: 'processor-comments-tab-content'
                     }],
                 select: function () {
                     // update the processor property table size in case this is the first time its rendered
                     if ($(this).text() === 'Properties') {
-                        nf.ProcessorPropertyTable.resetTableSize();
+                        $('#processor-properties').propertytable('resetTableSize');
                     }
 
                     // close all fields currently being edited
-                    nf.ProcessorPropertyTable.saveRow();
+                    $('#processor-properties').propertytable('saveRow');
 
                     // show the border around the processor relationships if necessary
                     var processorRelationships = $('#auto-terminate-relationship-names');
@@ -430,10 +430,10 @@ nf.ProcessorConfiguration = (function () {
                         $('#processor-property-dialog').hide();
 
                         // cancel any active edits
-                        nf.ProcessorPropertyTable.cancelEdit();
+                        $('#processor-properties').propertytable('cancelEdit');
 
                         // clear the tables
-                        nf.ProcessorPropertyTable.clear();
+                        $('#processor-properties').propertytable('clear');
 
                         // removed the cached processor details
                         $('#processor-configuration').removeData('processorDetails');
@@ -469,7 +469,10 @@ nf.ProcessorConfiguration = (function () {
             });
 
             // initialize the property table
-            nf.ProcessorPropertyTable.init();
+            $('#processor-properties').propertytable({
+                readOnly: false,
+                newPropertyDialogContainer: 'body'
+            });
         },
         
         /**
@@ -578,9 +581,33 @@ nf.ProcessorConfiguration = (function () {
                     $('#timer-driven-scheduling-period').val(processor.config['schedulingPeriod']);
                 }
 
-                // load the property table
-                nf.ProcessorPropertyTable.loadProperties(processor.config.properties, processor.config.descriptors);
+                // get the processor history
+                $.ajax({
+                    type: 'GET',
+                    url: '../nifi-api/controller/history/processors/' + encodeURIComponent(processor.id),
+                    dataType: 'json'
+                }).done(function (response) {
+                    var processorHistory = response.processorHistory;
+
+                    // record the processor history
+                    $('#processor-configuration').data('processorHistory', processorHistory);
+
+                    // load the property table
+                    $('#processor-properties').propertytable('loadProperties', processor.config.properties, processor.config.descriptors, processorHistory.propertyHistory);
 
+                    // show the details
+                    $('#processor-configuration').modal('show');
+
+                    // add ellipsis if necessary
+                    $('#processor-configuration div.relationship-name').ellipsis();
+
+                    // show the border if necessary
+                    var processorRelationships = $('#auto-terminate-relationship-names');
+                    if (processorRelationships.is(':visible') && processorRelationships.get(0).scrollHeight > processorRelationships.innerHeight()) {
+                        processorRelationships.css('border-width', '1px');
+                    }
+                }).fail(nf.Common.handleAjaxError);
+                
                 // load the relationship list
                 if (!nf.Common.isEmpty(processor.relationships)) {
                     $.each(processor.relationships, function (i, relationship) {
@@ -595,7 +622,7 @@ nf.ProcessorConfiguration = (function () {
                         handler: {
                             click: function () {
                                 // close all fields currently being edited
-                                nf.ProcessorPropertyTable.saveRow();
+                                $('#processor-properties').propertytable('saveRow');
 
                                 // marshal the settings and properties and update the processor
                                 var updatedProcessor = marshalDetails();
@@ -658,7 +685,7 @@ nf.ProcessorConfiguration = (function () {
                                 };
 
                                 // close all fields currently being edited
-                                nf.ProcessorPropertyTable.saveRow();
+                                $('#processor-properties').propertytable('saveRow');
 
                                 // determine if changes have been made
                                 if (isSaveRequired()) {
@@ -704,30 +731,6 @@ nf.ProcessorConfiguration = (function () {
 
                 // set the button model
                 $('#processor-configuration').modal('setButtonModel', buttons);
-
-                // get the processor history
-                $.ajax({
-                    type: 'GET',
-                    url: '../nifi-api/controller/history/processors/' + encodeURIComponent(processor.id),
-                    dataType: 'json'
-                }).done(function (response) {
-                    var processorHistory = response.processorHistory;
-
-                    // record the processor history
-                    $('#processor-configuration').data('processorHistory', processorHistory);
-
-                    // show the details
-                    $('#processor-configuration').modal('show');
-
-                    // add ellipsis if necessary
-                    $('#processor-configuration div.relationship-name').ellipsis();
-
-                    // show the border if necessary
-                    var processorRelationships = $('#auto-terminate-relationship-names');
-                    if (processorRelationships.is(':visible') && processorRelationships.get(0).scrollHeight > processorRelationships.innerHeight()) {
-                        processorRelationships.css('border-width', '1px');
-                    }
-                }).fail(nf.Common.handleAjaxError);
             }
         }
     };

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-property-combo-editor.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-processor-property-combo-editor.js b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-property-combo-editor.js
index e777293..590550a 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-property-combo-editor.js
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-property-combo-editor.js
@@ -19,10 +19,16 @@ nf.ProcessorPropertyComboEditor = function (args) {
     var initialValue = null;
     var wrapper;
     var combo;
-
+    var propertyDescriptor;
+    
     this.init = function () {
         var container = $('body');
 
+        // get the property descriptor
+        var gridContainer = $(args.grid.getContainerNode());
+        var descriptors = gridContainer.data('descriptors');
+        propertyDescriptor = descriptors[args.item.property];
+
         // create the wrapper
         wrapper = $('<div></div>').css({
             'z-index': 1999,
@@ -38,13 +44,8 @@ nf.ProcessorPropertyComboEditor = function (args) {
             containment: 'parent'
         }).appendTo(container);
 
-        // identify the property descriptor - property descriptor is never null/undefined here... in order
-        // to use this editor, the property descriptor would have had to indicate a set of allowable values
-        var processorDetails = $('#processor-configuration').data('processorDetails');
-        var propertyDescriptor = processorDetails.config.descriptors[args.item.property];
-
         // check for allowable values which will drive which editor to use
-        var allowableValues = nf.ProcessorPropertyTable.getAllowableValues(propertyDescriptor);
+        var allowableValues = nf.Common.getAllowableValues(propertyDescriptor);
 
         // show the output port options
         var options = [];
@@ -131,10 +132,6 @@ nf.ProcessorPropertyComboEditor = function (args) {
     };
 
     this.loadValue = function (item) {
-        // identify the property descriptor
-        var processorDetails = $('#processor-configuration').data('processorDetails');
-        var propertyDescriptor = processorDetails.config.descriptors[item.property];
-
         // select as appropriate
         if (!nf.Common.isUndefined(item.value)) {
             initialValue = item.value;

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-property-nfel-editor.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-processor-property-nfel-editor.js b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-property-nfel-editor.js
index dc369ac..91498c3 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-property-nfel-editor.js
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-property-nfel-editor.js
@@ -23,15 +23,17 @@ nf.ProcessorPropertyNfelEditor = function (args) {
     var wrapper;
     var editor;
 
+
     this.init = function () {
         var container = $('body');
-
-        // get the property descriptor for this property
-        var details = $('#processor-configuration').data('processorDetails');
-        propertyDescriptor = details.config.descriptors[args.item.property];
+        
+        // get the property descriptor
+        var gridContainer = $(args.grid.getContainerNode());
+        var descriptors = gridContainer.data('descriptors');
+        propertyDescriptor = descriptors[args.item.property];
 
         // determine if this is a sensitive property
-        var sensitive = nf.ProcessorPropertyTable.isSensitiveProperty(propertyDescriptor);
+        var sensitive = nf.Common.isSensitiveProperty(propertyDescriptor);
 
         // record the previous value
         previousValue = args.item[args.column.field];
@@ -129,12 +131,12 @@ nf.ProcessorPropertyNfelEditor = function (args) {
     this.loadValue = function (item) {
         // determine if this is a sensitive property
         var isEmptyChecked = false;
-        var sensitive = nf.ProcessorPropertyTable.isSensitiveProperty(propertyDescriptor);
+        var sensitive = nf.Common.isSensitiveProperty(propertyDescriptor);
 
         // determine the value to use when populating the text field
         if (nf.Common.isDefinedAndNotNull(item[args.column.field])) {
             if (sensitive) {
-                initialValue = nf.ProcessorPropertyTable.config.sensitiveText;
+                initialValue = nf.Common.config.sensitiveText;
             } else {
                 initialValue = item[args.column.field];
                 isEmptyChecked = initialValue === '';
@@ -158,7 +160,7 @@ nf.ProcessorPropertyNfelEditor = function (args) {
                 return '';
             } else {
                 // otherwise if the property is required
-                if (nf.ProcessorPropertyTable.isRequiredProperty(propertyDescriptor)) {
+                if (nf.Common.isRequiredProperty(propertyDescriptor)) {
                     if (nf.Common.isBlank(propertyDescriptor.defaultValue)) {
                         return previousValue;
                     } else {

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-property-table.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-processor-property-table.js b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-property-table.js
deleted file mode 100644
index 4c04702..0000000
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-property-table.js
+++ /dev/null
@@ -1,567 +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.ProcessorPropertyTable = (function () {
-
-    /**
-     * Initialize the new property dialog.
-     */
-    var initNewPropertyDialog = function () {
-        var languageId = 'nfel';
-        var editorClass = languageId + '-editor';
-
-        // add the over state for the new property button
-        nf.Common.addHoverEffect('#add-property-icon', 'add-icon-bg', 'add-icon-bg-hover');
-
-        var add = function () {
-            var propertyName = $.trim($('#new-property-name').val());
-            var propertyValue = $('#new-property-value').nfeditor('getValue');
-
-            // ensure the property name and value is specified
-            if (propertyName !== '') {
-                // add a row for the new property
-                var propertyGrid = $('#processor-properties').data('gridInstance');
-                var propertyData = propertyGrid.getData();
-                propertyData.addItem({
-                    id: propertyData.getLength(),
-                    hidden: false,
-                    property: propertyName,
-                    displayName: propertyName,
-                    previousValue: null,
-                    value: propertyValue,
-                    type: 'userDefined'
-                });
-            } else {
-                nf.Dialog.showOkDialog({
-                    dialogContent: 'Property name must be specified.',
-                    overlayBackground: false
-                });
-            }
-
-            // close the dialog
-            $('#processor-property-dialog').hide();
-        };
-
-        var cancel = function () {
-            $('#processor-property-dialog').hide();
-        };
-
-        // create the editor
-        $('#new-property-value').addClass(editorClass).nfeditor({
-            languageId: languageId,
-            width: 318,
-            minWidth: 318,
-            height: 106,
-            minHeight: 106,
-            resizable: true,
-            escape: cancel,
-            enter: add
-        });
-
-        // add a click listener to display the new property dialog
-        $('#add-property-icon').on('click', function () {
-            // close all fields currently being edited
-            nf.ProcessorPropertyTable.saveRow();
-
-            // clear the dialog
-            $('#new-property-name').val('');
-            $('#new-property-value').nfeditor('setValue', '');
-
-            // reset the add property dialog position/size
-            $('#new-property-value').nfeditor('setSize', 318, 106);
-
-            // open the new property dialog
-            $('#processor-property-dialog').center().show();
-
-            // give the property name focus
-            $('#new-property-value').nfeditor('refresh');
-            $('#new-property-name').focus();
-        });
-
-        // make the new property dialog draggable
-        $('#processor-property-dialog').draggable({
-            cancel: 'input, textarea, pre, .button, .' + editorClass,
-            containment: 'parent'
-        }).on('click', '#new-property-ok', add).on('click', '#new-property-cancel', cancel);
-
-        // enable tabs in the property value
-        $('#new-property-name').on('keydown', function (e) {
-            if (e.which === $.ui.keyCode.ENTER && !e.shiftKey) {
-                add();
-            } else if (e.which === $.ui.keyCode.ESCAPE) {
-                e.preventDefault();
-                cancel();
-            }
-        });
-    };
-
-    /**
-     * Initializes the processor property table.
-     */
-    var initProcessorPropertiesTable = function () {
-        // function for formatting the property name
-        var nameFormatter = function (row, cell, value, columnDef, dataContext) {
-            var nameWidthOffset = 10;
-            var cellContent = $('<div></div>');
-
-            // format the contents
-            var formattedValue = $('<span/>').addClass('table-cell').text(value).appendTo(cellContent);
-            if (dataContext.type === 'required') {
-                formattedValue.addClass('required');
-            }
-
-            // get the processor details to insert the description tooltip
-            var details = $('#processor-configuration').data('processorDetails');
-            var propertyDescriptor = details.config.descriptors[dataContext.property];
-
-            // show the property description if applicable
-            if (nf.Common.isDefinedAndNotNull(propertyDescriptor)) {
-                if (!nf.Common.isBlank(propertyDescriptor.description) || !nf.Common.isBlank(propertyDescriptor.defaultValue) || !nf.Common.isBlank(propertyDescriptor.supportsEl)) {
-                    $('<img class="icon-info" src="images/iconInfo.png" alt="Info" title="" style="float: right; margin-right: 6px; margin-top: 4px;" />').appendTo(cellContent);
-                    $('<span class="hidden property-descriptor-name"></span>').text(dataContext.property).appendTo(cellContent);
-                    nameWidthOffset = 26; // 10 + icon width (10) + icon margin (6)
-                }
-            }
-
-            // adjust the width accordingly
-            formattedValue.width(columnDef.width - nameWidthOffset).ellipsis();
-
-            // return the cell content
-            return cellContent.html();
-        };
-
-        // function for formatting the property value
-        var valueFormatter = function (row, cell, value, columnDef, dataContext) {
-            var valueMarkup;
-            if (nf.Common.isDefinedAndNotNull(value)) {
-                // identify the property descriptor
-                var processorDetails = $('#processor-configuration').data('processorDetails');
-                var propertyDescriptor = processorDetails.config.descriptors[dataContext.property];
-
-                // determine if the property is sensitive
-                if (nf.ProcessorPropertyTable.isSensitiveProperty(propertyDescriptor)) {
-                    valueMarkup = '<span class="table-cell sensitive">Sensitive value set</span>';
-                } else {
-                    // if there are allowable values, attempt to swap out for the display name
-                    var allowableValues = nf.ProcessorPropertyTable.getAllowableValues(propertyDescriptor);
-                    if ($.isArray(allowableValues)) {
-                        $.each(allowableValues, function (_, allowableValue) {
-                            if (value === allowableValue.value) {
-                                value = allowableValue.displayName;
-                                return false;
-                            }
-                        });
-                    }
-
-                    if (value === '') {
-                        valueMarkup = '<span class="table-cell blank">Empty string set</span>';
-                    } else {
-                        valueMarkup = '<div class="table-cell value"><pre class="ellipsis">' + nf.Common.escapeHtml(value) + '</pre></div>';
-                    }
-                }
-            } else {
-                valueMarkup = '<span class="unset">No value set</span>';
-            }
-
-            // format the contents
-            var content = $(valueMarkup);
-            if (dataContext.type === 'required') {
-                content.addClass('required');
-            }
-            content.find('.ellipsis').width(columnDef.width - 10).ellipsis();
-
-            // return the appropriate markup
-            return $('<div/>').append(content).html();
-        };
-
-        // custom formatter for the actions column
-        var actionFormatter = function (row, cell, value, columnDef, dataContext) {
-            var markup = '';
-
-            // allow user defined properties to be removed
-            if (dataContext.type === 'userDefined') {
-                markup = '<img src="images/iconDelete.png" title="Delete" class="pointer" style="margin-top: 2px" onclick="javascript:nf.ProcessorPropertyTable.deleteProperty(\'' + row + '\');"/>';
-            }
-
-            return markup;
-        };
-
-        var processorConfigurationColumns = [
-            {id: 'property', field: 'displayName', name: 'Property', sortable: false, resizable: true, rerenderOnResize: true, formatter: nameFormatter},
-            {id: 'value', field: 'value', name: 'Value', sortable: false, resizable: true, cssClass: 'pointer', rerenderOnResize: true, formatter: valueFormatter},
-            {id: "actions", name: "&nbsp;", minWidth: 20, width: 20, formatter: actionFormatter}
-        ];
-        var processorConfigurationOptions = {
-            forceFitColumns: true,
-            enableTextSelectionOnCells: true,
-            enableCellNavigation: true,
-            enableColumnReorder: false,
-            editable: true,
-            enableAddRow: false,
-            autoEdit: false
-        };
-
-        // initialize the dataview
-        var processorConfigurationData = new Slick.Data.DataView({
-            inlineFilters: false
-        });
-        processorConfigurationData.setItems([]);
-        processorConfigurationData.setFilterArgs({
-            searchString: '',
-            property: 'hidden'
-        });
-        processorConfigurationData.setFilter(filter);
-        processorConfigurationData.getItemMetadata = function (index) {
-            var item = processorConfigurationData.getItem(index);
-
-            // identify the property descriptor
-            var processorDetails = $('#processor-configuration').data('processorDetails');
-            var propertyDescriptor = processorDetails.config.descriptors[item.property];
-
-            // support el if specified or unsure yet (likely a dynamic property)
-            if (nf.Common.isUndefinedOrNull(propertyDescriptor) || nf.ProcessorPropertyTable.supportsEl(propertyDescriptor)) {
-                return {
-                    columns: {
-                        value: {
-                            editor: nf.ProcessorPropertyNfelEditor
-                        }
-                    }
-                };
-            } else {
-                // check for allowable values which will drive which editor to use
-                var allowableValues = nf.ProcessorPropertyTable.getAllowableValues(propertyDescriptor);
-                if ($.isArray(allowableValues)) {
-                    return {
-                        columns: {
-                            value: {
-                                editor: nf.ProcessorPropertyComboEditor
-                            }
-                        }
-                    };
-                } else {
-                    return {
-                        columns: {
-                            value: {
-                                editor: nf.ProcessorPropertyTextEditor
-                            }
-                        }
-                    };
-                }
-            }
-        };
-
-        // initialize the grid
-        var processorConfigurationGrid = new Slick.Grid('#processor-properties', processorConfigurationData, processorConfigurationColumns, processorConfigurationOptions);
-        processorConfigurationGrid.setSelectionModel(new Slick.RowSelectionModel());
-        processorConfigurationGrid.onClick.subscribe(function (e, args) {
-            // edits the clicked cell
-            processorConfigurationGrid.gotoCell(args.row, args.cell, true);
-
-            // prevents standard edit logic
-            e.stopImmediatePropagation();
-        });
-
-        // wire up the dataview to the grid
-        processorConfigurationData.onRowCountChanged.subscribe(function (e, args) {
-            processorConfigurationGrid.updateRowCount();
-            processorConfigurationGrid.render();
-        });
-        processorConfigurationData.onRowsChanged.subscribe(function (e, args) {
-            processorConfigurationGrid.invalidateRows(args.rows);
-            processorConfigurationGrid.render();
-        });
-
-        // hold onto an instance of the grid and listen for mouse events to add tooltips where appropriate
-        $('#processor-properties').data('gridInstance', processorConfigurationGrid).on('mouseenter', 'div.slick-cell', function (e) {
-            var infoIcon = $(this).find('img.icon-info');
-            if (infoIcon.length && !infoIcon.data('qtip')) {
-                var property = $(this).find('span.property-descriptor-name').text();
-
-                // get the processor details to insert the description tooltip
-                var details = $('#processor-configuration').data('processorDetails');
-                var propertyDescriptor = details.config.descriptors[property];
-
-                // get the processor history
-                var processorHistory = $('#processor-configuration').data('processorHistory');
-                var propertyHistory = processorHistory.propertyHistory[property];
-
-                // format the tooltip
-                var tooltip = nf.Common.formatPropertyTooltip(propertyDescriptor, propertyHistory);
-
-                if (nf.Common.isDefinedAndNotNull(tooltip)) {
-                    infoIcon.qtip($.extend({
-                        content: tooltip
-                    }, nf.Common.config.tooltipConfig));
-                }
-            }
-        });
-    };
-
-    /**
-     * Performs the filtering.
-     * 
-     * @param {object} item     The item subject to filtering
-     * @param {object} args     Filter arguments
-     * @returns {Boolean}       Whether or not to include the item
-     */
-    var filter = function (item, args) {
-        return item.hidden === false;
-    };
-
-    return {
-        config: {
-            sensitiveText: 'Sensitive value set'
-        },
-        
-        /**
-         * Initializes the property table.
-         */
-        init: function () {
-            initNewPropertyDialog();
-            initProcessorPropertiesTable();
-        },
-        
-        /**
-         * Determines if the specified property is sensitive.
-         * 
-         * @argument {object} propertyDescriptor        The property descriptor
-         */
-        isSensitiveProperty: function (propertyDescriptor) {
-            if (nf.Common.isDefinedAndNotNull(propertyDescriptor)) {
-                return propertyDescriptor.sensitive === true;
-            } else {
-                return false;
-            }
-        },
-        
-        /**
-         * Determines if the specified property is required.
-         * 
-         * @param {object} propertyDescriptor           The property descriptor
-         */
-        isRequiredProperty: function (propertyDescriptor) {
-            if (nf.Common.isDefinedAndNotNull(propertyDescriptor)) {
-                return propertyDescriptor.required === true;
-            } else {
-                return false;
-            }
-        },
-        
-        /**
-         * Determines if the specified property is required.
-         * 
-         * @param {object} propertyDescriptor           The property descriptor
-         */
-        isDynamicProperty: function (propertyDescriptor) {
-            if (nf.Common.isDefinedAndNotNull(propertyDescriptor)) {
-                return propertyDescriptor.dynamic === true;
-            } else {
-                return false;
-            }
-        },
-        
-        /**
-         * Gets the allowable values for the specified property.
-         * 
-         * @argument {object} propertyDescriptor        The property descriptor
-         */
-        getAllowableValues: function (propertyDescriptor) {
-            if (nf.Common.isDefinedAndNotNull(propertyDescriptor)) {
-                return propertyDescriptor.allowableValues;
-            } else {
-                return null;
-            }
-        },
-        
-        /**
-         * Returns whether the specified property supports EL.
-         * 
-         * @param {object} propertyDescriptor           The property descriptor
-         */
-        supportsEl: function (propertyDescriptor) {
-            if (nf.Common.isDefinedAndNotNull(propertyDescriptor)) {
-                return propertyDescriptor.supportsEl === true;
-            } else {
-                return false;
-            }
-        },
-        
-        /**
-         * Saves the last edited row in the specified grid.
-         */
-        saveRow: function () {
-            // get the property grid to commit the current edit
-            var propertyGrid = $('#processor-properties').data('gridInstance');
-            if (nf.Common.isDefinedAndNotNull(propertyGrid)) {
-                var editController = propertyGrid.getEditController();
-                editController.commitCurrentEdit();
-            }
-        },
-        
-        /**
-         * Cancels the edit in the specified row.
-         */
-        cancelEdit: function () {
-            // get the property grid to reset the current edit
-            var propertyGrid = $('#processor-properties').data('gridInstance');
-            if (nf.Common.isDefinedAndNotNull(propertyGrid)) {
-                var editController = propertyGrid.getEditController();
-                editController.cancelCurrentEdit();
-            }
-        },
-        
-        /**
-         * Deletes the property in the specified row.
-         * 
-         * @argument {string} row         The row
-         */
-        deleteProperty: function (row) {
-            var propertyGrid = $('#processor-properties').data('gridInstance');
-            if (nf.Common.isDefinedAndNotNull(propertyGrid)) {
-                var propertyData = propertyGrid.getData();
-
-                // update the property in question
-                var property = propertyData.getItem(row);
-                property.hidden = true;
-
-                // refresh the table
-                propertyData.updateItem(property.id, property);
-            }
-        },
-        
-        /**
-         * Update the size of the grid based on its container's current size.
-         */
-        resetTableSize: function () {
-            var propertyGrid = $('#processor-properties').data('gridInstance');
-            if (nf.Common.isDefinedAndNotNull(propertyGrid)) {
-                propertyGrid.resizeCanvas();
-            }
-        },
-        
-        /**
-         * Loads the specified properties.
-         * 
-         * @argument {object} properties        The properties
-         * @argument {map} descriptors          The property descriptors (property name -> property descriptor)
-         */
-        loadProperties: function (properties, descriptors) {
-            // get the property grid
-            var propertyGrid = $('#processor-properties').data('gridInstance');
-            var propertyData = propertyGrid.getData();
-
-            // generate the processor properties
-            if (nf.Common.isDefinedAndNotNull(properties)) {
-                propertyData.beginUpdate();
-
-                var i = 0;
-                $.each(properties, function (name, value) {
-                    // get the property descriptor
-                    var descriptor = descriptors[name];
-
-                    // determine the property type
-                    var type = 'userDefined';
-                    var displayName = name;
-                    if (nf.Common.isDefinedAndNotNull(descriptor)) {
-                        if (nf.ProcessorPropertyTable.isRequiredProperty(descriptor)) {
-                            type = 'required';
-                        } else if (nf.ProcessorPropertyTable.isDynamicProperty(descriptor)) {
-                            type = 'userDefined';
-                        } else {
-                            type = 'optional';
-                        }
-
-                        // use the display name if possible
-                        displayName = descriptor.displayName;
-                        
-                        // determine the value
-                        if (nf.Common.isNull(value) && nf.Common.isDefinedAndNotNull(descriptor.defaultValue)) {
-                            value = descriptor.defaultValue;
-                        }
-                    }
-
-                    // add the row
-                    propertyData.addItem({
-                        id: i++,
-                        hidden: false,
-                        property: name,
-                        displayName: displayName,
-                        previousValue: value,
-                        value: value,
-                        type: type
-                    });
-                });
-
-                propertyData.endUpdate();
-            }
-        },
-        
-        /**
-         * Determines if a save is required.
-         */
-        isSaveRequired: function () {
-            // get the property grid
-            var propertyGrid = $('#processor-properties').data('gridInstance');
-            var propertyData = propertyGrid.getData();
-
-            // determine if any of the processor properties have changed
-            var isSaveRequired = false;
-            $.each(propertyData.getItems(), function () {
-                if (this.value !== this.previousValue) {
-                    isSaveRequired = true;
-                    return false;
-                }
-            });
-            return isSaveRequired;
-        },
-        
-        /**
-         * Marshal's the properties to send to the server.
-         */
-        marshalProperties: function () {
-            // properties
-            var properties = {};
-
-            // get the property grid data
-            var propertyGrid = $('#processor-properties').data('gridInstance');
-            var propertyData = propertyGrid.getData();
-            $.each(propertyData.getItems(), function () {
-                if (this.hidden === true) {
-                    properties[this.property] = null;
-                } else if (this.value !== this.previousValue) {
-                    properties[this.property] = this.value;
-                }
-            });
-
-            return properties;
-        },
-        
-        /**
-         * Clears the property table.
-         */
-        clear: function () {
-            var propertyGridElement = $('#processor-properties');
-            
-            // clean up any tooltips that may have been generated
-            nf.Common.cleanUpTooltips(propertyGridElement, 'img.icon-info');
-            
-            // clear the data in the grid
-            var propertyGrid = propertyGridElement.data('gridInstance');
-            var propertyData = propertyGrid.getData();
-            propertyData.setItems([]);
-        }
-    };
-}());
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-property-text-editor.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-processor-property-text-editor.js b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-property-text-editor.js
index 8b65b3f..6f84a7a 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-property-text-editor.js
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-property-text-editor.js
@@ -22,13 +22,15 @@ nf.ProcessorPropertyTextEditor = function (args) {
     var wrapper;
     var isEmpty;
     var input;
+    
 
     this.init = function () {
         var container = $('body');
 
-        // get the property descriptor for this property
-        var details = $('#processor-configuration').data('processorDetails');
-        propertyDescriptor = details.config.descriptors[args.item.property];
+        // get the property descriptor
+        var gridContainer = $(args.grid.getContainerNode());
+        var descriptors = gridContainer.data('descriptors');
+        propertyDescriptor = descriptors[args.item.property];
 
         // record the previous value
         previousValue = args.item[args.column.field];
@@ -127,12 +129,12 @@ nf.ProcessorPropertyTextEditor = function (args) {
     this.loadValue = function (item) {
         // determine if this is a sensitive property
         var isEmptyChecked = false;
-        var sensitive = nf.ProcessorPropertyTable.isSensitiveProperty(propertyDescriptor);
+        var sensitive = nf.Common.isSensitiveProperty(propertyDescriptor);
 
         // determine the value to use when populating the text field
         if (nf.Common.isDefinedAndNotNull(item[args.column.field])) {
             if (sensitive) {
-                initialValue = nf.ProcessorPropertyTable.config.sensitiveText;
+                initialValue = nf.Common.config.sensitiveText;
             } else {
                 initialValue = item[args.column.field];
                 isEmptyChecked = initialValue === '';
@@ -149,7 +151,7 @@ nf.ProcessorPropertyTextEditor = function (args) {
                 var sensitiveInput = $(this);
                 if (sensitiveInput.hasClass('sensitive')) {
                     sensitiveInput.removeClass('sensitive');
-                    if (sensitiveInput.val() === nf.ProcessorPropertyTable.config.sensitiveText) {
+                    if (sensitiveInput.val() === nf.Common.config.sensitiveText) {
                         sensitiveInput.val('');
                     }
                 }
@@ -168,7 +170,7 @@ nf.ProcessorPropertyTextEditor = function (args) {
                 return '';
             } else {
                 // otherwise if the property is required
-                if (nf.ProcessorPropertyTable.isRequiredProperty(propertyDescriptor)) {
+                if (nf.Common.isRequiredProperty(propertyDescriptor)) {
                     if (nf.Common.isBlank(propertyDescriptor.defaultValue)) {
                         return previousValue;
                     } else {

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/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/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js
index c797429..9917270 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js
@@ -178,7 +178,6 @@ nf.Settings = (function () {
     var clearSelectedControllerService = function () {
         $('#controller-service-type-description').text('');
         $('#controller-service-type-name').text('');
-        $('#controller-service-name-field').val('');
         $('#selected-controller-service-name').text('');
         $('#selected-controller-service-type').text('');
         $('#controller-service-description-container').hide();
@@ -350,6 +349,39 @@ nf.Settings = (function () {
         
         return markup;
     };
+
+    /**
+     * Adds a new controller service of the specified type.
+     * 
+     * @param {string} controllerServiceType
+     */
+    var addControllerService = function (controllerServiceType) {
+        var revision = nf.Client.getRevision();
+
+        // add the new controller service
+        var addService = $.ajax({
+            type: 'POST',
+            url: config.urls.controllerServices,
+            data: {
+                version: revision.version,
+                clientId: revision.clientId,
+                type: controllerServiceType
+            },
+            dataType: 'json'
+        }).done(function (response) {
+            var controllerService = response.controllerService;
+            if (nf.Common.isDefinedAndNotNull(controllerService)) {
+                var controllerServicesGrid = $('#controller-services-table').data('gridInstance');
+                var controllerServicesData = controllerServicesGrid.getData();
+                controllerServicesData.addItem(controllerService);
+            }
+        });
+        
+        // hide the dialog
+        $('#new-controller-service-dialog').modal('hide');
+        
+        return addService;
+    };
     
     /**
      * Initializes the new controller service dialog.
@@ -454,7 +486,6 @@ nf.Settings = (function () {
 
                     // populate the dom
                     $('#controller-service-type-name').text(controllerServiceType.label).ellipsis();
-                    $('#controller-service-name-field').val(controllerServiceType.label);
                     $('#selected-controller-service-name').text(controllerServiceType.label);
                     $('#selected-controller-service-type').text(controllerServiceType.type);
                     
@@ -480,6 +511,10 @@ nf.Settings = (function () {
                 e.stopImmediatePropagation();
             }
         });
+        controllerServiceTypesGrid.onDblClick.subscribe(function (e, args) {
+            var controllerServiceType = controllerServiceTypesGrid.getDataItem(args.row);
+            addControllerService(controllerServiceType.type);
+        });
 
         // wire up the dataview to the grid
         controllerServiceTypesData.onRowCountChanged.subscribe(function (e, args) {
@@ -567,15 +602,8 @@ nf.Settings = (function () {
                 buttonText: 'Add',
                 handler: {
                     click: function () {
-                        // add the new controller service
-                        var selectedServiceName = $('#controller-service-name-field').val();
                         var selectedServiceType = $('#selected-controller-service-type').text();
-                        
-                        $.ajax({
-                            
-                        }).done(function () {
-                            
-                        });
+                        addControllerService(selectedServiceType);
                     }
                 }
             }, {
@@ -615,12 +643,43 @@ nf.Settings = (function () {
             return '<img src="images/iconDetails.png" title="View Details" class="pointer" style="margin-top: 5px; float: left;" onclick="javascript:nf.Settings.showControllerServiceDetails(\'' + row + '\');"/>';
         };
         
+        var typeFormatter = function (row, cell, value, columnDef, dataContext) {
+            return nf.Common.substringAfterLast(value, '.');
+        };
+        
+        var enabledFormatter = function (row, cell, value, columnDef, dataContext) {
+            if (dataContext.enabled === true) {
+                return 'Enabled';
+            } else {
+                return 'Disabled';
+            }
+        };
+        
         // define the column model for the controller services table
         var controllerServicesColumns = [
-            {id: 'moreDetails', field: 'moreDetails', name: '&nbsp;', resizable: false, formatter: moreControllerServiceDetails, sortable: true, width: 50, maxWidth: 50},
+            {id: 'moreDetails', name: '&nbsp;', resizable: false, formatter: moreControllerServiceDetails, sortable: false, width: 50, maxWidth: 50},
             {id: 'name', field: 'name', name: 'Name', sortable: true, resizable: true},
-            {id: 'type', field: 'type', name: 'Type', sortable: true, resizable: true}
+            {id: 'type', field: 'type', name: 'Type', formatter: typeFormatter, sortable: true, resizable: true},
+            {id: 'enabled', field: 'enabled', name: 'State', formatter: enabledFormatter, sortable: true, resizeable: true}
         ];
+        
+        // only DFM can edit controller services
+        if (nf.Common.isDFM()) {
+            var controllerServiceActionFormatter = function (row, cell, value, columnDef, dataContext) {
+                var markup = '';
+
+                if (dataContext.enabled === true) {
+                    markup += '<img src="images/iconDisable.png" title="Disable" class="pointer" style="margin-top: 2px;" onclick="javascript:nf.Settings.disableControllerService(\'' + row + '\');"/>&nbsp;';
+                } else {
+                    markup += '<img src="images/iconEdit.png" title="Edit" class="pointer" style="margin-top: 2px;" onclick="javascript:nf.Settings.editControllerService(\'' + row + '\');"/>&nbsp;<img src="images/iconRun.png" title="Enable" class="pointer" style="margin-top: 2px;" onclick="javascript:nf.Settings.enableControllerService(\'' + row + '\');"/>&nbsp;<img src="images/iconDelete.png" title="Remove" class="pointer" style="margin-top: 2px;" onclick="javascript:nf.Settings.removeControllerService(\'' + row + '\');"/>&nbsp;';
+                }
+
+                return markup;
+            };
+            
+            controllerServicesColumns.push({id: 'actions', name: '&nbsp;', resizable: false, formatter: controllerServiceActionFormatter, sortable: false, width: 75, maxWidth: 75});
+        }
+        
         var controllerServicesOptions = {
             forceFitColumns: true,
             enableTextSelectionOnCells: true,
@@ -635,11 +694,6 @@ nf.Settings = (function () {
             inlineFilters: false
         });
         controllerServicesData.setItems([]);
-//        controllerServicesData.setFilterArgs({
-//            searchString: getControllerServiceTypeFilterText(),
-//            property: $('#controller-service-type-filter-options').combo('getSelectedOption').value
-//        });
-        controllerServicesData.setFilter(filterControllerServiceTypes);
         
         // initialize the grid
         var controllerServicesGrid = new Slick.Grid('#controller-services-table', controllerServicesData, controllerServicesColumns, controllerServicesOptions);
@@ -651,9 +705,6 @@ nf.Settings = (function () {
         controllerServicesData.onRowCountChanged.subscribe(function (e, args) {
             controllerServicesGrid.updateRowCount();
             controllerServicesGrid.render();
-
-            // update the total number of displayed processors
-//            $('#displayed-controller-service-types').text(getVisibleControllerServiceCount());
         });
         controllerServicesData.onRowsChanged.subscribe(function (e, args) {
             controllerServicesGrid.invalidateRows(args.rows);
@@ -808,6 +859,47 @@ nf.Settings = (function () {
         },
         
         /**
+         * Edits the controller service at the specified row.
+         * 
+         * @param {type} row
+         */
+        editControllerService: function (row) {
+            var grid = $('#controller-services-table').data('gridInstance');
+            if (nf.Common.isDefinedAndNotNull(grid)) {
+                var data = grid.getData();
+                var item = data.getItem(row);
+                nf.ControllerServiceConfiguration.showConfiguration(item);
+            }
+        },
+        
+        /**
+         * Enables the controller service at the specified row.
+         * 
+         * @param {type} row
+         */
+        enableControllerService: function (row) {
+            
+        },
+        
+        /**
+         * Disables the controller service at the specified row.
+         * 
+         * @param {type} row
+         */
+        disableControllerService: function (row) {
+            
+        },
+        
+        /**
+         * Removes the controller service at the specified row.
+         * 
+         * @param {type} row
+         */
+        removeControllerService: function (row) {
+            
+        },
+        
+        /**
          * Shows the details of the reporting task at the specified row.
          * 
          * @param {documentedType} row

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/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/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-common.js b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-common.js
index 171b96f..53ea076 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-common.js
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-common.js
@@ -55,6 +55,7 @@ $(document).ready(function () {
 // Define a common utility class used across the entire application.
 nf.Common = {
     config: {
+        sensitiveText: 'Sensitive value set',
         tooltipConfig: {
             style: {
                 classes: 'nifi-tooltip'
@@ -406,6 +407,71 @@ nf.Common = {
     }()),
     
     /**
+     * Determines if the specified property is sensitive.
+     * 
+     * @argument {object} propertyDescriptor        The property descriptor
+     */
+    isSensitiveProperty: function (propertyDescriptor) {
+        if (nf.Common.isDefinedAndNotNull(propertyDescriptor)) {
+            return propertyDescriptor.sensitive === true;
+        } else {
+            return false;
+        }
+    },
+
+    /**
+     * Determines if the specified property is required.
+     * 
+     * @param {object} propertyDescriptor           The property descriptor
+     */
+    isRequiredProperty: function (propertyDescriptor) {
+        if (nf.Common.isDefinedAndNotNull(propertyDescriptor)) {
+            return propertyDescriptor.required === true;
+        } else {
+            return false;
+        }
+    },
+
+    /**
+     * Determines if the specified property is required.
+     * 
+     * @param {object} propertyDescriptor           The property descriptor
+     */
+    isDynamicProperty: function (propertyDescriptor) {
+        if (nf.Common.isDefinedAndNotNull(propertyDescriptor)) {
+            return propertyDescriptor.dynamic === true;
+        } else {
+            return false;
+        }
+    },
+
+    /**
+     * Gets the allowable values for the specified property.
+     * 
+     * @argument {object} propertyDescriptor        The property descriptor
+     */
+    getAllowableValues: function (propertyDescriptor) {
+        if (nf.Common.isDefinedAndNotNull(propertyDescriptor)) {
+            return propertyDescriptor.allowableValues;
+        } else {
+            return null;
+        }
+    },
+
+    /**
+     * Returns whether the specified property supports EL.
+     * 
+     * @param {object} propertyDescriptor           The property descriptor
+     */
+    supportsEl: function (propertyDescriptor) {
+        if (nf.Common.isDefinedAndNotNull(propertyDescriptor)) {
+            return propertyDescriptor.supportsEl === true;
+        } else {
+            return false;
+        }
+    },
+    
+    /**
      * Creates a form inline in order to submit the specified params to the specified URL
      * using the specified method.
      * 

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/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/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-processor-details.js b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-processor-details.js
index a3a2589..16dd95a 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-processor-details.js
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-processor-details.js
@@ -39,7 +39,7 @@ nf.ProcessorDetails = (function () {
             var propertyDescriptor = details.config.descriptors[property.property];
 
             // ensure we're not dealing with a sensitive property
-            if (!isSensitiveProperty(propertyDescriptor)) {
+            if (!nf.Common.isSensitiveProperty(propertyDescriptor)) {
 
                 // get details about the location of the cell
                 var cellNode = $(propertyGrid.getCellNode(row, cell));
@@ -130,19 +130,6 @@ nf.ProcessorDetails = (function () {
     };
 
     /**
-     * Determines if the specified property is sensitive.
-     * 
-     * @argument {object} propertyDescriptor        The property descriptor
-     */
-    var isSensitiveProperty = function (propertyDescriptor) {
-        if (nf.Common.isDefinedAndNotNull(propertyDescriptor)) {
-            return propertyDescriptor.sensitive === true;
-        } else {
-            return false;
-        }
-    };
-
-    /**
      * Returns whether the specified property supports EL.
      * 
      * @param {object} propertyDescriptor           The property descriptor
@@ -310,7 +297,7 @@ nf.ProcessorDetails = (function () {
                     var propertyDescriptor = processorDetails.config.descriptors[dataContext.property];
 
                     // determine if the property is sensitive
-                    if (isSensitiveProperty(propertyDescriptor)) {
+                    if (nf.Common.isSensitiveProperty(propertyDescriptor)) {
                         valueMarkup = '<span class="table-cell sensitive">Sensitive value set</span>';
                     } else {
                         if (value === '') {


[3/3] incubator-nifi git commit: Merge branch 'NIFI-250' of https://git-wip-us.apache.org/repos/asf/incubator-nifi into NIFI-250

Posted by mc...@apache.org.
Merge branch 'NIFI-250' of https://git-wip-us.apache.org/repos/asf/incubator-nifi into NIFI-250


Project: http://git-wip-us.apache.org/repos/asf/incubator-nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-nifi/commit/2d7c700d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-nifi/tree/2d7c700d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-nifi/diff/2d7c700d

Branch: refs/heads/NIFI-250
Commit: 2d7c700d173e757ca51b7b9832c9b385a67061c5
Parents: ec082f1 ea17dbe
Author: Matt Gilman <ma...@gmail.com>
Authored: Tue Jan 27 13:53:02 2015 -0500
Committer: Matt Gilman <ma...@gmail.com>
Committed: Tue Jan 27 13:53:02 2015 -0500

----------------------------------------------------------------------
 .../cluster/manager/impl/WebClusterManager.java | 16 ++++
 .../nifi/controller/ReportingTaskNode.java      |  4 +-
 .../service/ControllerServiceNode.java          |  4 +-
 .../apache/nifi/controller/FlowController.java  | 40 ++++++++-
 .../nifi/controller/StandardFlowSerializer.java |  4 +-
 .../controller/StandardFlowSynchronizer.java    |  4 +-
 .../reporting/AbstractReportingTaskNode.java    |  4 +-
 .../service/StandardControllerServiceNode.java  |  4 +-
 .../ControllerServiceConfiguration.xsd          | 61 --------------
 .../src/main/resources/FlowConfiguration.xsd    | 59 +++++++++++--
 .../resources/ReportingTaskConfiguration.xsd    | 87 --------------------
 .../org/apache/nifi/web/api/dto/DtoFactory.java |  2 +-
 12 files changed, 119 insertions(+), 170 deletions(-)
----------------------------------------------------------------------



[2/3] incubator-nifi git commit: NIFI-250: - Creating a jQuery plugin for rendering a table of properties (since we now want to configure processors, controller services, and reporting tasks).

Posted by mc...@apache.org.
NIFI-250:
- Creating a jQuery plugin for rendering a table of properties (since we now want to configure processors, controller services, and reporting tasks).

Project: http://git-wip-us.apache.org/repos/asf/incubator-nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-nifi/commit/ec082f1e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-nifi/tree/ec082f1e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-nifi/diff/ec082f1e

Branch: refs/heads/NIFI-250
Commit: ec082f1eead6b37e3b26e579f958cc0cde154d22
Parents: cb84829
Author: Matt Gilman <ma...@gmail.com>
Authored: Tue Jan 27 13:52:42 2015 -0500
Committer: Matt Gilman <ma...@gmail.com>
Committed: Tue Jan 27 13:52:42 2015 -0500

----------------------------------------------------------------------
 .../nifi-framework/nifi-web/nifi-web-ui/pom.xml |   3 +-
 .../main/resources/filters/canvas.properties    |   2 +-
 .../src/main/webapp/WEB-INF/pages/canvas.jsp    |   4 +-
 .../canvas/controller-service-configuration.jsp |  80 +++
 .../canvas/new-controller-service-dialog.jsp    |   7 -
 .../canvas/new-processor-property-dialog.jsp    |  34 -
 .../partials/canvas/new-property-dialog.jsp     |  34 +
 .../partials/canvas/processor-configuration.jsp |  18 +-
 .../nifi-web-ui/src/main/webapp/css/canvas.css  |   1 +
 .../css/controller-service-configuration.css    | 120 ++++
 .../nifi-web-ui/src/main/webapp/css/dialog.css  |  10 -
 .../css/new-controller-service-dialog.css       |  10 +-
 .../main/webapp/css/processor-configuration.css |  83 ---
 .../main/webapp/images/buttonNewProperty.png    | Bin 590 -> 0 bytes
 .../src/main/webapp/images/iconUndo.png         | Bin 642 -> 0 bytes
 .../jquery/propertytable/buttonNewProperty.png  | Bin 0 -> 590 bytes
 .../propertytable/jquery.propertytable.css      | 108 ++++
 .../propertytable/jquery.propertytable.js       | 628 +++++++++++++++++++
 .../js/jquery/tagcloud/jquery.tagcloud.js       |  10 -
 .../src/main/webapp/js/nf/canvas/nf-canvas.js   |   1 +
 .../nf-controller-service-configuration.js      | 345 ++++++++++
 .../js/nf/canvas/nf-processor-configuration.js  |  81 +--
 .../nf-processor-property-combo-editor.js       |  19 +-
 .../canvas/nf-processor-property-nfel-editor.js |  18 +-
 .../js/nf/canvas/nf-processor-property-table.js | 567 -----------------
 .../canvas/nf-processor-property-text-editor.js |  16 +-
 .../src/main/webapp/js/nf/canvas/nf-settings.js | 132 +++-
 .../src/main/webapp/js/nf/nf-common.js          |  66 ++
 .../main/webapp/js/nf/nf-processor-details.js   |  17 +-
 29 files changed, 1578 insertions(+), 836 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml
index 0df26b1..cd4152f 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml
@@ -267,10 +267,10 @@
                                                 <include>${staging.dir}/js/nf/canvas/nf-canvas-toolbox.js</include>
                                                 <include>${staging.dir}/js/nf/canvas/nf-custom-processor-ui.js</include>
                                                 <include>${staging.dir}/js/nf/canvas/nf-registration.js</include>
-                                                <include>${staging.dir}/js/nf/canvas/nf-processor-property-table.js</include>
                                                 <include>${staging.dir}/js/nf/canvas/nf-processor-property-text-editor.js</include>
                                                 <include>${staging.dir}/js/nf/canvas/nf-processor-property-nfel-editor.js</include>
                                                 <include>${staging.dir}/js/nf/canvas/nf-processor-property-combo-editor.js</include>
+                                                <include>${staging.dir}/js/nf/canvas/nf-controller-service-configuration.js</include>
                                                 <include>${staging.dir}/js/nf/canvas/nf-processor-configuration.js</include>
                                                 <include>${staging.dir}/js/nf/nf-processor-details.js</include>
                                                 <include>${staging.dir}/js/nf/canvas/nf-process-group-configuration.js</include>
@@ -406,6 +406,7 @@
                                             <insertNewLine>true</insertNewLine>
                                             <output>${project.build.directory}/${project.build.finalName}/css/nf-canvas-all.css</output>
                                             <includes>
+                                                <include>${staging.dir}/css/controller-service-configuration.css</include>
                                                 <include>${staging.dir}/css/processor-configuration.css</include>
                                                 <include>${staging.dir}/css/processor-details.css</include>
                                                 <include>${staging.dir}/css/process-group-configuration.css</include>

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/filters/canvas.properties
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/filters/canvas.properties b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/filters/canvas.properties
index 056a2af..eba3a0e 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/filters/canvas.properties
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/filters/canvas.properties
@@ -24,10 +24,10 @@ nf.canvas.script.tags=<script type="text/javascript" src="js/nf/nf-namespace.js?
 <script type="text/javascript" src="js/nf/canvas/nf-canvas-toolbox.js?${project.version}"></script>\n\
 <script type="text/javascript" src="js/nf/canvas/nf-custom-processor-ui.js?${project.version}"></script>\n\
 <script type="text/javascript" src="js/nf/canvas/nf-registration.js?${project.version}"></script>\n\
-<script type="text/javascript" src="js/nf/canvas/nf-processor-property-table.js?${project.version}"></script>\n\
 <script type="text/javascript" src="js/nf/canvas/nf-processor-property-text-editor.js?${project.version}"></script>\n\
 <script type="text/javascript" src="js/nf/canvas/nf-processor-property-nfel-editor.js?${project.version}"></script>\n\
 <script type="text/javascript" src="js/nf/canvas/nf-processor-property-combo-editor.js?${project.version}"></script>\n\
+<script type="text/javascript" src="js/nf/canvas/nf-controller-service-configuration.js?${project.version}"></script>\n\
 <script type="text/javascript" src="js/nf/canvas/nf-processor-configuration.js?${project.version}"></script>\n\
 <script type="text/javascript" src="js/nf/nf-processor-details.js?${project.version}"></script>\n\
 <script type="text/javascript" src="js/nf/canvas/nf-process-group-configuration.js?${project.version}"></script>\n\

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/canvas.jsp
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/canvas.jsp b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/canvas.jsp
index 13079e5..9afc26c 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/canvas.jsp
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/canvas.jsp
@@ -29,6 +29,7 @@
         <link rel="stylesheet" href="js/jquery/nfeditor/languages/nfel.css?${project.version}" type="text/css" />
         <link rel="stylesheet" href="js/jquery/tabbs/jquery.tabbs.css?${project.version}" type="text/css" />
         <link rel="stylesheet" href="js/jquery/combo/jquery.combo.css?${project.version}" type="text/css" />
+        <link rel="stylesheet" href="js/jquery/propertytable/jquery.propertytable.css?${project.version}" type="text/css" />
         <link rel="stylesheet" href="js/jquery/tagcloud/jquery.tagcloud.css?${project.version}" type="text/css" />
         <link rel="stylesheet" href="js/jquery/modal/jquery.modal.css?${project.version}" type="text/css" />
         <link rel="stylesheet" href="js/jquery/qtip2/jquery.qtip.min.css?" type="text/css" />
@@ -46,6 +47,7 @@
         <script type="text/javascript" src="js/jquery/jquery.tab.js"></script>
         <script type="text/javascript" src="js/jquery/tabbs/jquery.tabbs.js?${project.version}"></script>
         <script type="text/javascript" src="js/jquery/combo/jquery.combo.js?${project.version}"></script>
+        <script type="text/javascript" src="js/jquery/propertytable/jquery.propertytable.js?${project.version}"></script>
         <script type="text/javascript" src="js/jquery/tagcloud/jquery.tagcloud.js?${project.version}"></script>
         <script type="text/javascript" src="js/jquery/modal/jquery.modal.js?${project.version}"></script>
         <script type="text/javascript" src="js/jquery/minicolors/jquery.minicolors.min.js"></script>
@@ -85,7 +87,6 @@
         <jsp:include page="/WEB-INF/partials/canvas/new-remote-process-group-dialog.jsp"/>
         <jsp:include page="/WEB-INF/partials/canvas/new-template-dialog.jsp"/>
         <jsp:include page="/WEB-INF/partials/canvas/instantiate-template-dialog.jsp"/>
-        <jsp:include page="/WEB-INF/partials/canvas/new-processor-property-dialog.jsp"/>
         <jsp:include page="/WEB-INF/partials/canvas/fill-color-dialog.jsp"/>
         <jsp:include page="/WEB-INF/partials/canvas/connections-dialog.jsp"/>
         <jsp:include page="/WEB-INF/partials/canvas/flow-status.jsp"/>
@@ -99,6 +100,7 @@
         <jsp:include page="/WEB-INF/partials/canvas/navigation.jsp"/>
         <jsp:include page="/WEB-INF/partials/canvas/settings-content.jsp"/>
         <jsp:include page="/WEB-INF/partials/canvas/shell.jsp"/>
+        <jsp:include page="/WEB-INF/partials/canvas/controller-service-configuration.jsp"/>
         <jsp:include page="/WEB-INF/partials/canvas/processor-configuration.jsp"/>
         <jsp:include page="/WEB-INF/partials/processor-details.jsp"/>
         <jsp:include page="/WEB-INF/partials/canvas/process-group-configuration.jsp"/>

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/controller-service-configuration.jsp
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/controller-service-configuration.jsp b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/controller-service-configuration.jsp
new file mode 100644
index 0000000..b1454c4
--- /dev/null
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/controller-service-configuration.jsp
@@ -0,0 +1,80 @@
+<%--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+--%>
+<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
+<div id="controller-service-configuration">
+    <div class="controller-service-configuration-tab-container">
+        <div id="controller-service-configuration-tabs"></div>
+        <div id="controller-service-configuration-tabs-content">
+            <div id="controller-service-standard-settings-tab-content" class="configuration-tab">
+                <div class="settings-left">
+                    <div class="setting">
+                        <div class="setting-name">Name</div>
+                        <div class="setting-field">
+                            <input type="text" id="controller-service-name" name="controller-service-name"/>
+                            <div class="controller-service-enabled-container">
+                                <div id="controller-service-enabled" class="nf-checkbox checkbox-unchecked"></div>
+                                <span> Enabled</span>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="setting">
+                        <div class="setting-name">Id</div>
+                        <div class="setting-field">
+                            <span id="controller-service-id"></span>
+                        </div>
+                    </div>
+                    <div class="setting">
+                        <div class="setting-name">Type</div>
+                        <div class="setting-field">
+                            <span id="controller-service-type"></span>
+                        </div>
+                    </div>
+                    <div class="setting">
+                        <div class="bulletin-setting">
+                            <div class="setting-name">
+                                Availability
+                                <img class="setting-icon icon-info" src="images/iconInfo.png" alt="Info" title="Where this controller service will be available."/>
+                            </div>
+                            <div class="setting-field">
+                                <div id="bulletin-level-combo"></div>
+                            </div>
+                        </div>
+                        <div class="clear"></div>
+                    </div>
+                </div>
+                <div class="spacer">&nbsp;</div>
+                <div class="settings-right">
+                    <div class="setting">
+                        <div class="setting-name">
+                            References
+                            <img class="setting-icon icon-info" src="images/iconInfo.png" alt="Info" title="Other comonents referencing this controller service."/>
+                        </div>
+                        <div class="setting-field">
+                            <div id="controller-service-references"></div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div id="controller-service-properties-tab-content" class="configuration-tab">
+                <div id="controller-service-properties"></div>
+            </div>
+            <div id="controller-service-comments-tab-content" class="configuration-tab">
+                <textarea cols="30" rows="4" id="controller-service-comments" name="controller-service-comments" class="setting-input"></textarea>
+            </div>
+        </div>
+    </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-controller-service-dialog.jsp
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-controller-service-dialog.jsp b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-controller-service-dialog.jsp
index f90ab61..b0091a2 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-controller-service-dialog.jsp
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-controller-service-dialog.jsp
@@ -39,13 +39,6 @@
             <div id="controller-service-description-container" class="hidden">
                 <div id="controller-service-type-name" class="ellipsis"></div>
                 <div id="controller-service-type-description" class="ellipsis multiline"></div>
-                <div id="controller-service-name-container">
-                    <div class="setting-name">Name</div>
-                    <div class="setting-field">
-                        <input id="controller-service-name-field" type="text"/>
-                    </div>
-                    <div class="clear"></div>
-                </div>
                 <span class="hidden" id="selected-controller-service-name"></span>
                 <span class="hidden" id="selected-controller-service-type"></span>
             </div>

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-processor-property-dialog.jsp
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-processor-property-dialog.jsp b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-processor-property-dialog.jsp
deleted file mode 100644
index 9f58c2d..0000000
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-processor-property-dialog.jsp
+++ /dev/null
@@ -1,34 +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.
---%>
-<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
-<div id="processor-property-dialog" class="dialog">
-    <div>
-        <div class="setting-name">Property name</div>
-        <div class="setting-field" id="new-property-name-container">
-            <input id="new-property-name" name="new-property-name" type="text"/>
-        </div>
-        <div class="setting-name" style="margin-top: 36px;">Property value</div>
-        <div class="setting-field">
-            <div id="new-property-value"></div>
-        </div>
-    </div>
-    <div id="new-property-button-container">
-        <div id="new-property-ok" class="button button-normal">Ok</div>
-        <div id="new-property-cancel" class="button button-normal">Cancel</div>
-        <div class="clear"></div>
-    </div>
-</div>

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-property-dialog.jsp
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-property-dialog.jsp b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-property-dialog.jsp
new file mode 100644
index 0000000..ca332b4
--- /dev/null
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-property-dialog.jsp
@@ -0,0 +1,34 @@
+<%--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+--%>
+<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
+<div id="new-property-dialog" class="dialog">
+    <div>
+        <div class="setting-name">Property name</div>
+        <div class="setting-field" id="new-property-name-container">
+            <input id="new-property-name" name="new-property-name" type="text"/>
+        </div>
+        <div class="setting-name" style="margin-top: 36px;">Property value</div>
+        <div class="setting-field">
+            <div id="new-property-value"></div>
+        </div>
+    </div>
+    <div id="new-property-button-container">
+        <div id="new-property-ok" class="button button-normal">Ok</div>
+        <div id="new-property-cancel" class="button button-normal">Cancel</div>
+        <div class="clear"></div>
+    </div>
+</div>

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/processor-configuration.jsp
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/processor-configuration.jsp b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/processor-configuration.jsp
index 9d9da2a..113f04b 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/processor-configuration.jsp
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/processor-configuration.jsp
@@ -19,7 +19,7 @@
     <div class="processor-configuration-tab-container">
         <div id="processor-configuration-tabs"></div>
         <div id="processor-configuration-tabs-content">
-            <div id="configuration-standard-settings-tab-content" class="configuration-tab">
+            <div id="processor-standard-settings-tab-content" class="configuration-tab">
                 <div class="settings-left">
                     <div class="setting">
                         <div class="setting-name">Name</div>
@@ -71,7 +71,7 @@
                                 <img class="setting-icon icon-info" src="images/iconInfo.png" alt="Info" title="The level at which this processor will generate bulletins."/>
                             </div>
                             <div class="setting-field">
-                                <div type="text" id="bulletin-level-combo"></div>
+                                <div id="bulletin-level-combo"></div>
                             </div>
                         </div>
                         <div class="clear"></div>
@@ -90,7 +90,7 @@
                     </div>
                 </div>
             </div>
-            <div id="configuration-scheduling-tab-content" class="configuration-tab">
+            <div id="processor-scheduling-tab-content" class="configuration-tab">
                 <div class="settings-left">
                     <div class="setting">
                         <div class="scheduling-strategy-setting">
@@ -194,18 +194,10 @@
                     </div>
                 </div>
             </div>
-            <div id="configuration-processor-properties-tab-content" class="configuration-tab">
-                <div id="processor-properties-header">
-                    <div id="required-property-note">Required field</div>
-                    <div id="add-property">
-                        <div id="add-property-icon" class="add-icon-bg"></div>
-                        <div id="add-text">New property</div>
-                    </div>
-                    <div class="clear"></div>
-                </div>
+            <div id="processor-properties-tab-content" class="configuration-tab">
                 <div id="processor-properties"></div>
             </div>
-            <div id="configuration-comments-tab-content" class="configuration-tab">
+            <div id="processor-comments-tab-content" class="configuration-tab">
                 <textarea cols="30" rows="4" id="processor-comments" name="processor-comments" class="setting-input"></textarea>
             </div>
         </div>

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/canvas.css
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/canvas.css b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/canvas.css
index c988234..a472a42 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/canvas.css
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/canvas.css
@@ -20,6 +20,7 @@
 @import url(process-group-configuration.css);
 @import url(process-group-details.css);
 @import url(remote-process-group-configuration.css);
+@import url(controller-service-configuration.css);
 @import url(port-configuration.css);
 @import url(port-details.css);
 @import url(label-configuration.css);

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/controller-service-configuration.css
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/controller-service-configuration.css b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/controller-service-configuration.css
new file mode 100644
index 0000000..c18a8fb
--- /dev/null
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/controller-service-configuration.css
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+/*
+    Controller service configuration styles.
+*/
+
+#controller-service-configuration {
+    position: absolute;
+    overflow: hidden;
+    width: 800px;
+    height: 450px;
+    font-size: 10px;
+    z-index: 1301;
+    display: none;
+    border: 1px solid #eee;
+}
+
+div.controller-service-configuration-tab-container {
+    margin-top: -10px;
+    padding: 5px 11px;
+}
+
+#controller-service-configuration-advanced {
+    display: none;
+}
+
+#controller-service-configuration-tabs {
+    background-color: transparent;
+    width: 778px;
+    height: 21px;
+    border-bottom: 3px solid #666;
+}
+
+#controller-service-configuration div.configuration-tab {
+    height: 320px;
+    overflow: auto;
+    padding: 10px;
+    background: #eee url(../images/bgTabContainer.png) repeat-x;
+    display: none;
+}
+
+/* controller-service settings */
+
+#controller-service-configuration div.settings-left {
+    float: left;
+    width: 330px;
+}
+
+#controller-service-configuration div.settings-right {
+    float: left;
+    width: 382px;
+}
+
+#controller-service-configuration div.spacer {
+    float: left;
+    margin-right: 40px;
+}
+
+#controller-service-configuration .setting-input {
+    font-size: 11px !important;
+    width: 320px;
+}
+
+#controller-service-configuration .small-setting-input {
+    font-size: 11px !important;
+    width: 130px;
+}
+
+#controller-service-name {
+    font-size: 11px !important;
+    width: 250px;
+    float: left;
+}
+
+#controller-service-enabled {
+    width: 12px;
+    height: 12px;
+    float: left;
+    margin-right: 4px;
+}
+
+div.controller-service-enabled-container {
+    float: left;
+    margin-top: 5px;
+    margin-left: 10px;
+}
+
+#controller-service-references {
+    border: 0 solid #CCCCCC;
+    height: 280px;
+    overflow-y: auto;
+    overflow-x: hidden;
+    padding: 2px;
+    width: 376px;
+}
+
+/*
+    Comments
+*/
+
+#controller-service-comments {
+    height: 250px;
+    width: 748px !important;
+    margin-top: 10px;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/dialog.css
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/dialog.css b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/dialog.css
index 56e6580..b7bc388 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/dialog.css
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/dialog.css
@@ -66,16 +66,6 @@
     width: 320px;
 }
 
-#processor-property-dialog {
-    z-index: 1301;
-    display: none;
-    border: 1px solid #eee;
-    padding: 10px;
-    border: 3px solid #365C6A;
-    box-shadow: 4px 4px 6px rgba(0, 0, 0, 0.9);
-    cursor: move;
-}
-
 #alias-dialog {
     z-index: 1301;
     display: none;

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/new-controller-service-dialog.css
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/new-controller-service-dialog.css b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/new-controller-service-dialog.css
index 962f2b0..9a9a199 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/new-controller-service-dialog.css
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/new-controller-service-dialog.css
@@ -56,18 +56,10 @@
 
 #controller-service-type-description {
     width: 588px;
-    max-height: 60px;
+    height: 60px;
     margin-bottom: 8px;
 }
 
-#controller-service-name-container {
-    height: 45px;
-}
-
-#controller-service-name-field {
-    width: 285px;
-}
-
 #controller-service-types-table {
     width: 586px;
     height: 249px;

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/processor-configuration.css
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/processor-configuration.css b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/processor-configuration.css
index add52e0..6d04834 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/processor-configuration.css
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/processor-configuration.css
@@ -225,89 +225,6 @@ div.relationship-description {
     float: right;
 }
 
-/* properties */
-
-#processor-properties-header {
-    margin-bottom: 10px;
-    height: 19px;
-}
-
-#add-property {
-    float: right;
-    margin-right: 20px;
-}
-
-#processor-property-dialog .nfel-editor {
-    margin-bottom: 35px;
-}
-
-#new-property-name-container {
-    position: absolute;
-    height: 25px;
-    left: 10px;
-    right: 10px;
-    padding-right: 10px;
-    overflow: hidden; 
-    margin-bottom: 10px;
-}
-
-#new-property-name {
-    height: 14px;
-    width: 100%;
-}
-
-#new-property-button-container {
-    position: absolute;
-    left: 0;
-    bottom: 0;
-    right: 0;
-    padding: 0 8px 10px;
-}
-
-#add-property-icon {
-    width: 19px;
-    height: 19px;
-    cursor: pointer;
-    float: left;
-}
-
-div.add-icon-bg {
-    background: transparent url(../images/buttonNewProperty.png) no-repeat scroll top left;
-}
-
-div.add-icon-bg-hover {
-    background: transparent url(../images/buttonNewProperty.png) no-repeat scroll top right;
-}
-
-#add-text {
-    float: left;
-    margin-left: 5px;
-    height: 19px;
-    line-height: 19px;
-}
-
-#required-property-note {
-    font-weight: bold;
-    float: left;
-    height: 19px;
-    line-height: 19px;
-    margin-left: 6px;
-}
-
-#processor-properties {
-    width: 758px;
-    height: 290px;
-    border-bottom: 1px solid #666;
-    background-color: #fff;
-}
-
-#configuration-buttons {
-    text-align: center;
-    position: absolute;
-    right: 10px;
-    bottom: 10px;
-}
-
 /*
     Styles for the processor property editor.
 */

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/images/buttonNewProperty.png
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/images/buttonNewProperty.png b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/images/buttonNewProperty.png
deleted file mode 100755
index 3e51a15..0000000
Binary files a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/images/buttonNewProperty.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/images/iconUndo.png
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/images/iconUndo.png b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/images/iconUndo.png
deleted file mode 100755
index f48895d..0000000
Binary files a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/images/iconUndo.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/propertytable/buttonNewProperty.png
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/propertytable/buttonNewProperty.png b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/propertytable/buttonNewProperty.png
new file mode 100755
index 0000000..3e51a15
Binary files /dev/null and b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/propertytable/buttonNewProperty.png differ

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/propertytable/jquery.propertytable.css
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/propertytable/jquery.propertytable.css b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/propertytable/jquery.propertytable.css
new file mode 100644
index 0000000..632ad06
--- /dev/null
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/propertytable/jquery.propertytable.css
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+/*
+    Styles for the property table.
+*/
+
+div.properties-header {
+    margin-bottom: 10px;
+    height: 19px;
+}
+
+div.required-property-note {
+    font-weight: bold;
+    float: left;
+    height: 19px;
+    line-height: 19px;
+    margin-left: 6px;
+}
+
+div.add-property {
+    float: right;
+    margin-right: 20px;
+}
+
+div.add-property-icon {
+    width: 19px;
+    height: 19px;
+    cursor: pointer;
+    float: left;
+}
+
+div.add-icon-bg {
+    background: transparent url(buttonNewProperty.png) no-repeat scroll top left;
+}
+
+div.add-icon-bg-hover {
+    background: transparent url(buttonNewProperty.png) no-repeat scroll top right;
+}
+
+div.add-property-text {
+    float: left;
+    margin-left: 5px;
+    height: 19px;
+    line-height: 19px;
+}
+
+div.property-table {
+    width: 758px;
+    height: 290px;
+    border-bottom: 1px solid #666;
+    background-color: #fff;
+}
+
+/*
+    New property dialog
+*/
+
+div.new-property-dialog {
+    z-index: 1301;
+    display: none;
+    border: 1px solid #eee;
+    padding: 10px;
+    border: 3px solid #365C6A;
+    box-shadow: 4px 4px 6px rgba(0, 0, 0, 0.9);
+    cursor: move;
+}
+
+div.new-property-dialog .nfel-editor {
+    margin-bottom: 35px;
+}
+
+div.new-property-name-container {
+    position: absolute;
+    height: 25px;
+    left: 10px;
+    right: 10px;
+    padding-right: 10px;
+    overflow: hidden; 
+    margin-bottom: 10px;
+}
+
+input.new-property-name {
+    height: 14px;
+    width: 100%;
+}
+
+div.new-property-button-container {
+    position: absolute;
+    left: 0;
+    bottom: 0;
+    right: 0;
+    padding: 0 8px 10px;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/propertytable/jquery.propertytable.js
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/propertytable/jquery.propertytable.js b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/propertytable/jquery.propertytable.js
new file mode 100644
index 0000000..479499d
--- /dev/null
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/propertytable/jquery.propertytable.js
@@ -0,0 +1,628 @@
+/*
+ * 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.
+ */
+
+/**
+ * Create a property table. The options are specified in the following
+ * format:
+ *
+ * {
+ *   tags: ['attributes', 'copy', 'regex', 'xml', 'copy', 'xml', 'attributes'],
+ *   select: selectHandler,
+ *   remove: removeHandler
+ * }
+ */
+
+/**
+ * jQuery plugin for a property table.
+ * 
+ * @param {type} $
+ */
+(function ($) {
+    var languageId = 'nfel';
+    var editorClass = languageId + '-editor';
+
+    var isUndefined = function (obj) {
+        return typeof obj === 'undefined';
+    };
+
+    var isNull = function (obj) {
+        return obj === null;
+    };
+
+    var isDefinedAndNotNull = function (obj) {
+        return !isUndefined(obj) && !isNull(obj);
+    };
+
+    var isBlank = function (str) {
+        return isUndefined(str) || isNull(str) || str === '';
+    };
+
+    var initPropertiesTable = function (table, options) {
+        // function for formatting the property name
+        var nameFormatter = function (row, cell, value, columnDef, dataContext) {
+            var nameWidthOffset = 10;
+            var cellContent = $('<div></div>');
+
+            // format the contents
+            var formattedValue = $('<span/>').addClass('table-cell').text(value).appendTo(cellContent);
+            if (dataContext.type === 'required') {
+                formattedValue.addClass('required');
+            }
+
+            // get the property descriptor
+            var descriptors = table.data('descriptors');
+            var propertyDescriptor = descriptors[dataContext.property];
+
+            // show the property description if applicable
+            if (nf.Common.isDefinedAndNotNull(propertyDescriptor)) {
+                if (!nf.Common.isBlank(propertyDescriptor.description) || !nf.Common.isBlank(propertyDescriptor.defaultValue) || !nf.Common.isBlank(propertyDescriptor.supportsEl)) {
+                    $('<img class="icon-info" src="images/iconInfo.png" alt="Info" title="" style="float: right; margin-right: 6px; margin-top: 4px;" />').appendTo(cellContent);
+                    $('<span class="hidden property-descriptor-name"></span>').text(dataContext.property).appendTo(cellContent);
+                    nameWidthOffset = 26; // 10 + icon width (10) + icon margin (6)
+                }
+            }
+
+            // adjust the width accordingly
+            formattedValue.width(columnDef.width - nameWidthOffset).ellipsis();
+
+            // return the cell content
+            return cellContent.html();
+        };
+
+        // function for formatting the property value
+        var valueFormatter = function (row, cell, value, columnDef, dataContext) {
+            var valueMarkup;
+            if (nf.Common.isDefinedAndNotNull(value)) {
+                // get the property descriptor
+                var descriptors = table.data('descriptors');
+                var propertyDescriptor = descriptors[dataContext.property];
+
+                // determine if the property is sensitive
+                if (nf.Common.isSensitiveProperty(propertyDescriptor)) {
+                    valueMarkup = '<span class="table-cell sensitive">Sensitive value set</span>';
+                } else {
+                    // if there are allowable values, attempt to swap out for the display name
+                    var allowableValues = nf.Common.getAllowableValues(propertyDescriptor);
+                    if ($.isArray(allowableValues)) {
+                        $.each(allowableValues, function (_, allowableValue) {
+                            if (value === allowableValue.value) {
+                                value = allowableValue.displayName;
+                                return false;
+                            }
+                        });
+                    }
+
+                    if (value === '') {
+                        valueMarkup = '<span class="table-cell blank">Empty string set</span>';
+                    } else {
+                        valueMarkup = '<div class="table-cell value"><pre class="ellipsis">' + nf.Common.escapeHtml(value) + '</pre></div>';
+                    }
+                }
+            } else {
+                valueMarkup = '<span class="unset">No value set</span>';
+            }
+
+            // format the contents
+            var content = $(valueMarkup);
+            if (dataContext.type === 'required') {
+                content.addClass('required');
+            }
+            content.find('.ellipsis').width(columnDef.width - 10).ellipsis();
+
+            // return the appropriate markup
+            return $('<div/>').append(content).html();
+        };
+
+        var processorConfigurationColumns = [
+            {id: 'property', field: 'displayName', name: 'Property', sortable: false, resizable: true, rerenderOnResize: true, formatter: nameFormatter},
+            {id: 'value', field: 'value', name: 'Value', sortable: false, resizable: true, cssClass: 'pointer', rerenderOnResize: true, formatter: valueFormatter}
+        ];
+        
+        if (options.readOnly !== true) {
+            // custom formatter for the actions column
+            var actionFormatter = function (row, cell, value, columnDef, dataContext) {
+                var markup = '';
+
+                // allow user defined properties to be removed
+                if (dataContext.type === 'userDefined') {
+                    markup = '<img src="images/iconDelete.png" title="Delete" class="delete-property pointer" style="margin-top: 2px" />';
+                }
+
+                return markup;
+            };
+            processorConfigurationColumns.push({id: "actions", name: "&nbsp;", minWidth: 20, width: 20, formatter: actionFormatter});
+        }
+        
+        var propertyConfigurationOptions = {
+            forceFitColumns: true,
+            enableTextSelectionOnCells: true,
+            enableCellNavigation: true,
+            enableColumnReorder: false,
+            editable: true,
+            enableAddRow: false,
+            autoEdit: false
+        };
+
+        // initialize the dataview
+        var propertyData = new Slick.Data.DataView({
+            inlineFilters: false
+        });
+        propertyData.setItems([]);
+        propertyData.setFilterArgs({
+            searchString: '',
+            property: 'hidden'
+        });
+        propertyData.setFilter(filter);
+        propertyData.getItemMetadata = function (index) {
+            var item = propertyData.getItem(index);
+
+            // get the property descriptor
+            var descriptors = table.data('descriptors');
+            var propertyDescriptor = descriptors[item.property];
+
+            // support el if specified or unsure yet (likely a dynamic property)
+            if (nf.Common.isUndefinedOrNull(propertyDescriptor) || nf.Common.supportsEl(propertyDescriptor)) {
+                return {
+                    columns: {
+                        value: {
+                            editor: nf.ProcessorPropertyNfelEditor
+                        }
+                    }
+                };
+            } else {
+                // check for allowable values which will drive which editor to use
+                var allowableValues = nf.Common.getAllowableValues(propertyDescriptor);
+                if ($.isArray(allowableValues)) {
+                    return {
+                        columns: {
+                            value: {
+                                editor: nf.ProcessorPropertyComboEditor
+                            }
+                        }
+                    };
+                } else {
+                    return {
+                        columns: {
+                            value: {
+                                editor: nf.ProcessorPropertyTextEditor
+                            }
+                        }
+                    };
+                }
+            }
+        };
+
+        // initialize the grid
+        var propertyGrid = new Slick.Grid(table, propertyData, processorConfigurationColumns, propertyConfigurationOptions);
+        propertyGrid.setSelectionModel(new Slick.RowSelectionModel());
+        propertyGrid.onClick.subscribe(function (e, args) {
+            if (propertyGrid.getColumns()[args.cell].id === 'value') {
+                // edits the clicked cell
+                propertyGrid.gotoCell(args.row, args.cell, true);
+
+                // prevents standard edit logic
+                e.stopImmediatePropagation();
+            } else if (propertyGrid.getColumns()[args.cell].id === 'actions') {
+                var target = $(e.target);
+                if (target.hasClass('delete-property')) {
+                    // mark the property in question for removal
+                    var property = propertyData.getItem(args.row);
+                    property.hidden = true;
+
+                    // refresh the table
+                    propertyData.updateItem(property.id, property);
+                    
+                    // prevents standard edit logic
+                    e.stopImmediatePropagation();
+                }
+            }
+        });
+
+        // wire up the dataview to the grid
+        propertyData.onRowCountChanged.subscribe(function (e, args) {
+            propertyGrid.updateRowCount();
+            propertyGrid.render();
+        });
+        propertyData.onRowsChanged.subscribe(function (e, args) {
+            propertyGrid.invalidateRows(args.rows);
+            propertyGrid.render();
+        });
+
+        // hold onto an instance of the grid and listen for mouse events to add tooltips where appropriate
+        table.data('gridInstance', propertyGrid).on('mouseenter', 'div.slick-cell', function (e) {
+            var infoIcon = $(this).find('img.icon-info');
+            if (infoIcon.length && !infoIcon.data('qtip')) {
+                var property = $(this).find('span.property-descriptor-name').text();
+
+                // get the property descriptor
+                var descriptors = table.data('descriptors');
+                var propertyDescriptor = descriptors[property];
+
+                // get the processor history
+                var history = table.data('history');
+                var propertyHistory = history[property];
+
+                // format the tooltip
+                var tooltip = nf.Common.formatPropertyTooltip(propertyDescriptor, propertyHistory);
+
+                if (nf.Common.isDefinedAndNotNull(tooltip)) {
+                    infoIcon.qtip($.extend({
+                        content: tooltip
+                    }, nf.Common.config.tooltipConfig));
+                }
+            }
+        });
+    };
+    
+    var saveRow = function (table) {
+        // get the property grid to commit the current edit
+        var propertyGrid = table.data('gridInstance');
+        if (nf.Common.isDefinedAndNotNull(propertyGrid)) {
+            var editController = propertyGrid.getEditController();
+            editController.commitCurrentEdit();
+        }
+    };
+    
+    /**
+     * Performs the filtering.
+     * 
+     * @param {object} item     The item subject to filtering
+     * @param {object} args     Filter arguments
+     * @returns {Boolean}       Whether or not to include the item
+     */
+    var filter = function (item, args) {
+        return item.hidden === false;
+    };
+    
+    /**
+     * Loads the specified properties.
+     * 
+     * @param {type} table 
+     * @param {type} properties
+     * @param {type} descriptors
+     * @param {type} history
+     */
+    var loadProperties = function (table, properties, descriptors, history) {
+        // save the descriptors and history
+        table.data({
+            'descriptors': descriptors,
+            'history': history
+        });
+        
+        // get the grid
+        var propertyGrid = table.data('gridInstance');
+        var propertyData = propertyGrid.getData();
+
+        // generate the properties
+        if (nf.Common.isDefinedAndNotNull(properties)) {
+            propertyData.beginUpdate();
+
+            var i = 0;
+            $.each(properties, function (name, value) {
+                // get the property descriptor
+                var descriptor = descriptors[name];
+
+                // determine the property type
+                var type = 'userDefined';
+                var displayName = name;
+                if (nf.Common.isDefinedAndNotNull(descriptor)) {
+                    if (nf.Common.isRequiredProperty(descriptor)) {
+                        type = 'required';
+                    } else if (nf.Common.isDynamicProperty(descriptor)) {
+                        type = 'userDefined';
+                    } else {
+                        type = 'optional';
+                    }
+
+                    // use the display name if possible
+                    displayName = descriptor.displayName;
+
+                    // determine the value
+                    if (nf.Common.isNull(value) && nf.Common.isDefinedAndNotNull(descriptor.defaultValue)) {
+                        value = descriptor.defaultValue;
+                    }
+                }
+
+                // add the row
+                propertyData.addItem({
+                    id: i++,
+                    hidden: false,
+                    property: name,
+                    displayName: displayName,
+                    previousValue: value,
+                    value: value,
+                    type: type
+                });
+            });
+
+            propertyData.endUpdate();
+        }
+    };
+
+    var methods = {
+        
+        /**
+         * Initializes the tag cloud.
+         * 
+         * @argument {object} options The options for the tag cloud
+         */
+        init: function (options) {
+            return this.each(function () {
+                // ensure the options have been properly specified
+                if (isDefinedAndNotNull(options)) {
+                    // get the tag cloud
+                    var propertyTableContainer = $(this);
+                    
+                    // clear any current contents, remote events, and store options
+                    propertyTableContainer.empty().unbind().data('options', options);
+
+                    // build the component
+                    var header = $('<div class="properties-header"></div>').appendTo(propertyTableContainer);
+                    $('<div class="required-property-note">Required field</div>').appendTo(header);
+                    
+                    // build the table
+                    var table = $('<div class="property-table"></div>').appendTo(propertyTableContainer);
+                    
+                    // optionally add a add new property button
+                    if (options.readOnly !== true) {
+                        // build the new property dialog
+                        var newPropertyDialogMarkup = '<div class="new-property-dialog dialog">' +
+                            '<div>' +
+                                '<div class="setting-name">Property name</div>' +
+                                '<div class="setting-field new-property-name-container">' +
+                                    '<input class="new-property-name" type="text"/>' +
+                                '</div>' +
+                                '<div class="setting-name" style="margin-top: 36px;">Property value</div>' +
+                                '<div class="setting-field">' +
+                                    '<div class="new-property-value"></div>' +
+                                '</div>' +
+                            '</div>' +
+                            '<div class="new-property-button-container">' +
+                                '<div class="new-property-ok button button-normal">Ok</div>' +
+                                '<div class="new-property-cancel button button-normal">Cancel</div>' +
+                                '<div class="clear"></div>' +
+                            '</div>' +
+                        '</div>';
+
+                        var newPropertyDialog = $(newPropertyDialogMarkup).appendTo(options.newPropertyDialogContainer);
+                        var newPropertyNameField = newPropertyDialog.find('input.new-property-name');
+                        var newPropertyValueField = newPropertyDialog.find('div.new-property-value');
+                        
+                        var add = function () {
+                            var propertyName = $.trim(newPropertyNameField.val());
+                            var propertyValue = newPropertyValueField.nfeditor('getValue');
+
+                            // ensure the property name and value is specified
+                            if (propertyName !== '') {
+                                // add a row for the new property
+                                var propertyGrid = table.data('gridInstance');
+                                var propertyData = propertyGrid.getData();
+                                propertyData.addItem({
+                                    id: propertyData.getLength(),
+                                    hidden: false,
+                                    property: propertyName,
+                                    displayName: propertyName,
+                                    previousValue: null,
+                                    value: propertyValue,
+                                    type: 'userDefined'
+                                });
+                            } else {
+                                nf.Dialog.showOkDialog({
+                                    dialogContent: 'Property name must be specified.',
+                                    overlayBackground: false
+                                });
+                            }
+
+                            // close the dialog
+                            newPropertyDialog.hide();
+                        };
+
+                        var cancel = function () {
+                            newPropertyDialog.hide();
+                        };
+                        
+                        // create the editor
+                        newPropertyValueField.addClass(editorClass).nfeditor({
+                            languageId: languageId,
+                            width: 318,
+                            minWidth: 318,
+                            height: 106,
+                            minHeight: 106,
+                            resizable: true,
+                            escape: cancel,
+                            enter: add
+                        });
+
+                        // make the new property dialog draggable
+                        newPropertyDialog.draggable({
+                            cancel: 'input, textarea, pre, .button, .' + editorClass,
+                            containment: 'body'
+                        }).on('click', 'div.new-property-ok', add).on('click', 'div.new-property-cancel', cancel);
+
+                        // enable tabs in the property value
+                        newPropertyNameField.on('keydown', function (e) {
+                            if (e.which === $.ui.keyCode.ENTER && !e.shiftKey) {
+                                add();
+                            } else if (e.which === $.ui.keyCode.ESCAPE) {
+                                e.preventDefault();
+                                cancel();
+                            }
+                        });
+                        
+                        // build the control to open the new property dialog
+                        var addProperty = $('<div class="add-property"></div>').appendTo(header);
+                        $('<div class="add-property-icon add-icon-bg"></div>').on('click', function() {
+                            // close all fields currently being edited
+                            saveRow(table);
+
+                            // clear the dialog
+                            newPropertyNameField.val('');
+                            newPropertyValueField.nfeditor('setValue', '');
+
+                            // reset the add property dialog position/size
+                            newPropertyValueField.nfeditor('setSize', 318, 106);
+
+                            // open the new property dialog
+                            newPropertyDialog.center().show();
+
+                            // give the property name focus
+                            newPropertyValueField.nfeditor('refresh');
+                            newPropertyNameField.focus();
+                        }).on('mouseenter', function () {
+                            $(this).removeClass('add-icon-bg').addClass('add-icon-bg-hover');
+                        }).on('mouseleave', function () {
+                            $(this).removeClass('add-icon-bg-hover').addClass('add-icon-bg');
+                        }).appendTo(addProperty);
+                        $('<div class="add-property-text">New property</div>').appendTo(addProperty);
+                    }
+                    $('<div class="clear"></div>').appendTo(header);
+                    
+                    // initializes the properties table
+                    initPropertiesTable(table, options);
+                }
+            });
+        },
+        
+        /**
+         * Loads the specified properties.
+         * 
+         * @argument {object} properties        The properties
+         * @argument {map} descriptors          The property descriptors (property name -> property descriptor)
+         * @argument {map} history
+         */
+        loadProperties: function (properties, descriptors, history) {
+            return this.each(function () {
+                var table = $(this).find('div.property-table');
+                loadProperties(table, properties, descriptors, history);
+            });
+        },
+        
+        /**
+         * Saves the last edited row in the specified grid.
+         */
+        saveRow: function () {
+            return this.each(function () {
+                var table = $(this).find('div.property-table');
+                saveRow(table);
+            });
+        },
+        
+        /**
+         * Update the size of the grid based on its container's current size.
+         */
+        resetTableSize: function () {
+            return this.each(function () {
+                var table = $(this).find('div.property-table');
+                var propertyGrid = table.data('gridInstance');
+                if (nf.Common.isDefinedAndNotNull(propertyGrid)) {
+                    propertyGrid.resizeCanvas();
+                }
+            });
+        },
+        
+        /**
+         * Cancels the edit in the specified row.
+         */
+        cancelEdit: function () {
+            return this.each(function () {
+                var table = $(this).find('div.property-table');
+                var propertyGrid = table.data('gridInstance');
+                if (nf.Common.isDefinedAndNotNull(propertyGrid)) {
+                    var editController = propertyGrid.getEditController();
+                    editController.cancelCurrentEdit();
+                }
+            });
+        },
+        
+        /**
+         * Clears the property table.
+         */
+        clear: function () {
+            return this.each(function () {
+                var table = $(this).find('div.property-table');
+            
+                // clean up any tooltips that may have been generated
+                nf.Common.cleanUpTooltips(table, 'img.icon-info');
+
+                // clear the data in the grid
+                var propertyGrid = table.data('gridInstance');
+                var propertyData = propertyGrid.getData();
+                propertyData.setItems([]);
+            });
+        },
+        
+        /**
+         * Determines if a save is required for the first matching element.
+         */
+        isSaveRequired: function () {
+            var isSaveRequired = false;
+            
+            this.each(function () {
+                // get the property grid
+                var table = $(this).find('div.property-table');
+                var propertyGrid = table.data('gridInstance');
+                var propertyData = propertyGrid.getData();
+
+                // determine if any of the processor properties have changed
+                $.each(propertyData.getItems(), function () {
+                    if (this.value !== this.previousValue) {
+                        isSaveRequired = true;
+                        return false;
+                    }
+                });
+                
+                return false;
+            });
+            
+            return isSaveRequired;
+        },
+        
+        /**
+         * Marshalls the properties for the first matching element.
+         */
+        marshalProperties: function () {
+            // properties
+            var properties = {};
+
+            this.each(function () {
+                // get the property grid data
+                var table = $(this).find('div.property-table');
+                var propertyGrid = table.data('gridInstance');
+                var propertyData = propertyGrid.getData();
+                $.each(propertyData.getItems(), function () {
+                    if (this.hidden === true) {
+                        properties[this.property] = null;
+                    } else if (this.value !== this.previousValue) {
+                        properties[this.property] = this.value;
+                    }
+                });
+                
+                return false;
+            });
+
+            return properties;
+        }
+    };
+
+    $.fn.propertytable = function (method) {
+        if (methods[method]) {
+            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
+        } else {
+            return methods.init.apply(this, arguments);
+        }
+    };
+})(jQuery);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/tagcloud/jquery.tagcloud.js
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/tagcloud/jquery.tagcloud.js b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/tagcloud/jquery.tagcloud.js
index 51aa7d8..525cfe9 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/tagcloud/jquery.tagcloud.js
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/tagcloud/jquery.tagcloud.js
@@ -24,16 +24,6 @@
  *   select: selectHandler,
  *   remove: removeHandler
  * }
- * 
- * Options have a label (specified as the text property that is rendered
- * to users) and a value which is not. Additionally, options can be marked
- * as disabled. A disabled option cannot be selected by a user but may be
- * programmatically selected (supporting the restoration of options that have
- * become invalid). It is up to the developer to ensure that the selected 
- * option is not disabled.
- * 
- * The optionClass option supports specifying a class to apply to the 
- * option element.
  */
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.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-canvas.js b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
index 8125219..4e2fc08 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
@@ -1005,6 +1005,7 @@ nf.Canvas = (function () {
 
                         // initialize components
                         nf.ConnectionConfiguration.init();
+                        nf.ControllerServiceConfiguration.init();
                         nf.ProcessorConfiguration.init();
                         nf.ProcessGroupConfiguration.init();
                         nf.RemoteProcessGroupConfiguration.init();

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/ec082f1e/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-service-configuration.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-configuration.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-configuration.js
new file mode 100644
index 0000000..5a3e48f
--- /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-configuration.js
@@ -0,0 +1,345 @@
+/*
+ * 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.ControllerServiceConfiguration = (function () {
+
+    /**
+     * 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 processor 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-comments').val() !== details.comments) {
+            return true;
+        }
+
+        // defer to the property and relationship grids
+        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();
+        
+        // set the properties
+        if ($.isEmptyObject(properties) === false) {
+            controllerServiceDto['properties'] = properties;
+        }
+        
+        // mark the controller service disabled if appropriate
+        if ($('#controller-service-enabled').hasClass('checkbox-unchecked')) {
+            controllerServiceDto['enabled'] = false;
+        } else if ($('#controller-service-enabled').hasClass('checkbox-checked')) {
+            controllerServiceDto['enabled'] = true;
+        }
+
+        // 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 components that reference this controller service.
+     * 
+     * @param {object} controllerService
+     */
+    var reloadControllerServiceReferences = function (controllerService) {
+        
+    };
+
+    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 processor 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 processorRelationships = $('#auto-terminate-relationship-names');
+//                    if (processorRelationships.is(':visible') && processorRelationships.get(0).scrollHeight > processorRelationships.innerHeight()) {
+//                        processorRelationships.css('border-width', '1px');
+//                    }
+                }
+            });
+
+            // initialize the processor configuration dialog
+            $('#controller-service-configuration').modal({
+                headerText: 'Configure Controller Service',
+                overlayBackground: false,
+                handler: {
+                    close: function () {
+//                        // empty the relationship list
+//                        $('#auto-terminate-relationship-names').css('border-width', '0').empty();
+
+                        // close the new property dialog if necessary
+                        $('#processor-property-dialog').hide();
+
+                        // cancel any active edits
+                        $('#controller-service-properties').propertytable('cancelEdit');
+
+                        // clear the tables
+                        $('#controller-service-properties').propertytable('clear');
+
+                        // removed the cached controller service details
+//                        $('#controller-service-configuration').removeData('processorDetails');
+//                        $('#controller-service-configuration').removeData('processorHistory');
+                    }
+                }
+            });
+
+            // initialize the property table
+            $('#controller-service-properties').propertytable({
+                readOnly: false,
+                newPropertyDialogContainer: 'body'
+            });
+        },
+        
+        /**
+         * Shows the configuration dialog for the specified controller service.
+         * 
+         * @argument {controllerService} controllerService      The controller service
+         */
+        showConfiguration: function (controllerService) {
+            // record the processor details
+            $('#controller-service-configuration').data('controllerServiceDetails', controllerService);
+
+            // determine if the enabled checkbox is checked or not
+            var controllerServiceEnableStyle = 'checkbox-checked';
+            if (controllerService['enabled'] === false) {
+                controllerServiceEnableStyle = 'checkbox-unchecked';
+            }
+
+            // populate the processor settings
+            $('#controller-service-id').text(controllerService['id']);
+            $('#controller-service-type').text(nf.Common.substringAfterLast(controllerService['type'], '.'));
+            $('#controller-service-name').val(controllerService['name']);
+            $('#controller-service-enabled').removeClass('checkbox-unchecked checkbox-checked').addClass(controllerServiceEnableStyle);
+            $('#controller-service-comments').val(controllerService['comments']);
+
+            // load the property table
+            $('#controller-service-properties').propertytable('loadProperties', controllerService.properties, controllerService.descriptors, {});
+
+            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)) {
+                                // 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.processor)) {
+//                                        // update the revision
+//                                        nf.Client.setRevision(response.revision);
+//
+//                                        // set the new processor state based on the response
+//                                        nf.Processor.set(response.processor);
+//
+//                                        // reload the processor's outgoing connections
+//                                        reloadProcessorConnections(processor);
+//
+//                                        // close the details panel
+//                                        $('#processor-configuration').modal('hide');
+//                                    }
+                                }).fail(handleControllerServiceConfigurationError);
+                            }
+                        }
+                    }
+                }, {
+                    buttonText: 'Cancel',
+                    handler: {
+                        click: function () {
+                            $('#controller-service-configuration').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
+                                $('#controller-service-configuration').modal('hide');
+
+                                // show the custom ui
+                                nf.CustomProcessorUi.showCustomUi($('#controller-service-id').text(), controllerService.customUiUrl, true).done(function () {
+//                                    // once the custom ui is closed, reload the processor
+//                                    nf.Processor.reload(processor);
+//
+//                                    // and reload the processor's outgoing connections
+//                                    reloadProcessorConnections(processor);
+                                });
+                            };
+
+                            // 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)) {
+                                            // 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);
+
+                                                    // open the custom ui
+                                                    openCustomUi();
+                                                }
+                                            }).fail(handleControllerServiceConfigurationError);
+                                        }
+                                    }
+                                });
+                            } else {
+                                // if there were no changes, simply open the custom ui
+                                openCustomUi();
+                            }
+                        }
+                    }
+                });
+            }
+
+            // set the button model
+            $('#controller-service-configuration').modal('setButtonModel', buttons);
+
+            // get the processor history
+//            $.ajax({
+//                type: 'GET',
+//                url: '../nifi-api/controller/history/processors/' + encodeURIComponent(processor.id),
+//                dataType: 'json'
+//            }).done(function (response) {
+//                var processorHistory = response.processorHistory;
+//
+//                // record the processor history
+//                $('#processor-configuration').data('processorHistory', processorHistory);
+
+                // show the details
+                $('#controller-service-configuration').modal('show');
+
+//                // show the border if necessary
+//                var processorRelationships = $('#auto-terminate-relationship-names');
+//                if (processorRelationships.is(':visible') && processorRelationships.get(0).scrollHeight > processorRelationships.innerHeight()) {
+//                    processorRelationships.css('border-width', '1px');
+//                }
+//            }).fail(nf.Common.handleAjaxError);
+        }
+    };
+}());