NIFI-250:
- Creating endpoints for returning the available controller services and 
reporting tasks.
- Made the Setting tabbed to provide a place for configuring controller 
services and reporting tasks.

NIFI-250:
- Extracting the tagcloud into a re-usable jQuery plugin.

NIFI-250:
- Creating a new controller service dialog. Dialog may be refactored into a 
reusable widget if possible.
- Loading the new controller service dialog with all available controller 
services.
- Fixing typos.


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

Branch: refs/heads/NIFI-250
Commit: b39fdbd6052adf342f72f44764145a3564669920
Parents: 52e9c4a
Author: Matt Gilman <matt.c.gil...@gmail.com>
Authored: Tue Jan 13 14:52:23 2015 -0500
Committer: Matt Gilman <matt.c.gil...@gmail.com>
Committed: Tue Jan 20 07:56:10 2015 -0500

----------------------------------------------------------------------
 .../web/api/dto/DocumentedChildTypeDTO.java     |  43 ++
 .../entity/ControllerServiceTypesEntity.java    |  46 ++
 .../api/entity/ReportingTaskTypesEntity.java    |  46 ++
 .../canvas/new-controller-service-dialog.jsp    |  48 ++
 .../css/new-controller-service-dialog.css       | 133 +++++
 .../js/jquery/tagcloud/jquery.tagcloud.css      |  62 ++
 .../js/jquery/tagcloud/jquery.tagcloud.js       | 238 ++++++++
 .../org/apache/nifi/web/NiFiServiceFacade.java  |  16 +-
 .../nifi/web/StandardNiFiServiceFacade.java     |  12 +-
 .../apache/nifi/web/api/ControllerResource.java |  68 +++
 .../org/apache/nifi/web/api/dto/DtoFactory.java |  50 ++
 .../nifi/web/controller/ControllerFacade.java   |  22 +
 .../framework/web/nifi-web-ui/pom.xml           |   1 +
 .../src/main/webapp/WEB-INF/pages/canvas.jsp    |   3 +
 .../partials/canvas/new-processor-dialog.jsp    |   6 +-
 .../partials/canvas/settings-content.jsp        |  82 +--
 .../nifi-web-ui/src/main/webapp/css/canvas.css  |   1 +
 .../nifi-web-ui/src/main/webapp/css/main.css    |   4 +
 .../main/webapp/css/new-processor-dialog.css    |  52 +-
 .../src/main/webapp/css/settings.css            |  84 ++-
 .../webapp/js/nf/canvas/nf-canvas-toolbox.js    | 166 ++----
 .../src/main/webapp/js/nf/canvas/nf-canvas.js   |   1 +
 .../src/main/webapp/js/nf/canvas/nf-settings.js | 593 ++++++++++++++++---
 23 files changed, 1483 insertions(+), 294 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/b39fdbd6/nar-bundles/framework-bundle/framework/client-dto/src/main/java/org/apache/nifi/web/api/dto/DocumentedChildTypeDTO.java
----------------------------------------------------------------------
diff --git 
a/nar-bundles/framework-bundle/framework/client-dto/src/main/java/org/apache/nifi/web/api/dto/DocumentedChildTypeDTO.java
 
b/nar-bundles/framework-bundle/framework/client-dto/src/main/java/org/apache/nifi/web/api/dto/DocumentedChildTypeDTO.java
new file mode 100644
index 0000000..af7a06b
--- /dev/null
+++ 
b/nar-bundles/framework-bundle/framework/client-dto/src/main/java/org/apache/nifi/web/api/dto/DocumentedChildTypeDTO.java
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+package org.apache.nifi.web.api.dto;
+
+import java.util.Set;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * Class used for providing documentation of a specified child type that may be
+ * instantiated. Also supports specifying what the underlying base classes are.
+ */
+@XmlType(name = "documentedChildType")
+public class DocumentedChildTypeDTO extends DocumentedTypeDTO {
+
+    private Set<String> baseTypes;
+
+    /**
+     * The type is the fully-qualified name of a Java class.
+     *
+     * @return
+     */
+    public Set<String> getBaseTypes() {
+        return baseTypes;
+    }
+
+    public void setBaseTypes(Set<String> baseTypes) {
+        this.baseTypes = baseTypes;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/b39fdbd6/nar-bundles/framework-bundle/framework/client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceTypesEntity.java
----------------------------------------------------------------------
diff --git 
a/nar-bundles/framework-bundle/framework/client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceTypesEntity.java
 
b/nar-bundles/framework-bundle/framework/client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceTypesEntity.java
new file mode 100644
index 0000000..dafb8c2
--- /dev/null
+++ 
b/nar-bundles/framework-bundle/framework/client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceTypesEntity.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+package org.apache.nifi.web.api.entity;
+
+import java.util.Set;
+import javax.xml.bind.annotation.XmlRootElement;
+import org.apache.nifi.web.api.dto.DocumentedTypeDTO;
+
+/**
+ * A serialized representation of this class can be placed in the entity body 
of
+ * a response to the API. This particular entity holds a reference to a list of
+ * controller service types.
+ */
+@XmlRootElement(name = "controllerServiceTypesEntity")
+public class ControllerServiceTypesEntity extends Entity {
+
+    private Set<DocumentedTypeDTO> controllerServiceTypes;
+
+    /**
+     * The list of controller service types that are being serialized.
+     *
+     * @return
+     */
+    public Set<DocumentedTypeDTO> getControllerServiceTypes() {
+        return controllerServiceTypes;
+    }
+
+    public void setControllerServiceTypes(Set<DocumentedTypeDTO> 
controllerServiceTypes) {
+        this.controllerServiceTypes = controllerServiceTypes;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/b39fdbd6/nar-bundles/framework-bundle/framework/client-dto/src/main/java/org/apache/nifi/web/api/entity/ReportingTaskTypesEntity.java
----------------------------------------------------------------------
diff --git 
a/nar-bundles/framework-bundle/framework/client-dto/src/main/java/org/apache/nifi/web/api/entity/ReportingTaskTypesEntity.java
 
b/nar-bundles/framework-bundle/framework/client-dto/src/main/java/org/apache/nifi/web/api/entity/ReportingTaskTypesEntity.java
new file mode 100644
index 0000000..4b021ef
--- /dev/null
+++ 
b/nar-bundles/framework-bundle/framework/client-dto/src/main/java/org/apache/nifi/web/api/entity/ReportingTaskTypesEntity.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+package org.apache.nifi.web.api.entity;
+
+import java.util.Set;
+import javax.xml.bind.annotation.XmlRootElement;
+import org.apache.nifi.web.api.dto.DocumentedTypeDTO;
+
+/**
+ * A serialized representation of this class can be placed in the entity body 
of
+ * a response to the API. This particular entity holds a reference to a list of
+ * reporting task types.
+ */
+@XmlRootElement(name = "reportingTaskTypesEntity")
+public class ReportingTaskTypesEntity extends Entity {
+
+    private Set<DocumentedTypeDTO> reportingTaskTypes;
+
+    /**
+     * The list of reporting task types that are being serialized.
+     *
+     * @return
+     */
+    public Set<DocumentedTypeDTO> getReportingTaskTypes() {
+        return reportingTaskTypes;
+    }
+
+    public void setReportingTaskTypes(Set<DocumentedTypeDTO> 
reportingTaskTypes) {
+        this.reportingTaskTypes = reportingTaskTypes;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/b39fdbd6/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-controller-service-dialog.jsp
----------------------------------------------------------------------
diff --git 
a/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-controller-service-dialog.jsp
 
b/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-controller-service-dialog.jsp
new file mode 100644
index 0000000..b896d8a
--- /dev/null
+++ 
b/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-controller-service-dialog.jsp
@@ -0,0 +1,48 @@
+<%--
+ 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-controller-service-dialog">
+    <div class="dialog-content">
+        <div id="controller-service-type-filter-controls">
+            <div id="controller-service-type-filter-container">
+                <input type="text" id="controller-service-type-filter"/>
+                <div id="controller-service-type-filter-options"></div>
+            </div>
+            <div id="controller-service-type-filter-status">
+                Displaying&nbsp;<span 
id="displayed-controller-service-types"></span>&nbsp;of&nbsp;<span 
id="total-controller-service-types"></span>
+            </div>
+        </div>
+        <div id="controller-service-tag-cloud-container">
+            <div class="setting">
+                <div class="setting-name">Tags</div>
+                <div class="setting-field">
+                    <div id="controller-service-tag-cloud"></div>
+                </div>
+            </div>
+        </div>
+        <div id="controller-service-types-container">
+            <div id="controller-service-types-table" 
class="unselectable"></div>
+            <div id="controller-service-description-container">
+                <div id="controller-service-type-name" class="ellipsis"></div>
+                <div id="controller-service-type-description" class="ellipsis 
multiline"></div>
+                <span class="hidden" 
id="selected-controller-service-name"></span>
+                <span class="hidden" 
id="selected-controller-service-type"></span>
+            </div>
+        </div>
+        <div class="clear"></div>
+    </div>
+</div>

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/b39fdbd6/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/css/new-controller-service-dialog.css
----------------------------------------------------------------------
diff --git 
a/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/css/new-controller-service-dialog.css
 
b/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/css/new-controller-service-dialog.css
new file mode 100644
index 0000000..67492ce
--- /dev/null
+++ 
b/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/css/new-controller-service-dialog.css
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+
+/* 
+    New controller dialog.
+*/
+
+#new-controller-service-dialog {
+    z-index: 1301;
+    display: none;
+    width: 800px;
+    height: 450px;
+    border: 1px solid #eee;
+    line-height: normal;
+}
+
+#controller-service-tag-cloud-container {
+    float: left;
+    width: 190px;
+    height: 350px;
+}
+
+#controller-service-types-container {
+    float: left;
+    width: 588px;
+    height: 350px;
+}
+
+#controller-service-description-container {
+    width: 588px;
+    height: 100px;
+    margin-top: 10px;
+}
+
+#controller-service-type-name {
+    font-size: 12pt;
+    font-weight: bold;
+    color: #527991;
+    margin-bottom: 8px;
+    width: 588px;
+}
+
+#controller-service-type-description {
+    width: 588px;
+    height: 60px;
+}
+
+#controller-service-types-table {
+    width: 586px;
+    height: 249px;
+    border: 1px solid #666;
+}
+
+#controller-service-types-table-container th {
+    vertical-align: middle;
+}
+
+/*
+    Processor tag cloud
+*/
+
+#controller-service-tag-cloud ul.tag-cloud {
+    max-height: 257px;
+}
+
+#controller-service-tag-cloud ul.tag-cloud li {
+    max-width: 180px;
+}
+
+#controller-service-tag-cloud div.tag-cloud-separator {
+    width: 180px;
+}
+
+#controller-service-tag-cloud ul.tag-filter li {
+    width: 180px;
+}
+
+#controller-service-tag-cloud div.selected-tag-text {
+    width: 160px;
+}
+
+/*
+    Processor type table filter
+*/
+
+#controller-service-type-filter-controls {
+    float: right;
+    margin-top: -35px;
+    margin-right: 2px;
+    margin-bottom: 7px;
+}
+
+#controller-service-type-filter-status {
+    font-size: 9px;
+    font-weight: bold;
+    color: #9f6000;
+    clear: left; 
+    line-height: normal;
+    margin-left: 5px;
+}
+
+#controller-service-type-filter {
+    padding: 3px 0px 1px 3px;
+    font-size: 12px;
+    height: 18px;
+    line-height: 20px;
+    width: 173px;
+    border: 1px solid #ccc;
+    margin-right: 3px;
+    float: left;
+}
+
+#controller-service-type-filter-options {
+    float: left;
+    height: 17px;
+    line-height: 17px;
+    width: 85px;
+    margin-top: 1px;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/b39fdbd6/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/js/jquery/tagcloud/jquery.tagcloud.css
----------------------------------------------------------------------
diff --git 
a/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/js/jquery/tagcloud/jquery.tagcloud.css
 
b/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/js/jquery/tagcloud/jquery.tagcloud.css
new file mode 100644
index 0000000..dda7474
--- /dev/null
+++ 
b/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/js/jquery/tagcloud/jquery.tagcloud.css
@@ -0,0 +1,62 @@
+/*
+ * 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 Nifi tag cloud.
+*/
+
+ul.tag-cloud {
+    font-size: 90%;
+    padding: 2px;
+    margin-left: -5px;
+    overflow: hidden;
+}
+
+ul.tag-cloud li {
+    float: left;
+    list-style-type: none;
+    margin: 0 3px;
+    height: 20px;
+    line-height: 20px;
+    overflow: hidden;
+    white-space: nowrap;
+}
+
+div.tag-cloud-separator {
+    height: 1px;
+    border-bottom: 1px solid #aaa;
+    margin: 3px 0;
+}
+
+ul.tag-filter {
+    overflow: hidden;
+}
+
+ul.tag-filter li {
+    height: 18px;
+    line-height: 18px;
+    padding: 2px;
+}
+
+div.selected-tag-text {
+    float: left;
+}
+
+img.remove-selected-tag {
+    float: right;
+    margin-top: 1px;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/b39fdbd6/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/js/jquery/tagcloud/jquery.tagcloud.js
----------------------------------------------------------------------
diff --git 
a/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/js/jquery/tagcloud/jquery.tagcloud.js
 
b/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/js/jquery/tagcloud/jquery.tagcloud.js
new file mode 100644
index 0000000..51aa7d8
--- /dev/null
+++ 
b/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/js/jquery/tagcloud/jquery.tagcloud.js
@@ -0,0 +1,238 @@
+/*
+ * 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 tag cloud. The options are specified in the following
+ * format:
+ *
+ * {
+ *   tags: ['attributes', 'copy', 'regex', 'xml', 'copy', 'xml', 'attributes'],
+ *   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.
+ */
+
+/**
+ * jQuery plugin for a NiFi style tag cloud.
+ * 
+ * @param {type} $
+ * @returns {undefined}
+ */
+(function ($) {
+
+    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 config = {
+        maxTags: 25,
+        maxTagFontSize: 2,
+        minTagFontSize: 1,
+        minWidth: 20
+    };
+    
+    /**
+     * Adds the specified tag filter.
+     * 
+     * @argument {jQuery} cloudContainer    The tag cloud container
+     * @argument {string} tag               The tag to add
+     */
+    var addTagFilter = function (cloudContainer, tag) {
+        var config = cloudContainer.data('options');
+        var tagFilter = cloudContainer.find('ul.tag-filter');
+        
+        // ensure this tag hasn't already been added
+        var tagFilterExists = false;
+        tagFilter.find('li div.selected-tag-text').each(function () {
+            if (tag === $(this).text()) {
+                tagFilterExists = true;
+                return false;
+            }
+        });
+
+        // add this tag filter if applicable
+        if (!tagFilterExists) {
+            // create the list item content
+            var tagText = $('<div class="selected-tag-text"></div>').text(tag);
+            var removeTagIcon = $('<img src="images/iconDelete.png" 
class="remove-selected-tag pointer"></img>').click(function () {
+                // remove this tag
+                $(this).closest('li').remove();
+
+                // fire a remove event if applicable
+                if (isDefinedAndNotNull(config.remove)) {
+                    config.remove.call(cloudContainer, tag);
+                }
+            });
+            var selectedTagItem = 
$('<div></div>').append(tagText).append(removeTagIcon);
+
+            // create the list item and update the tag filter list
+            $('<li></li>').append(selectedTagItem).appendTo(tagFilter);
+
+            // fire a select event if applicable
+            if (isDefinedAndNotNull(config.select)) {
+                config.select.call(cloudContainer, tag);
+            }
+        }
+    };
+
+    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) && 
isDefinedAndNotNull(options.tags)) {
+                    // get the tag cloud
+                    var cloudContainer = $(this);
+                    
+                    // clear any current contents, remote events, and store 
options
+                    cloudContainer.empty().unbind().data('options', options);
+
+                    // build the component
+                    var cloud = $('<ul 
class="tag-cloud"></ul>').appendTo(cloudContainer);
+                    $('<div 
class="tag-cloud-separator">').appendTo(cloudContainer);
+                    var filter = $('<ul 
class="tag-filter"></ul>').appendTo(cloudContainer);
+
+                    var tagCloud = {};
+                    var tags = [];
+                    
+                    // count the frequency of each tag for this type
+                    $.each(options.tags, function (i, tag) {
+                        var normalizedTagName = tag.toLowerCase();
+
+                        if 
(nf.Common.isDefinedAndNotNull(tagCloud[normalizedTagName])) {
+                            tagCloud[normalizedTagName].count = 
tagCloud[normalizedTagName].count + 1;
+                        } else {
+                            var tagCloudEntry = {
+                                term: normalizedTagName,
+                                count: 1
+                            };
+                            tags.push(tagCloudEntry);
+                            tagCloud[normalizedTagName] = tagCloudEntry;
+                        }
+                    });
+                    
+                    // handle the case when no tags are present
+                    if (tags.length > 0) {
+                        // sort the tags by frequency to limit the less 
frequent tags
+                        tags.sort(function (a, b) {
+                            return b.count - a.count;
+                        });
+
+                        // limit to the most frequest tags
+                        if (tags.length > config.maxTags) {
+                            tags = tags.slice(0, config.maxTags);
+                        }
+
+                        // determine the max frequency
+                        var maxFrequency = tags[0].count;
+
+                        // sort the tags alphabetically
+                        tags.sort(function (a, b) {
+                            var compA = a.term.toUpperCase();
+                            var compB = b.term.toUpperCase();
+                            return (compA < compB) ? -1 : (compA > compB) ? 1 
: 0;
+                        });
+
+                        // set the tag content
+                        $.each(tags, function (i, tag) {
+                            // determine the appropriate font size
+                            var fontSize = Math.log(tag.count) / 
Math.log(maxFrequency) * (config.maxTagFontSize - config.minTagFontSize) + 
config.minTagFontSize;
+                            var minWidth = config.minWidth * fontSize;
+
+                            // create the tag cloud entry
+                            $('<li></li>').append($('<span 
class="link"></span>').text(tag.term).css({
+                                'font-size': fontSize + 'em'
+                            })).css({
+                                'min-width': minWidth + 'px'
+                            }).click(function () {
+                                // ensure we don't exceed 5 selected
+                                if (filter.children('li').length < 5) {
+                                    var tagText = 
$(this).children('span').text();
+                                    addTagFilter(cloudContainer, tagText);
+                                }
+                            }).appendTo(cloud).ellipsis();
+                        });
+                    } else {
+                        // indicate when no tags are found
+                        $('<li><span class="unset">No tags 
specified</span></li>').appendTo(cloud);
+                    }
+                }
+            });
+        },
+        
+        /**
+         * Resets the selected tags from the tag cloud.
+         */
+        clearSelectedTags: function () {
+            return this.each(function() {
+                var cloudContainer = $(this);
+                
cloudContainer.find('img.remove-selected-tag').trigger('click');
+            });
+        },
+        
+        /**
+         * Returns the selected tags of the first matching element.
+         */
+        getSelectedTags: function () {
+            var tags = [];
+
+            this.each(function () {
+                var cloudContainer = $(this);
+                cloudContainer.find('div.selected-tag-text').each(function() {
+                    tags.push($(this).text());
+                });
+            });
+
+            return tags;
+        }
+    };
+
+    $.fn.tagcloud = 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/b39fdbd6/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
----------------------------------------------------------------------
diff --git 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
index ae6bf28..b0001ec 100644
--- 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
+++ 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
@@ -243,7 +243,21 @@ public interface NiFiServiceFacade {
      * @return The list of available processor types
      */
     Set<DocumentedTypeDTO> getProcessorTypes();
-
+    
+    /**
+     * Returns the list of controller service types.
+     * 
+     * @return The list of available controller types
+     */
+    Set<DocumentedTypeDTO> getControllerServiceTypes();
+    
+    /**
+     * Returns the list of reporting task types.
+     * 
+     * @return The list of available reporting task types
+     */
+    Set<DocumentedTypeDTO> getReportingTaskTypes();
+    
     /**
      * Returns the list of prioritizer types.
      *

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/b39fdbd6/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
----------------------------------------------------------------------
diff --git 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
index c8683b0..41660f2 100644
--- 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
+++ 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
@@ -16,8 +16,6 @@
  */
 package org.apache.nifi.web;
 
-import org.apache.nifi.web.OptimisticLockingManager;
-import org.apache.nifi.web.ConfigurationSnapshot;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -1640,6 +1638,16 @@ public class StandardNiFiServiceFacade implements 
NiFiServiceFacade {
     }
 
     @Override
+    public Set<DocumentedTypeDTO> getControllerServiceTypes() {
+        return controllerFacade.getControllerServiceTypes();
+    }
+
+    @Override
+    public Set<DocumentedTypeDTO> getReportingTaskTypes() {
+        return controllerFacade.getReportingTaskTypes();
+    }
+
+    @Override
     public ProcessorDTO getProcessor(String groupId, String id) {
         final ProcessorNode processor = processorDAO.getProcessor(groupId, id);
         final ProcessorDTO processorDto = 
dtoFactory.createProcessorDto(processor);

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/b39fdbd6/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
----------------------------------------------------------------------
diff --git 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
index 3afe0e1..d13e4ce 100644
--- 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
+++ 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
@@ -72,6 +72,8 @@ import org.apache.nifi.web.api.request.ClientIdParameter;
 import org.apache.nifi.web.api.request.IntegerParameter;
 import org.apache.nifi.web.api.request.LongParameter;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.web.api.entity.ControllerServiceTypesEntity;
+import org.apache.nifi.web.api.entity.ReportingTaskTypesEntity;
 import org.codehaus.enunciate.jaxrs.TypeHint;
 import org.springframework.security.access.prepost.PreAuthorize;
 
@@ -713,6 +715,72 @@ public class ControllerResource extends 
ApplicationResource {
         // generate the response
         return clusterContext(generateOkResponse(entity)).build();
     }
+    
+    /**
+     * Retrieves the types of controller services that this NiFi supports.
+     *
+     * @param clientId Optional client id. If the client id is not specified, a
+     * new one will be generated. This value (whether specified or generated) 
is
+     * included in the response.
+     * @return A controllerServicesTypesEntity.
+     */
+    @GET
+    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+    @Path("/controller-service-types")
+    @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
+    @TypeHint(ControllerServiceTypesEntity.class)
+    public Response getControllerServiceTypes(@QueryParam(CLIENT_ID) 
@DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId) {
+
+        // replicate if cluster manager
+        if (properties.isClusterManager()) {
+            return clusterManager.applyRequest(HttpMethod.GET, 
getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse();
+        }
+
+        // create the revision
+        final RevisionDTO revision = new RevisionDTO();
+        revision.setClientId(clientId.getClientId());
+
+        // create response entity
+        final ControllerServiceTypesEntity entity = new 
ControllerServiceTypesEntity();
+        entity.setRevision(revision);
+        
entity.setControllerServiceTypes(serviceFacade.getControllerServiceTypes());
+
+        // generate the response
+        return clusterContext(generateOkResponse(entity)).build();
+    }
+    
+    /**
+     * Retrieves the types of reporting tasks that this NiFi supports.
+     *
+     * @param clientId Optional client id. If the client id is not specified, a
+     * new one will be generated. This value (whether specified or generated) 
is
+     * included in the response.
+     * @return A controllerServicesTypesEntity.
+     */
+    @GET
+    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+    @Path("/reporting-task-types")
+    @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
+    @TypeHint(ReportingTaskTypesEntity.class)
+    public Response getReportingTaskTypes(@QueryParam(CLIENT_ID) 
@DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId) {
+
+        // replicate if cluster manager
+        if (properties.isClusterManager()) {
+            return clusterManager.applyRequest(HttpMethod.GET, 
getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse();
+        }
+
+        // create the revision
+        final RevisionDTO revision = new RevisionDTO();
+        revision.setClientId(clientId.getClientId());
+
+        // create response entity
+        final ReportingTaskTypesEntity entity = new ReportingTaskTypesEntity();
+        entity.setRevision(revision);
+        
entity.setReportingTaskTypes(serviceFacade.getControllerServiceTypes());
+
+        // generate the response
+        return clusterContext(generateOkResponse(entity)).build();
+    }
 
     /**
      * Retrieves the types of prioritizers that this NiFi supports.

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/b39fdbd6/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java
----------------------------------------------------------------------
diff --git 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java
 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java
index 9a2dc30..30abaf8 100644
--- 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java
+++ 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java
@@ -1128,6 +1128,56 @@ public final class DtoFactory {
 
         return types;
     }
+    
+    /**
+     * Identifies all baseTypes for the specified type that are assignable to 
the specified baseType.
+     * 
+     * @param baseType
+     * @param type
+     * @param baseTypes 
+     */
+    private void identifyBaseTypes(final Class baseType, final Class type, 
final Set<String> baseTypes) {
+        final Class[] interfaces = type.getInterfaces();
+        for (final Class i : interfaces) {
+            if (baseType.isAssignableFrom(i) && !baseType.equals(i)) {
+                baseTypes.add(i.getName());
+            }
+        }
+        
+        if (type.getSuperclass() != null) {
+            identifyBaseTypes(baseType, type.getSuperclass(), baseTypes);
+        }
+    }
+    
+    /**
+     * Gets the DocumentedTypeDTOs from the specified classes for the 
specified baseClass.
+     *
+     * @param baseClass
+     * @param classes
+     * @return
+     */
+    public Set<DocumentedTypeDTO> fromDocumentedTypes(final Class baseClass, 
final Set<Class> classes) {
+        final Set<DocumentedTypeDTO> types = new LinkedHashSet<>();
+        final Set<Class> sortedClasses = new TreeSet<>(CLASS_NAME_COMPARATOR);
+        sortedClasses.addAll(classes);
+
+        for (final Class<?> cls : sortedClasses) {
+            final DocumentedChildTypeDTO type = new DocumentedChildTypeDTO();
+            type.setType(cls.getName());
+            type.setDescription(getCapabilityDescription(cls));
+            type.setTags(getTags(cls));
+            
+            // identify the base types
+            final Set<String> baseTypes = new LinkedHashSet<>();
+            identifyBaseTypes(baseClass, cls, baseTypes);
+            type.setBaseTypes(baseTypes);
+            
+            // add this type
+            types.add(type);
+        }
+
+        return types;
+    }
 
     /**
      * Creates a ProcessorDTO from the specified ProcessorNode.

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/b39fdbd6/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java
----------------------------------------------------------------------
diff --git 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java
 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java
index dbc4b3c..a9ad968 100644
--- 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java
+++ 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java
@@ -114,6 +114,8 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.admin.service.UserService;
 import org.apache.nifi.authorization.DownloadAuthorization;
 import org.apache.nifi.processor.DataUnit;
+import org.apache.nifi.reporting.ReportingTask;
+import org.apache.nifi.web.api.dto.DocumentedChildTypeDTO;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.security.access.AccessDeniedException;
@@ -347,6 +349,24 @@ public class ControllerFacade implements 
ControllerServiceProvider {
     public Set<DocumentedTypeDTO> getFlowFileComparatorTypes() {
         return 
dtoFactory.fromDocumentedTypes(ExtensionManager.getExtensions(FlowFilePrioritizer.class));
     }
+    
+    /**
+     * Gets the ControllerService types that this controller supports.
+     * 
+     * @return 
+     */
+    public Set<DocumentedTypeDTO> getControllerServiceTypes() {
+        return dtoFactory.fromDocumentedTypes(ControllerService.class, 
ExtensionManager.getExtensions(ControllerService.class));
+    }
+    
+    /**
+     * Gets the ReportingTask types that this controller supports.
+     * 
+     * @return 
+     */
+    public Set<DocumentedTypeDTO> getReportingTaskTypes() {
+        return dtoFactory.fromDocumentedTypes(ReportingTask.class, 
ExtensionManager.getExtensions(ReportingTask.class));
+    }
 
     /**
      * Gets the counters for this controller.
@@ -371,6 +391,8 @@ public class ControllerFacade implements 
ControllerServiceProvider {
 
         return counter;
     }
+    
+    
 
     /**
      * Return the controller service for the specified identifier.

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/b39fdbd6/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/pom.xml
----------------------------------------------------------------------
diff --git 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/pom.xml 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/pom.xml
index cffefaf..de48029 100644
--- a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/pom.xml
+++ b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/pom.xml
@@ -422,6 +422,7 @@
                                                 
<include>${staging.dir}/css/registration.css</include>
                                                 
<include>${staging.dir}/css/dialog.css</include>
                                                 
<include>${staging.dir}/css/new-processor-dialog.css</include>
+                                                
<include>${staging.dir}/css/new-controller-service-dialog.css</include>
                                                 
<include>${staging.dir}/css/graph.css</include>
                                                 
<include>${staging.dir}/css/header.css</include>
                                                 
<include>${staging.dir}/css/main.css</include>

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/b39fdbd6/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/WEB-INF/pages/canvas.jsp
----------------------------------------------------------------------
diff --git 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/WEB-INF/pages/canvas.jsp
 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/WEB-INF/pages/canvas.jsp
index ba65475..13079e5 100644
--- 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/WEB-INF/pages/canvas.jsp
+++ 
b/nifi/nar-bundles/framework-bundle/framework/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/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" />
         <link rel="stylesheet" 
href="js/jquery/ui-smoothness/jquery-ui-1.10.4.min.css" type="text/css" />
@@ -45,6 +46,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/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>
         <script type="text/javascript" 
src="js/jquery/qtip2/jquery.qtip.min.js"></script>
@@ -76,6 +78,7 @@
         <jsp:include page="/WEB-INF/partials/ok-dialog.jsp"/>
         <jsp:include page="/WEB-INF/partials/yes-no-dialog.jsp"/>
         <jsp:include page="/WEB-INF/partials/status-history-dialog.jsp"/>
+        <jsp:include 
page="/WEB-INF/partials/canvas/new-controller-service-dialog.jsp"/>
         <jsp:include page="/WEB-INF/partials/canvas/new-processor-dialog.jsp"/>
         <jsp:include page="/WEB-INF/partials/canvas/new-port-dialog.jsp"/>
         <jsp:include 
page="/WEB-INF/partials/canvas/new-process-group-dialog.jsp"/>

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/b39fdbd6/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-processor-dialog.jsp
----------------------------------------------------------------------
diff --git 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-processor-dialog.jsp
 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-processor-dialog.jsp
index 29b57c9..df7766c 100644
--- 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-processor-dialog.jsp
+++ 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/new-processor-dialog.jsp
@@ -26,13 +26,11 @@
                 Displaying&nbsp;<span 
id="displayed-processor-types"></span>&nbsp;of&nbsp;<span 
id="total-processor-types"></span>
             </div>
         </div>
-        <div id="tag-cloud-container">
+        <div id="processor-tag-cloud-container">
             <div class="setting">
                 <div class="setting-name">Tags</div>
                 <div class="setting-field">
-                    <ul id="tag-cloud"></ul>
-                    <div id="tag-cloud-separator"></div>
-                    <ul id="tag-filter"></ul>
+                    <div id="processor-tag-cloud"></div>
                 </div>
             </div>
         </div>

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/b39fdbd6/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/settings-content.jsp
----------------------------------------------------------------------
diff --git 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/settings-content.jsp
 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/settings-content.jsp
index d9b2f29..b235bdf 100644
--- 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/settings-content.jsp
+++ 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/settings-content.jsp
@@ -18,43 +18,59 @@
 <div id="settings">
     <div id="settings-header-text">NiFi Settings</div>
     <div id="settings-container">
-        <div id="general-settings">
-            <div class="setting">
-                <div class="setting-name">Data flow name</div>
-                <div class="setting-field">
-                    <input type="text" id="data-flow-title-field" 
name="data-flow-title" class="setting-input"/>
-                    <span id="archive-flow-link" class="link">Back-up 
flow</span>
-                    <img class="setting-icon icon-info" 
src="images/iconInfo.png" alt="Info" title="Archives the flow configuration."/>
-                </div>
-            </div>
-            <div class="setting">
-                <div class="setting-name">Data flow comments</div>
-                <div class="setting-field">
-                    <textarea id="data-flow-comments-field" 
name="data-flow-comments" class="setting-input"></textarea>
+        <div id="settings-tabs-container">
+            <div id="settings-tabs"></div>
+            <div id="new-service-or-task" class="add-icon-bg"></div>
+            <div class="clear"></div>
+        </div>
+        <div id="settings-tab-background"></div>
+        <div id="settings-tabs-content">
+            <div id="general-settings-tab-content" class="configuration-tab">
+                <div id="general-settings">
+                    <div class="setting">
+                        <div class="setting-name">Data flow name</div>
+                        <div class="setting-field">
+                            <input type="text" id="data-flow-title-field" 
name="data-flow-title" class="setting-input"/>
+                            <span id="archive-flow-link" class="link">Back-up 
flow</span>
+                            <img class="setting-icon icon-info" 
src="images/iconInfo.png" alt="Info" title="Archives the flow configuration."/>
+                        </div>
+                    </div>
+                    <div class="setting">
+                        <div class="setting-name">Data flow comments</div>
+                        <div class="setting-field">
+                            <textarea id="data-flow-comments-field" 
name="data-flow-comments" class="setting-input"></textarea>
+                        </div>
+                    </div>
+                    <div class="setting">
+                        <div class="setting-name">
+                            Maximum timer driven thread count
+                            <img class="setting-icon icon-info" 
src="images/iconInfo.png" alt="Info" title="The maximum number of threads for 
timer driven processors available to the system."/>
+                        </div>
+                        <div class="setting-field">
+                            <input type="text" 
id="maximum-timer-driven-thread-count-field" class="setting-input"/>
+                        </div>
+                    </div>
+                    <div class="setting">
+                        <div class="setting-name">
+                            Maximum event driven thread count
+                            <img class="setting-icon icon-info" 
src="images/iconInfo.png" alt="Info" title="The maximum number of threads for 
event driven processors available to the system."/>
+                        </div>
+                        <div class="setting-field">
+                            <input type="text" 
id="maximum-event-driven-thread-count-field" class="setting-input"/>
+                        </div>
+                    </div>
+                    <div id="settings-buttons">
+                        <div id="settings-save" class="button">Apply</div>
+                        <div class="clear"></div>
+                    </div>
                 </div>
             </div>
-            <div class="setting">
-                <div class="setting-name">
-                    Maximum timer driven thread count
-                    <img class="setting-icon icon-info" 
src="images/iconInfo.png" alt="Info" title="The maximum number of threads for 
timer driven processors available to the system."/>
-                </div>
-                <div class="setting-field">
-                    <input type="text" 
id="maximum-timer-driven-thread-count-field" class="setting-input"/>
-                </div>
+            <div id="controller-services-tab-content" 
class="configuration-tab">
+                <div id="controller-services-table" 
class="settings-table"></div>
             </div>
-            <div class="setting">
-                <div class="setting-name">
-                    Maximum event driven thread count
-                    <img class="setting-icon icon-info" 
src="images/iconInfo.png" alt="Info" title="The maximum number of threads for 
event driven processors available to the system."/>
-                </div>
-                <div class="setting-field">
-                    <input type="text" 
id="maximum-event-driven-thread-count-field" class="setting-input"/>
-                </div>
+            <div id="reporting-tasks-tab-content" class="configuration-tab">
+                <div id="reporting-tasks-table" class="settings-table"></div>
             </div>
         </div>
-        <div id="settings-buttons">
-            <div id="settings-cancel" class="button">Cancel</div>
-            <div id="settings-save" class="button">Apply</div>
-        </div>
     </div>
 </div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/b39fdbd6/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/css/canvas.css
----------------------------------------------------------------------
diff --git 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/css/canvas.css
 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/css/canvas.css
index cac2a3d..c988234 100644
--- 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/css/canvas.css
+++ 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/css/canvas.css
@@ -29,6 +29,7 @@
 @import url(registration.css);
 @import url(dialog.css);
 @import url(new-processor-dialog.css);
+@import url(new-controller-service-dialog.css);
 @import url(graph.css);
 @import url(header.css);
 @import url(main.css);

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/b39fdbd6/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/css/main.css
----------------------------------------------------------------------
diff --git 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/css/main.css
 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/css/main.css
index 3afdc12..2724f71 100644
--- 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/css/main.css
+++ 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/css/main.css
@@ -126,6 +126,10 @@ div.nifi-tooltip {
     white-space: normal;
 }
 
+input.filter-list {
+    color: #888;
+}
+
 .table-cell {
     overflow: hidden;
     white-space: nowrap;

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/b39fdbd6/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/css/new-processor-dialog.css
----------------------------------------------------------------------
diff --git 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/css/new-processor-dialog.css
 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/css/new-processor-dialog.css
index 5456dea..a1c77f8 100644
--- 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/css/new-processor-dialog.css
+++ 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/css/new-processor-dialog.css
@@ -27,7 +27,7 @@
     line-height: normal;
 }
 
-#tag-cloud-container {
+#processor-tag-cloud-container {
     float: left;
     width: 190px;
     height: 350px;
@@ -69,56 +69,29 @@
 }
 
 /*
-    Tag cloud
+    Processor tag cloud
 */
 
-#tag-cloud {
-    font-size: 90%;
-    padding: 2px;
-    margin-left: -5px;
+#processor-tag-cloud ul.tag-cloud {
     max-height: 257px;
-    overflow: hidden;
 }
 
-#tag-cloud li {
-    float: left;
-    list-style-type: none;
-    margin: 0 3px;
-    height: 20px;
-    line-height: 20px;
+#processor-tag-cloud ul.tag-cloud li {
     max-width: 180px;
-    overflow: hidden;
-    white-space: nowrap;
 }
 
-#tag-cloud-separator {
+#processor-tag-cloud div.tag-cloud-separator {
     width: 180px;
-    height: 1px;
-    border-bottom: 1px solid #aaa;
-    margin: 3px 0;
-}
-
-#tag-filter {
-    overflow: hidden;
 }
 
-#tag-filter li {
-    width: 185px;
-    height: 18px;
-    line-height: 18px;
-    padding: 2px;
+#processor-tag-cloud ul.tag-filter li {
+    width: 180px;
 }
 
-div.selected-tag-text {
-    float: left;
+#processor-tag-cloud div.selected-tag-text {
     width: 160px;
 }
 
-img.remove-selected-tag {
-    float: left;
-    margin-top: 1px;
-}
-
 /*
     Processor type table filter
 */
@@ -150,19 +123,10 @@ img.remove-selected-tag {
     float: left;
 }
 
-input.filter-list {
-    color: #888;
-}
-
 #processor-type-filter-options {
     float: left;
     height: 17px;
     line-height: 17px;
     width: 85px;
     margin-top: 1px;
-}
-
-.no-select {
-    -webkit-user-select: none;
-    -moz-user-select: none;
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/b39fdbd6/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/css/settings.css
----------------------------------------------------------------------
diff --git 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/css/settings.css
 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/css/settings.css
index e9d78d4..0622aa9 100644
--- 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/css/settings.css
+++ 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/css/settings.css
@@ -21,23 +21,93 @@
     bottom: 0px;
     left: 0px;
     display: none;
+    padding: 20px;
 }
 
 #settings-header-text {
     height: 35px;
-    margin-top: 20px;
-    margin-left: 20px;
     font-size: 16px;
     font-weight: bold;
 }
 
 #settings-container {
-    margin-top: -10px;
+    margin-top: 18px;
 }
 
+#new-service-or-task {
+    float: right;
+    width: 19px;
+    height: 19px;
+    margin-top: 4px;
+    cursor: pointer;
+}
+
+/* settings tabs */
+
+#settings-tabs-container {
+    border-bottom: 2px solid #666;
+}
+
+#settings-tabs {
+    float: left;
+}
+
+.settings-tab {
+    display: block;
+    padding: 0 5px;
+    height: 26px;
+    float: left;
+    color: #666;
+    background-color: #ccc;
+    border-left: 1px solid #b5b5b5;
+    border-top: 1px solid #b5b5b5;
+    border-right: 1px solid #b5b5b5;
+    margin-right: 5px;
+    text-align: center;
+    cursor: pointer;
+    line-height: 26px;
+    font-weight: bold;
+}
+
+.settings-selected-tab {
+    color: #fff;
+    background-color: #666;
+    border-left: 1px solid #666;
+    border-top: 1px solid #666;
+    border-right: 1px solid #666;
+}
+
+#settings-tab-background {
+    height: 200px;
+    margin-top: 1px;
+    background-color: transparent;
+    background: linear-gradient(to bottom, #dddddd, #ffffff);
+    filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, 
startColorstr=#dddddd, endColorstr=#ffffff);
+}
+
+#settings div.configuration-tab {
+    display: none;
+}
+
+div.settings-table {
+    position: absolute;
+    top: 115px;
+    left: 25px;
+    bottom: 20px;
+    right: 25px;
+    border: 1px solid #666;
+    overflow: hidden;
+    background-color: #fff;
+}
+
+span.sorted {
+    text-decoration: underline;
+}
+
+/* general */
+
 #general-settings {
-    padding-left: 10px;
-    margin-top: 15px;
+    margin-top: -190px;
     margin-left: 10px;
 }
 
@@ -53,11 +123,11 @@
 }
 
 #settings-buttons {
-    margin-left: 260px;
+    margin-left: 304px;
     margin-top: 10px;
 }
 
-#settings-save, #settings-cancel {
+#settings-save {
     float: left;
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/b39fdbd6/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-toolbox.js
----------------------------------------------------------------------
diff --git 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-toolbox.js
 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-toolbox.js
index ee91107..bcb7c40 100644
--- 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-toolbox.js
+++ 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-toolbox.js
@@ -17,13 +17,6 @@
 nf.CanvasToolbox = (function () {
 
     var config = {
-        /**
-         * Tag properties configuration.
-         */
-        maxTags: 25,
-        maxTagFontSize: 2,
-        minTagFontSize: 1,
-        minWidth: 20,
         filterText: 'Filter',
         type: {
             processor: 'Processor',
@@ -71,7 +64,7 @@ nf.CanvasToolbox = (function () {
                 return $('<div 
class="toolbox-icon"></div>').addClass(dragCls).appendTo('body');
             },
             'containment': 'body',
-            'start': function(e, ui) {
+            'start': function (e, ui) {
                 // hide the context menu if necessary
                 nf.ContextMenu.hide();
             },
@@ -92,49 +85,12 @@ nf.CanvasToolbox = (function () {
                         x: x,
                         y: y
                     });
-                } 
+                }
             }
         }).appendTo(toolbox);
     };
 
     /**
-     * Adds the specified tag filter.
-     * 
-     * @argument {string} tag       The tag to add
-     */
-    var addTagFilter = function (tag) {
-        // ensure this tag hasn't already been added
-        var tagFilter = $('#tag-filter');
-        var tagFilterExists = false;
-        tagFilter.find('li div.selected-tag-text').each(function () {
-            if (tag === $(this).text()) {
-                tagFilterExists = true;
-                return false;
-            }
-        });
-
-        // add this tag filter if applicable
-        if (!tagFilterExists) {
-            // create the list item content
-            var tagText = $('<div class="selected-tag-text"></div>').text(tag);
-            var removeTagIcon = $('<img src="images/iconDelete.png" 
class="remove-selected-tag pointer"></img>').click(function () {
-                // remove this tag
-                $(this).closest('li').remove();
-
-                // re-apply the filter
-                applyFilter();
-            });
-            var selectedTagItem = 
$('<div></div>').append(tagText).append(removeTagIcon);
-
-            // create the list item and update the tag filter list
-            $('<li></li>').append(selectedTagItem).appendTo(tagFilter);
-
-            // re-apply the filter
-            applyFilter();
-        }
-    };
-
-    /**
      * Filters the processor type table.
      */
     var applyFilter = function () {
@@ -192,7 +148,7 @@ nf.CanvasToolbox = (function () {
         // determine if the row matches the selected tags
         var matchesTags = true;
         if (matchesFilter) {
-            var tagFilters = $('#tag-filter li');
+            var tagFilters = 
$('#processor-tag-cloud').tagcloud('getSelectedTags');
             var hasSelectedTags = tagFilters.length > 0;
             if (hasSelectedTags) {
                 matchesTags = matchesSelectedTags(tagFilters, item['tags']);
@@ -221,13 +177,13 @@ nf.CanvasToolbox = (function () {
     /**
      * Determines if the specified tags match all the tags selected by the 
user.
      * 
-     * @argument {jQuery} tagFilters    The tag filters
-     * @argument {string} tags          The tags to test
+     * @argument {string[]} tagFilters      The tag filters
+     * @argument {string} tags              The tags to test
      */
     var matchesSelectedTags = function (tagFilters, tags) {
         var selectedTags = [];
-        tagFilters.each(function () {
-            selectedTags.push($(this).text());
+        $.each(tagFilters, function (_, filter) {
+            selectedTags.push(filter);
         });
 
         // normalize the tags
@@ -280,16 +236,6 @@ nf.CanvasToolbox = (function () {
      * Resets the filtered processor types.
      */
     var resetProcessorDialog = function () {
-        // clear and selected tags
-        var tagFilter = $('#tag-filter');
-        tagFilter.empty();
-
-        // clear any filter strings
-        
$('#processor-type-filter').addClass(config.styles.filterList).val(config.filterText);
-
-        // reset the filter before closing
-        applyFilter();
-
         // clear the selected row
         $('#processor-type-description').text('');
         $('#processor-type-name').text('');
@@ -300,6 +246,12 @@ nf.CanvasToolbox = (function () {
         var processTypesGrid = 
$('#processor-types-table').data('gridInstance');
         processTypesGrid.setSelectedRows([]);
         processTypesGrid.resetActiveCell();
+
+        // clear any filter strings
+        
$('#processor-type-filter').addClass(config.styles.filterList).val(config.filterText);
+
+        // clear the selected tag cloud
+        $('#processor-tag-cloud').tagcloud('clearSelectedTags');
     };
 
     /**
@@ -985,6 +937,20 @@ nf.CanvasToolbox = (function () {
                     }
                 });
 
+                // wire up the dataview to the grid
+                processorTypesData.onRowCountChanged.subscribe(function (e, 
args) {
+                    processorTypesGrid.updateRowCount();
+                    processorTypesGrid.render();
+
+                    // update the total number of displayed processors
+                    $('#displayed-processor-types').text(args.current);
+                });
+                processorTypesData.onRowsChanged.subscribe(function (e, args) {
+                    processorTypesGrid.invalidateRows(args.rows);
+                    processorTypesGrid.render();
+                });
+                processorTypesData.syncGridSelection(processorTypesGrid, 
false);
+
                 // hold onto an instance of the grid
                 $('#processor-types-table').data('gridInstance', 
processorTypesGrid);
 
@@ -995,7 +961,6 @@ nf.CanvasToolbox = (function () {
                     url: config.urls.processorTypes,
                     dataType: 'json'
                 }).done(function (response) {
-                    var tagCloud = {};
                     var tags = [];
 
                     // begin the update
@@ -1014,21 +979,9 @@ nf.CanvasToolbox = (function () {
                             tags: documentedType.tags.join(', ')
                         });
 
-
                         // count the frequency of each tag for this type
                         $.each(documentedType.tags, function (i, tag) {
-                            var normalizedTagName = tag.toLowerCase();
-
-                            if 
(nf.Common.isDefinedAndNotNull(tagCloud[normalizedTagName])) {
-                                tagCloud[normalizedTagName].count = 
tagCloud[normalizedTagName].count + 1;
-                            } else {
-                                var tagCloudEntry = {
-                                    term: normalizedTagName,
-                                    count: 1
-                                };
-                                tags.push(tagCloudEntry);
-                                tagCloud[normalizedTagName] = tagCloudEntry;
-                            }
+                            tags.push(tag.toLowerCase());
                         });
                     });
 
@@ -1038,65 +991,12 @@ nf.CanvasToolbox = (function () {
                     // set the total number of processors
                     $('#total-processor-types, 
#displayed-processor-types').text(response.processorTypes.length);
 
-                    // handle the case when no tags are present
-                    if (tags.length > 0) {
-                        // sort the tags by frequency to limit the less 
frequent tags
-                        tags.sort(function (a, b) {
-                            return b.count - a.count;
-                        });
-
-                        // limit to the most frequest tags
-                        if (tags.length > config.maxTags) {
-                            tags = tags.slice(0, config.maxTags);
-                        }
-
-                        // determine the max frequency
-                        var maxFrequency = tags[0].count;
-
-                        // sort the tags alphabetically
-                        tags.sort(function (a, b) {
-                            var compA = a.term.toUpperCase();
-                            var compB = b.term.toUpperCase();
-                            return (compA < compB) ? -1 : (compA > compB) ? 1 
: 0;
-                        });
-
-                        // set the tag content
-                        $.each(tags, function (i, tag) {
-                            // determine the appropriate font size
-                            var fontSize = Math.log(tag.count) / 
Math.log(maxFrequency) * (config.maxTagFontSize - config.minTagFontSize) + 
config.minTagFontSize;
-                            var minWidth = config.minWidth * fontSize;
-
-                            // create the tag cloud entry
-                            $('<li></li>').append($('<span 
class="link"></span>').text(tag.term).css({
-                                'font-size': fontSize + 'em'
-                            })).css({
-                                'min-width': minWidth + 'px'
-                            }).click(function () {
-                                // ensure we don't exceed 5 selected
-                                if ($('#tag-filter').children('li').length < 
5) {
-                                    var tagText = 
$(this).children('span').text();
-                                    addTagFilter(tagText);
-                                }
-                            }).appendTo('#tag-cloud').ellipsis();
-                        });
-                    } else {
-                        // indicate when no tags are found
-                        $('<li><span class="unset">No tags 
specified</span></li>').appendTo('#tag-cloud');
-                    }
-
-                    // wire up the dataview to the grid
-                    processorTypesData.onRowCountChanged.subscribe(function 
(e, args) {
-                        processorTypesGrid.updateRowCount();
-                        processorTypesGrid.render();
-
-                        // update the total number of displayed processors
-                        $('#displayed-processor-types').text(args.current);
-                    });
-                    processorTypesData.onRowsChanged.subscribe(function (e, 
args) {
-                        processorTypesGrid.invalidateRows(args.rows);
-                        processorTypesGrid.render();
+                    // create the tag cloud
+                    $('#processor-tag-cloud').tagcloud({
+                        tags: tags,
+                        select: applyFilter,
+                        remove: applyFilter
                     });
-                    processorTypesData.syncGridSelection(processorTypesGrid, 
false);
                 }).fail(nf.Common.handleAjaxError);
 
                 // define the function for filtering the list

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/b39fdbd6/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
----------------------------------------------------------------------
diff --git 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
index 26db837..8125219 100644
--- 
a/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
+++ 
b/nifi/nar-bundles/framework-bundle/framework/web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
@@ -509,6 +509,7 @@ nf.Canvas = (function () {
         // listen for browser resize events to reset the graph size
         $(window).on('resize', function () {
             updateGraphSize();
+            nf.Settings.resetTableSize();
         }).on('keydown', function (evt) {
             // if a dialog is open, disable canvas shortcuts
             if ($('.dialog').is(':visible')) {

Reply via email to