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 2016/05/11 20:40:25 UTC

nifi git commit: [NIFI-1782] new search UX and add angular control of flow status values. This closes #433

Repository: nifi
Updated Branches:
  refs/heads/master 25e7f314b -> 3c3304aff


[NIFI-1782] new search UX and add angular control of flow status values. This closes #433


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

Branch: refs/heads/master
Commit: 3c3304aff4a576f32bf3f18ded9a8e718280e4e8
Parents: 25e7f31
Author: Scott Aslan <ja...@hortonworks.com>
Authored: Wed May 11 16:06:35 2016 -0400
Committer: Matt Gilman <ma...@gmail.com>
Committed: Wed May 11 16:39:38 2016 -0400

----------------------------------------------------------------------
 .../nifi-framework/nifi-web/nifi-web-ui/pom.xml |   2 +-
 .../main/resources/filters/canvas.properties    |   2 +-
 .../WEB-INF/partials/canvas/canvas-header.jsp   |   8 +-
 .../WEB-INF/partials/canvas/flow-status.jsp     |  26 +-
 .../src/main/webapp/css/flow-status.css         |  58 +--
 .../nifi-web-ui/src/main/webapp/css/header.css  |   4 +-
 .../src/main/webapp/css/navigation.css          |   2 +-
 .../nf-ng-canvas-flow-status-controller.js      | 389 +++++++++++++++++++
 .../nf-ng-canvas-global-menu-controller.js      |  87 +++--
 .../nf-ng-canvas-header-controller.js           |  79 +++-
 .../src/main/webapp/js/nf/canvas/nf-canvas.js   | 187 +--------
 .../src/main/webapp/js/nf/canvas/nf-search.js   | 179 ---------
 .../src/main/webapp/js/nf/canvas/nf-settings.js |   3 +-
 .../src/main/webapp/js/nf/nf-ng-bridge.js       |   6 +-
 14 files changed, 574 insertions(+), 458 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/3c3304af/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml
index dd2ea09..a2c4daa 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml
@@ -364,7 +364,6 @@
                                                 <include>${staging.dir}/js/nf/canvas/nf-selectable.js</include>
                                                 <include>${staging.dir}/js/nf/canvas/nf-connectable.js</include>
                                                 <include>${staging.dir}/js/nf/canvas/nf-birdseye.js</include>
-                                                <include>${staging.dir}/js/nf/canvas/nf-search.js</include>
                                                 <include>${staging.dir}/js/nf/canvas/nf-settings.js</include>
                                                 <include>${staging.dir}/js/nf/canvas/nf-go-to.js</include>
                                                 <include>${staging.dir}/js/nf/canvas/nf-actions.js</include>
@@ -377,6 +376,7 @@
                                                 <include>${staging.dir}/js/nf/canvas/controllers/nf-ng-breadcrumbs-controller.js</include>
                                                 <include>${staging.dir}/js/nf/canvas/controllers/nf-ng-canvas-header-controller.js</include>
                                                 <include>${staging.dir}/js/nf/canvas/controllers/nf-ng-canvas-toolbox-controller.js</include>
+                                                <include>${staging.dir}/js/nf/canvas/controllers/nf-ng-canvas-flow-status-controller.js</include>
                                                 <include>${staging.dir}/js/nf/canvas/controllers/nf-ng-canvas-global-menu-controller.js</include>
                                                 <include>${staging.dir}/js/nf/canvas/controllers/nf-ng-canvas-graph-controls-controller.js</include>
                                                 <include>${staging.dir}/js/nf/canvas/controllers/nf-ng-canvas-navigate-controller.js</include>

http://git-wip-us.apache.org/repos/asf/nifi/blob/3c3304af/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/filters/canvas.properties
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/filters/canvas.properties b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/filters/canvas.properties
index 70cff30..cd58d9f 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/filters/canvas.properties
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/filters/canvas.properties
@@ -53,7 +53,6 @@ nf.canvas.script.tags=<script type="text/javascript" src="js/nf/nf-namespace.js?
 <script type="text/javascript" src="js/nf/canvas/nf-connectable.js?${project.version}"></script>\n\
 <script type="text/javascript" src="js/nf/canvas/nf-selectable.js?${project.version}"></script>\n\
 <script type="text/javascript" src="js/nf/canvas/nf-birdseye.js?${project.version}"></script>\n\
-<script type="text/javascript" src="js/nf/canvas/nf-search.js?${project.version}"></script>\n\
 <script type="text/javascript" src="js/nf/canvas/nf-settings.js?${project.version}"></script>\n\
 <script type="text/javascript" src="js/nf/canvas/nf-go-to.js?${project.version}"></script>\n\
 <script type="text/javascript" src="js/nf/canvas/nf-actions.js?${project.version}"></script>\n\
@@ -65,6 +64,7 @@ nf.canvas.script.tags=<script type="text/javascript" src="js/nf/nf-namespace.js?
 <script type="text/javascript" src="js/nf/canvas/controllers/nf-ng-breadcrumbs-controller.js?${project.version}"></script>\n\
 <script type="text/javascript" src="js/nf/canvas/controllers/nf-ng-canvas-header-controller.js?${project.version}"></script>\n\
 <script type="text/javascript" src="js/nf/canvas/controllers/nf-ng-canvas-toolbox-controller.js?${project.version}"></script>\n\
+<script type="text/javascript" src="js/nf/canvas/controllers/nf-ng-canvas-flow-status-controller.js?${project.version}"></script>\n\
 <script type="text/javascript" src="js/nf/canvas/controllers/nf-ng-canvas-global-menu-controller.js?${project.version}"></script>\n\
 <script type="text/javascript" src="js/nf/canvas/controllers/nf-ng-canvas-graph-controls-controller.js?${project.version}"></script>\n\
 <script type="text/javascript" src="js/nf/canvas/controllers/nf-ng-canvas-navigate-controller.js?${project.version}"></script>\n\

http://git-wip-us.apache.org/repos/asf/nifi/blob/3c3304af/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/canvas-header.jsp
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/canvas-header.jsp b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/canvas-header.jsp
index 8f00429..492dc21 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/canvas-header.jsp
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/canvas-header.jsp
@@ -61,11 +61,11 @@
                 </div>
                 <div id="login-link-container">
                     <span id="login-link" class="link"
-                          ng-click="appCtrl.serviceProvider.headerCtrl.loginLink.shell.launch();">login</span>
+                          ng-click="appCtrl.serviceProvider.headerCtrl.loginCtrl.shell.launch();">login</span>
                 </div>
                 <div id="logout-link-container" style="display: none;">
                     <span id="logout-link" class="link"
-                          ng-click="appCtrl.serviceProvider.headerCtrl.logoutLink.logout();">logout</span>
+                          ng-click="appCtrl.serviceProvider.headerCtrl.logoutCtrl.logout();">logout</span>
                 </div>
             </div>
             <md-menu md-position-mode="target-right target" md-offset="-1 44">
@@ -114,9 +114,9 @@
                     </md-menu-item>
                     <md-menu-item ng-if="appCtrl.serviceProvider.headerCtrl.globalMenuCtrl.users.enabled();"
                                   layout-align="space-around center">
-                        <a id="users-link"
+                        <a id="users-link" layout="row"
                            ng-click="appCtrl.serviceProvider.headerCtrl.globalMenuCtrl.users.shell.launch();;"><i
-                                class="fa fa-users"></i>Users</a>
+                                class="fa fa-users"></i>Users<div id="has-pending-accounts" class="hidden"></div></a>
                     </md-menu-item>
                     <md-menu-divider></md-menu-divider>
                     <md-menu-item layout-align="space-around center">

http://git-wip-us.apache.org/repos/asf/nifi/blob/3c3304af/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/flow-status.jsp
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/flow-status.jsp b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/flow-status.jsp
index efecd01..e0ec233 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/flow-status.jsp
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/flow-status.jsp
@@ -17,21 +17,23 @@
 <%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
 <div id="flow-status" flex layout="row" layout-align="space-between center">
     <div id="flow-status-container" layout="row" layout-align="space-around center">
-        <i class="fa fa-cubes" ng-if="appCtrl.nf.Canvas.isClustered()"><span id="connected-nodes-count"></span></i>
-        <i class="icon icon-threads"><span id="active-thread-count"></span></i>
-        <i class="fa fa-list"><span id="total-queued"></span></i>
-        <i class="fa fa-bullseye"><span id="controller-transmitting-count"></span></i>
-        <i class="icon icon-transmit-false"><span id="controller-not-transmitting-count"></span></i>
-        <i class="fa fa-play"><span id="controller-running-count"></span></i>
-        <i class="fa fa-stop"><span id="controller-stopped-count"></span></i>
-        <i class="fa fa-warning"><span id="controller-invalid-count"></span></i>
-        <i class="icon icon-enable-false"><span id="controller-disabled-count"></span></i>
-        <i class="fa fa-refresh"><span id="stats-last-refreshed"></span></i>
+        <i class="fa fa-cubes" ng-if="appCtrl.nf.Canvas.isClustered()"><span id="connected-nodes-count">{{appCtrl.serviceProvider.headerCtrl.flowStatusCtrl.connectedNodesCount}}</span></i>
+        <i class="icon icon-threads"><span id="active-thread-count">{{appCtrl.serviceProvider.headerCtrl.flowStatusCtrl.activeThreadCount}}</span></i>
+        <i class="fa fa-list"><span id="total-queued">{{appCtrl.serviceProvider.headerCtrl.flowStatusCtrl.totalQueued}}</span></i>
+        <i class="fa fa-bullseye"><span id="controller-transmitting-count">{{appCtrl.serviceProvider.headerCtrl.flowStatusCtrl.controllerTransmittingCount}}</span></i>
+        <i class="icon icon-transmit-false"><span id="controller-not-transmitting-count">{{appCtrl.serviceProvider.headerCtrl.flowStatusCtrl.controllerNotTransmittingCount}}</span></i>
+        <i class="fa fa-play"><span id="controller-running-count">{{appCtrl.serviceProvider.headerCtrl.flowStatusCtrl.controllerRunningCount}}</span></i>
+        <i class="fa fa-stop"><span id="controller-stopped-count">{{appCtrl.serviceProvider.headerCtrl.flowStatusCtrl.controllerStoppedCount}}</span></i>
+        <i class="fa fa-warning"><span id="controller-invalid-count">{{appCtrl.serviceProvider.headerCtrl.flowStatusCtrl.controllerInvalidCount}}</span></i>
+        <i class="icon icon-enable-false"><span id="controller-disabled-count">{{appCtrl.serviceProvider.headerCtrl.flowStatusCtrl.controllerDisabledCount}}</span></i>
+        <i class="fa fa-refresh"><span id="stats-last-refreshed">{{appCtrl.serviceProvider.headerCtrl.flowStatusCtrl.statsLastRefreshed}}</span></i>
         <div id="canvas-loading-container" class="loading-container"></div>
     </div>
     <div layout="row" layout-align="end center">
-        <input id="search-field" type="text"/>
-        <button id="search-button"><i class="fa fa-search"></i></button>
+        <div id="search-container">
+            <button id="search-button" ng-click="appCtrl.serviceProvider.headerCtrl.flowStatusCtrl.search.toggleSearchField();"><i class="fa fa-search"></i></button>
+            <input id="search-field" type="text" placeholder="Search"/>
+        </div>
         <button id="bulletin-button"><i class="fa fa-sticky-note-o"></i></button>
     </div>
 </div>

http://git-wip-us.apache.org/repos/asf/nifi/blob/3c3304af/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/flow-status.css
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/flow-status.css b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/flow-status.css
index f79c8e3..4f99055 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/flow-status.css
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/flow-status.css
@@ -18,69 +18,78 @@
 
 #flow-status {
     height: 32px;
-    background-color:#E3E8EB; /*tint base-color 60%*/
+    background-color: #E3E8EB; /*tint base-color 60%*/
 }
 
 #flow-status .icon {
-    font-size:15px;
+    font-size: 15px;
     font-style: normal;
     color: #728E9B; /*base-color*/
 }
 
 #flow-status .fa {
-    font-size:15px;
+    font-size: 15px;
     font-style: normal;
     color: #728E9B; /*base-color*/
 }
 
-#flow-status .icon span{
-    font-size:15px;
+#flow-status .icon span {
+    font-size: 15px;
     font-weight: 500;
     color: #775351; /*value-color*/
 }
 
-#flow-status .fa span{
-    font-size:15px;
+#flow-status .fa span {
+    font-size: 15px;
     font-weight: 500;
     color: #775351; /*value-color*/
     font-family: Roboto, sans-serif;
 }
 
-#flow-status button{
+#flow-status button {
     height: 32px;
-    width:32px;
-    border-left:1px solid #AABBC3; /*tint base-color 40%*/
+    width: 32px;
+    border-left: 1px solid #AABBC3; /*tint base-color 40%*/
     border-right: none;
     border-top: none;
     border-bottom: none;
+    position: relative;
 }
 
-#flow-status span{
+#flow-status span {
     padding-left: 5px;
 }
 
-#search-button {
-    background-color:#E3E8EB; /*tint base-color 80%*/
+#search-container {
+    overflow: hidden;
+    height: 32px;
+    background: #FFFFFF;
+}
+
+.search-container-opened {
+    width: 235px;
 }
 
-#search-button i{
-    color: #004849;
-    font-size:15px;
+.search-container-closed {
+    width: 32px;
 }
 
 #search-button:hover {
-    background-color:#FFFFFF;
-    border-left:1px solid #004849; /*link-color*/
-    box-shadow:0 2px 2px rgba(0,0,0,0.25);
+    background-color: #FFFFFF !important; /* override any styles set by JS */
+    border-left: 1px solid #004849; /*link-color*/
+}
+
+#search-button .fa {
+    color: #004849;
 }
 
 #bulletin-button {
-    background-color:#728E9B; /*base-color*/
+    background-color: #728E9B; /*base-color*/
 }
 
 #bulletin-button i.fa {
     color: #fff;
-    font-size:15px;
+    font-size: 15px;
 }
 
 #canvas-loading-container {
@@ -101,12 +110,11 @@ div.search-result-icon {
 }
 
 #search-field {
-    height: 32px;
+    height: 33px;
     width: 200px;
     background: #FFFFFF;
-    border: 0px solid #AABBC3;
-    position: relative;
-    left: 32px;
+    border: 0px;
+    padding: 0px;
 }
 
 input.search-flow {

http://git-wip-us.apache.org/repos/asf/nifi/blob/3c3304af/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/header.css
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/header.css b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/header.css
index b36914e..6d280d0 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/header.css
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/header.css
@@ -174,7 +174,7 @@ md-toolbar.md-small .md-toolbar-tools {
     background-image: url(../images/starburst.png);
     width: 9px;
     height: 9px;
-    margin-top: 2px;
-    margin-left: 13px;
+    margin-top: 3px;
+    margin-left: 5px;
     background-color: transparent;
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/3c3304af/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/navigation.css
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/navigation.css b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/navigation.css
index d80ff15..8d8e9d7 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/navigation.css
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/navigation.css
@@ -188,7 +188,7 @@ rect.birdseye-brush {
     background-color: rgba(249, 250, 251, 0.97); /*tint base-color 96%*/
     border-top: 1px solid #C7D2D7; /*tint base-color 60%*/
     color: #598599;
-    z-index: 2;
+    z-index: 3;
     height: 31px;
     width: 100%;
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/3c3304af/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-flow-status-controller.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-flow-status-controller.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-flow-status-controller.js
new file mode 100644
index 0000000..7937874
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-flow-status-controller.js
@@ -0,0 +1,389 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* global nf, d3 */
+
+nf.ng.Canvas.FlowStatusCtrl = function (serviceProvider, $sanitize) {
+    'use strict';
+
+    var config = {
+        search: 'Search',
+        urls: {
+            search: '../nifi-api/flow/search-results',
+            status: '../nifi-api/flow/status'
+        }
+    };
+
+    function FlowStatusCtrl() {
+        this.connectedNodesCount = "-";
+        this.activeThreadCount = "-";
+        this.totalQueued = "-";
+        this.controllerTransmittingCount = "-";
+        this.controllerNotTransmittingCount = "-";
+        this.controllerRunningCount = "-";
+        this.controllerStoppedCount = "-";
+        this.controllerInvalidCount = "-";
+        this.controllerDisabledCount = "-";
+        this.statsLastRefreshed = "-";
+
+        /**
+         * The search controller.
+         */
+        this.search = {
+
+            /**
+             * Get the search input element.
+             */
+            getInputElement: function () {
+                return $('#search-field');
+            },
+
+            /**
+             * Get the search button element.
+             */
+            getButtonElement: function () {
+                return $('#search-button');
+            },
+
+            /**
+             * Get the search container element.
+             */
+            getSearchContainerElement: function () {
+                return $('#search-container');
+            },
+
+            /**
+             * Initialize the search controller.
+             */
+            init: function () {
+
+                var self = this;
+
+                // Create new jQuery UI widget
+                $.widget('nf.searchAutocomplete', $.ui.autocomplete, {
+                    reset: function () {
+                        this.term = null;
+                    },
+                    _resizeMenu: function () {
+                        var ul = this.menu.element;
+                        ul.width(399);
+                    },
+                    _normalize: function (searchResults) {
+                        var items = [];
+                        items.push(searchResults);
+                        return items;
+                    },
+                    _renderMenu: function (ul, items) {
+                        var self = this;
+
+                        // the object that holds the search results is normalized into a single element array
+                        var searchResults = items[0];
+
+                        // show all processors
+                        if (!nf.Common.isEmpty(searchResults.processorResults)) {
+                            ul.append('<li class="search-header"><div class="search-result-icon"><i class="icon icon-processor"></i></div>Processors</li>');
+                            $.each(searchResults.processorResults, function (i, processorMatch) {
+                                self._renderItem(ul, processorMatch);
+                            });
+                        }
+
+                        // show all process groups
+                        if (!nf.Common.isEmpty(searchResults.processGroupResults)) {
+                            ul.append('<li class="search-header"><div class="search-result-icon"><i class="icon icon-group"></i></div>Process Groups</li>');
+                            $.each(searchResults.processGroupResults, function (i, processGroupMatch) {
+                                self._renderItem(ul, processGroupMatch);
+                            });
+                        }
+
+                        // show all remote process groups
+                        if (!nf.Common.isEmpty(searchResults.remoteProcessGroupResults)) {
+                            ul.append('<li class="search-header"><div class="search-result-icon"><i class="icon icon-group-remote"></i></div>Remote Process Groups</li>');
+                            $.each(searchResults.remoteProcessGroupResults, function (i, remoteProcessGroupMatch) {
+                                self._renderItem(ul, remoteProcessGroupMatch);
+                            });
+                        }
+
+                        // show all connections
+                        if (!nf.Common.isEmpty(searchResults.connectionResults)) {
+                            ul.append('<li class="search-header"><div class="search-result-icon"><i class="icon icon-connect"></i></div>Connections</li>');
+                            $.each(searchResults.connectionResults, function (i, connectionMatch) {
+                                self._renderItem(ul, connectionMatch);
+                            });
+                        }
+
+                        // show all input ports
+                        if (!nf.Common.isEmpty(searchResults.inputPortResults)) {
+                            ul.append('<li class="search-header"><div class="search-result-icon"><i class="icon icon-port-in"></i></div>Input Ports</li>');
+                            $.each(searchResults.inputPortResults, function (i, inputPortMatch) {
+                                self._renderItem(ul, inputPortMatch);
+                            });
+                        }
+
+                        // show all output ports
+                        if (!nf.Common.isEmpty(searchResults.outputPortResults)) {
+                            ul.append('<li class="search-header"><div class="search-result-icon"><i class="icon icon-port-out"></i></div>Output Ports</li>');
+                            $.each(searchResults.outputPortResults, function (i, outputPortMatch) {
+                                self._renderItem(ul, outputPortMatch);
+                            });
+                        }
+
+                        // show all funnels
+                        if (!nf.Common.isEmpty(searchResults.funnelResults)) {
+                            ul.append('<li class="search-header"><div class="search-result-icon"><i class="icon icon-funnel"></i></div>Funnels</li>');
+                            $.each(searchResults.funnelResults, function (i, funnelMatch) {
+                                self._renderItem(ul, funnelMatch);
+                            });
+                        }
+
+                        // ensure there were some results
+                        if (ul.children().length === 0) {
+                            ul.append('<li class="unset search-no-matches">No results matched the search terms</li>');
+                        }
+                    },
+                    _renderItem: function (ul, match) {
+                        var itemContent = $('<a></a>').append($('<div class="search-match-header"></div>').text(match.name));
+                        $.each(match.matches, function (i, match) {
+                            itemContent.append($('<div class="search-match"></div>').text(match));
+                        });
+                        return $('<li></li>').data('ui-autocomplete-item', match).append(itemContent).appendTo(ul);
+                    }
+                })
+
+                // configure the new searchAutocomplete jQuery UI widget
+                this.getInputElement().searchAutocomplete({
+                    appendTo: '#search-flow-results',
+                    position: {
+                        my: 'right top',
+                        at: 'right bottom',
+                        offset: '1 1'
+                    },
+                    source: function (request, response) {
+                        // create the search request
+                        $.ajax({
+                            type: 'GET',
+                            data: {
+                                q: request.term
+                            },
+                            dataType: 'json',
+                            url: config.urls.search
+                        }).done(function (searchResponse) {
+                            response(searchResponse.searchResultsDTO);
+                        });
+                    },
+                    select: function (event, ui) {
+                        var item = ui.item;
+
+                        // show the selected component
+                        nf.CanvasUtils.showComponent(item.groupId, item.id);
+
+                        self.getInputElement().val('').blur();
+
+                        // stop event propagation
+                        return false;
+                    },
+                    open: function (event, ui) {
+                        // show the glass pane
+                        var searchField = $(this);
+                        $('<div class="search-glass-pane"></div>').one('click', function () {
+                        }).appendTo('body');
+                    },
+                    close: function (event, ui) {
+                        // set the input text to '' and reset the cached term
+                        $(this).searchAutocomplete('reset');
+                        self.getInputElement().val('');
+
+                        // remove the glass pane
+                        $('div.search-glass-pane').remove();
+                    }
+                });
+
+                // hide the search input
+                self.toggleSearchField();
+            },
+
+            /**
+             * Toggle/Slide the search field open/closed.
+             */
+            toggleSearchField: function () {
+                var self = this;
+
+                // hide the context menu if necessary
+                nf.ContextMenu.hide();
+
+                var isVisible = self.getInputElement().is(':visible');
+                var display = 'none';
+                var class1 = 'search-container-opened';
+                var class2 = 'search-container-closed';
+                if (!isVisible) {
+                    self.getButtonElement().css('background-color', '#FFFFFF');
+                    display = 'inline-block';
+                    class1 = 'search-container-closed';
+                    class2 = 'search-container-opened';
+                } else {
+                    self.getInputElement().css('display', display);
+                }
+
+                this.getSearchContainerElement().switchClass(class1, class2, 500, function () {
+                    self.getInputElement().css('display', display);
+                    if (!isVisible) {
+                        self.getButtonElement().css('background-color', '#FFFFFF');
+                        self.getInputElement().focus();
+                    } else {
+                        self.getButtonElement().css('background-color', '#E3E8EB');
+                    }
+                });
+            }
+        }
+
+        /**
+         * The bulletins controller.
+         */
+        this.bulletins = {
+
+            /**
+             * Update the bulletins.
+             *
+             * @param status  The controller status returned from the `../nifi-api/flow/status` endpoint.
+             */
+            update: function (status) {
+
+                // icon for system bulletins
+                var bulletinIcon = $('#bulletin-button');
+                var currentBulletins = bulletinIcon.data('bulletins');
+
+                // update the bulletins if necessary
+                if (nf.Common.doBulletinsDiffer(currentBulletins, status.bulletins)) {
+                    bulletinIcon.data('bulletins', status.bulletins);
+
+                    // get the formatted the bulletins
+                    var bulletins = nf.Common.getFormattedBulletins(status.bulletins);
+
+                    // bulletins for this processor are now gone
+                    if (bulletins.length === 0) {
+                        if (bulletinIcon.data('qtip')) {
+                            bulletinIcon.removeClass('has-bulletins').qtip('api').destroy(true);
+                        }
+                    } else {
+                        var newBulletins = nf.Common.formatUnorderedList(bulletins);
+
+                        // different bulletins, refresh
+                        if (bulletinIcon.data('qtip')) {
+                            bulletinIcon.qtip('option', 'content.text', newBulletins);
+                        } else {
+                            // no bulletins before, show icon and tips
+                            bulletinIcon.addClass('has-bulletins').qtip($.extend({
+                                content: newBulletins
+                            }, nf.CanvasUtils.config.systemTooltipConfig));
+                        }
+                    }
+                }
+
+                // update controller service and reporting task bulletins
+                nf.Settings.setBulletins(status.controllerServiceBulletins, status.reportingTaskBulletins);
+            }
+
+        }
+    }
+
+    FlowStatusCtrl.prototype = {
+        constructor: FlowStatusCtrl,
+
+        /**
+         * Initialize the flow status controller.
+         */
+        init: function () {
+            this.search.init();
+        },
+
+        /**
+         * Reloads the current status of the flow.
+         */
+        reloadFlowStatus: function () {
+            var self = this;
+
+            return $.ajax({
+                type: 'GET',
+                url: config.urls.status,
+                dataType: 'json'
+            }).done(function (response) {
+                // report the updated status
+                if (nf.Common.isDefinedAndNotNull(response.controllerStatus)) {
+                    self.update(response.controllerStatus);
+                }
+            }).fail(nf.Common.handleAjaxError);
+        },
+
+        /**
+         * Update the flow status counts.
+         *
+         * @param status  The controller status returned from the `../nifi-api/flow/status` endpoint.
+         */
+        update: function (status) {
+            var controllerInvalidCountColor =
+                (nf.Common.isDefinedAndNotNull(status.invalidCount) && (status.invalidCount > 0)) ?
+                    '#BA554A' : '#728E9B';
+            $('#controller-invalid-count').parent().css('color', controllerInvalidCountColor);
+
+            if (nf.Common.isDefinedAndNotNull(status.connectedNodes)) {
+                var connectedNodes = status.connectedNodes.split(' / ');
+                var connectedNodesCountColor =
+                    (connectedNodes.length === 2 && connectedNodes[0] !== connectedNodes[1]) ? '#BA554A' : '#728E9B';
+                $('#connected-nodes-count').parent().css('color', connectedNodesCountColor);
+            }
+
+            // update the report values
+            this.activeThreadCount = $sanitize(status.activeThreadCount);
+            this.totalQueued = $sanitize(status.queued);
+
+            // update the component counts
+            this.controllerTransmittingCount =
+                nf.Common.isDefinedAndNotNull(status.activeRemotePortCount) ?
+                    $sanitize(status.activeRemotePortCount) : '-';
+
+            this.controllerNotTransmittingCount =
+                nf.Common.isDefinedAndNotNull(status.inactiveRemotePortCount) ?
+                    $sanitize(status.inactiveRemotePortCount) : '-';
+
+            this.controllerRunningCount =
+                nf.Common.isDefinedAndNotNull(status.runningCount) ? $sanitize(status.runningCount) : '-';
+
+            this.controllerStoppedCount =
+                nf.Common.isDefinedAndNotNull(status.stoppedCount) ? $sanitize(status.stoppedCount) : '-';
+
+            this.controllerInvalidCount =
+                nf.Common.isDefinedAndNotNull(status.invalidCount) ? $sanitize(status.invalidCount) : '-';
+
+            this.controllerDisabledCount =
+                nf.Common.isDefinedAndNotNull(status.disabledCount) ? $sanitize(status.disabledCount) : '-';
+
+            this.connectedNodesCount =
+                nf.Common.isDefinedAndNotNull(status.connectedNodes) ? $sanitize(status.connectedNodes) : '-';
+
+            this.bulletins.update(status);
+
+            // handle any pending user request
+            if (status.hasPendingAccounts === true) {
+                $('#has-pending-accounts').show();
+            } else {
+                $('#has-pending-accounts').hide();
+            }
+        }
+    }
+
+    var flowStatusCtrl = new FlowStatusCtrl();
+    return flowStatusCtrl;
+};
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/3c3304af/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-global-menu-controller.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-global-menu-controller.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-global-menu-controller.js
index f916144..1a6c713 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-global-menu-controller.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-global-menu-controller.js
@@ -30,12 +30,12 @@ nf.ng.Canvas.GlobalMenuCtrl = function (serviceProvider) {
     function GlobalMenuCtrl(serviceProvider) {
 
         /**
-         * The summary menu item.
+         * The summary menu item controller.
          */
         this.summary = {
 
             /**
-             * The summary menu item's shell.
+             * The summary menu item's shell controller.
              */
             shell: {
 
@@ -49,12 +49,12 @@ nf.ng.Canvas.GlobalMenuCtrl = function (serviceProvider) {
         };
 
         /**
-         * The counters menu item.
+         * The counters menu item controller.
          */
         this.counters = {
 
             /**
-             * The counters menu item's shell.
+             * The counters menu item's shell controller.
              */
             shell: {
 
@@ -68,12 +68,12 @@ nf.ng.Canvas.GlobalMenuCtrl = function (serviceProvider) {
         };
 
         /**
-         * The bulletin board menu item.
+         * The bulletin board menu item controller.
          */
         this.bulletinBoard = {
 
             /**
-             * The bulletin board menu item's shell.
+             * The bulletin board menu item's shell controller.
              */
             shell: {
 
@@ -87,7 +87,7 @@ nf.ng.Canvas.GlobalMenuCtrl = function (serviceProvider) {
         };
 
         /**
-         * The data provenance menu item.
+         * The data provenance menu item controller.
          */
         this.dataProvenance = {
 
@@ -101,7 +101,7 @@ nf.ng.Canvas.GlobalMenuCtrl = function (serviceProvider) {
             },
 
             /**
-             * The data provenance menu item's shell.
+             * The data provenance menu item's shell controller.
              */
             shell: {
 
@@ -115,12 +115,12 @@ nf.ng.Canvas.GlobalMenuCtrl = function (serviceProvider) {
         };
 
         /**
-         * The controller settings menu item.
+         * The controller settings menu item controller.
          */
         this.controllerSettings = {
 
             /**
-             * The controller settings menu item's shell.
+             * The controller settings menu item's shell controller.
              */
             shell: {
 
@@ -136,7 +136,7 @@ nf.ng.Canvas.GlobalMenuCtrl = function (serviceProvider) {
         };
 
         /**
-         * The cluster menu item.
+         * The cluster menu item controller.
          */
         this.cluster = {
 
@@ -150,7 +150,7 @@ nf.ng.Canvas.GlobalMenuCtrl = function (serviceProvider) {
             },
 
             /**
-             * The cluster menu item's shell.
+             * The cluster menu item's shell controller.
              */
             shell: {
 
@@ -164,12 +164,12 @@ nf.ng.Canvas.GlobalMenuCtrl = function (serviceProvider) {
         };
 
         /**
-         * The flow config history menu item.
+         * The flow config history menu item controller.
          */
         this.flowConfigHistory = {
 
             /**
-             * The flow config history menu item's shell.
+             * The flow config history menu item's shell controller.
              */
             shell: {
 
@@ -183,7 +183,7 @@ nf.ng.Canvas.GlobalMenuCtrl = function (serviceProvider) {
         };
 
         /**
-         * The users menu item.
+         * The users menu item controller.
          */
         this.users = {
 
@@ -197,7 +197,7 @@ nf.ng.Canvas.GlobalMenuCtrl = function (serviceProvider) {
             },
 
             /**
-             * The users menu item's shell.
+             * The users menu item's shell controller.
              */
             shell: {
 
@@ -211,12 +211,12 @@ nf.ng.Canvas.GlobalMenuCtrl = function (serviceProvider) {
         };
 
         /**
-         * The templates menu item.
+         * The templates menu item controller.
          */
         this.templates = {
 
             /**
-             * The templates menu item's shell.
+             * The templates menu item's shell controller.
              */
             shell: {
 
@@ -232,12 +232,12 @@ nf.ng.Canvas.GlobalMenuCtrl = function (serviceProvider) {
         };
 
         /**
-         * The help menu item.
+         * The help menu item controller.
          */
         this.help = {
 
             /**
-             * The help menu item's shell.
+             * The help menu item's shell controller.
              */
             shell: {
 
@@ -251,12 +251,36 @@ nf.ng.Canvas.GlobalMenuCtrl = function (serviceProvider) {
         };
 
         /**
-         * The about menu item.
+         * The about menu item controller.
          */
         this.about = {
 
             /**
-             * The about menu item's modal.
+             * Initialize the about details.
+             */
+            init: function () {
+                // get the about details
+                $.ajax({
+                    type: 'GET',
+                    url: config.urls.controllerAbout,
+                    dataType: 'json'
+                }).done(function (response) {
+                    var aboutDetails = response.about;
+                    // set the document title and the about title
+                    document.title = aboutDetails.title;
+                    $('#nf-version').text(aboutDetails.version);
+
+                    // store the content viewer url if available
+                    if (!nf.Common.isBlank(aboutDetails.contentViewerUrl)) {
+                        $('#nifi-content-viewer-url').text(aboutDetails.contentViewerUrl);
+                    }
+                }).fail(nf.Common.handleAjaxError);
+
+                this.modal.init();
+            },
+
+            /**
+             * The about menu item's modal controller.
              */
             modal: {
 
@@ -274,19 +298,7 @@ nf.ng.Canvas.GlobalMenuCtrl = function (serviceProvider) {
                  */
                 init: function () {
                     var self = this;
-                    // get the about details
-                    $.ajax({
-                        type: 'GET',
-                        url: config.urls.controllerAbout,
-                        dataType: 'json'
-                    }).done(function (response) {
-                        var aboutDetails = response.about;
-                        // set the document title and the about title
-                        document.title = aboutDetails.title;
-                        $('#nf-version').text(aboutDetails.version);
-                    }).fail(nf.Common.handleAjaxError);
-
-                    // configure the about dialog
+
                     this.getElement().modal({
                         overlayBackground: true,
                         buttons: [{
@@ -326,14 +338,15 @@ nf.ng.Canvas.GlobalMenuCtrl = function (serviceProvider) {
             }
         }
     }
+
     GlobalMenuCtrl.prototype = {
         constructor: GlobalMenuCtrl,
 
         /**
          * Initialize the global menu controls.
          */
-        init: function() {
-            this.about.modal.init();
+        init: function () {
+            this.about.init();
         }
     }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/3c3304af/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-header-controller.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-header-controller.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-header-controller.js
index d29a638..bcbd690 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-header-controller.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-header-controller.js
@@ -17,19 +17,63 @@
 
 /* global nf, d3 */
 
-nf.ng.Canvas.HeaderCtrl = function (serviceProvider, toolboxCtrl, globalMenuCtrl) {
+nf.ng.Canvas.HeaderCtrl = function (serviceProvider, toolboxCtrl, globalMenuCtrl, flowStatusCtrl) {
     'use strict';
 
     var MIN_TOOLBAR_WIDTH = 640;
 
-    function HeaderCtrl(toolboxCtrl, globalMenuCtrl) {
+    var config = {
+        urls: {
+            accessConfig: '../nifi-api/access/config'
+        }
+    };
+
+    function HeaderCtrl(toolboxCtrl, globalMenuCtrl, flowStatusCtrl) {
         this.toolboxCtrl = toolboxCtrl;
         this.globalMenuCtrl = globalMenuCtrl;
+        this.flowStatusCtrl = flowStatusCtrl;
 
         /**
-         * The login link.
+         * The login controller.
          */
-        this.loginLink = {
+        this.loginCtrl = {
+
+            /**
+             * Initialize the login controller.
+             */
+            init: function () {
+                var self = this;
+
+                // if the user is not anonymous or accessing via http
+                if ($('#current-user').text() !== nf.Common.ANONYMOUS_USER_TEXT || location.protocol === 'http:') {
+                    $('#login-link-container').css('display', 'none');
+                }
+
+                // if accessing via http, don't show the current user
+                if (location.protocol === 'http:') {
+                    $('#current-user-container').css('display', 'none');
+                }
+
+                // get the login config
+                var loginXhr = $.ajax({
+                    type: 'GET',
+                    url: config.urls.accessConfig,
+                    dataType: 'json'
+                });
+
+                $.when(loginXhr).done(function (loginResult) {
+                    self.supportsLogin = loginResult.config.supportsLogin;
+                }).fail(nf.Common.handleAjaxError);
+            },
+
+            /**
+             * Boolean describing whether or not the NiFi instance supports login.
+             */
+            supportsLogin: undefined,
+
+            /**
+             * The login shell controller.
+             */
             shell: {
 
                 /**
@@ -42,22 +86,23 @@ nf.ng.Canvas.HeaderCtrl = function (serviceProvider, toolboxCtrl, globalMenuCtrl
         };
 
         /**
-         * Logout.
+         * The logout controller.
          */
-        this.logoutLink = {
+        this.logoutCtrl = {
             logout: function () {
                 nf.Storage.removeItem("jwt");
                 window.location = '/nifi';
             }
         };
     }
+
     HeaderCtrl.prototype = {
         constructor: HeaderCtrl,
 
         /**
          *  Register the header controller.
          */
-        register: function() {
+        register: function () {
             if (serviceProvider.headerCtrl === undefined) {
                 serviceProvider.register('headerCtrl', headerCtrl);
             }
@@ -65,26 +110,20 @@ nf.ng.Canvas.HeaderCtrl = function (serviceProvider, toolboxCtrl, globalMenuCtrl
 
         /**
          * Initialize the canvas header.
+         *
+         * @argument {boolean} supportsLogin    Whether login is supported.
          */
-        init: function() {
+        init: function () {
             this.toolboxCtrl.init();
             this.globalMenuCtrl.init();
-
-            // if the user is not anonymous or accessing via http
-            if ($('#current-user').text() !== nf.Common.ANONYMOUS_USER_TEXT || location.protocol === 'http:') {
-                $('#login-link-container').css('display', 'none');
-            }
-
-            // if accessing via http, don't show the current user
-            if (location.protocol === 'http:') {
-                $('#current-user-container').css('display', 'none');
-            }
+            this.flowStatusCtrl.init();
+            this.loginCtrl.init();
         },
 
         /**
          * Reloads and clears any warnings.
          */
-        reloadAndClearWarnings: function() {
+        reloadAndClearWarnings: function () {
             nf.Canvas.reload().done(function () {
                 // update component visibility
                 nf.Canvas.View.updateVisibility();
@@ -108,7 +147,7 @@ nf.ng.Canvas.HeaderCtrl = function (serviceProvider, toolboxCtrl, globalMenuCtrl
         }
     }
 
-    var headerCtrl = new HeaderCtrl(toolboxCtrl, globalMenuCtrl);
+    var headerCtrl = new HeaderCtrl(toolboxCtrl, globalMenuCtrl, flowStatusCtrl);
     headerCtrl.register();
     return headerCtrl;
 };
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/3c3304af/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-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
index f0dcbd3..9cd11d8 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
@@ -28,7 +28,8 @@ $(document).ready(function () {
         nf.ng.Canvas.AppCtrl.$inject = ['$scope', 'serviceProvider', 'headerCtrl', 'graphControlsCtrl'];
         nf.ng.ServiceProvider.$inject = [];
         nf.ng.BreadcrumbsCtrl.$inject = ['serviceProvider', '$sanitize'];
-        nf.ng.Canvas.HeaderCtrl.$inject = ['serviceProvider', 'toolboxCtrl', 'globalMenuCtrl'];
+        nf.ng.Canvas.HeaderCtrl.$inject = ['serviceProvider', 'toolboxCtrl', 'globalMenuCtrl', 'flowStatusCtrl'];
+        nf.ng.Canvas.FlowStatusCtrl.$inject = ['serviceProvider', '$sanitize'];
         nf.ng.Canvas.GlobalMenuCtrl.$inject = ['serviceProvider'];
         nf.ng.Canvas.ToolboxCtrl.$inject = ['processorComponent',
             'inputPortComponent',
@@ -64,6 +65,7 @@ $(document).ready(function () {
         app.service('headerCtrl', nf.ng.Canvas.HeaderCtrl);
         app.service('globalMenuCtrl', nf.ng.Canvas.GlobalMenuCtrl);
         app.service('toolboxCtrl', nf.ng.Canvas.ToolboxCtrl);
+        app.service('flowStatusCtrl', nf.ng.Canvas.FlowStatusCtrl);
         app.service('processorComponent', nf.ng.ProcessorComponent);
         app.service('inputPortComponent', nf.ng.InputPortComponent);
         app.service('outputPortComponent', nf.ng.OutputPortComponent);
@@ -126,15 +128,9 @@ nf.Canvas = (function () {
             authorities: '../nifi-api/controller/authorities',
             kerberos: '../nifi-api/access/kerberos',
             revision: '../nifi-api/flow/revision',
-            status: '../nifi-api/flow/status',
-            bulletinBoard: '../nifi-api/flow/bulletin-board',
             banners: '../nifi-api/flow/banners',
-            controller: '../nifi-api/controller',
             controllerConfig: '../nifi-api/controller/config',
-            about: '../nifi-api/flow/about',
-            accessConfig: '../nifi-api/access/config',
-            cluster: '../nifi-api/cluster',
-            d3Script: 'js/d3/d3.min.js'
+            cluster: '../nifi-api/cluster'
         }
     };
     
@@ -521,9 +517,7 @@ nf.Canvas = (function () {
             });
 
             //breadcrumbs
-            nf.ng.Bridge.call('appCtrl.serviceProvider.breadcrumbsCtrl',
-                'appCtrl.serviceProvider.breadcrumbsCtrl.updateBreadcrumbsCss',
-                {'bottom': bottom + 'px'});
+            nf.ng.Bridge.get('appCtrl.serviceProvider.breadcrumbsCtrl').updateBreadcrumbsCss({'bottom': bottom + 'px'});
 
             // body
             $('#canvas-body').css({
@@ -634,123 +628,6 @@ nf.Canvas = (function () {
     };
 
     /**
-     * Reloads the current status of this flow.
-     */
-    var reloadFlowStatus = function () {
-        return $.ajax({
-            type: 'GET',
-            url: config.urls.status,
-            dataType: 'json'
-        }).done(function (response) {
-            // report the updated status
-            if (nf.Common.isDefinedAndNotNull(response.controllerStatus)) {
-                var controllerStatus = response.controllerStatus;
-
-                // update the report values
-                $('#active-thread-count').text(controllerStatus.activeThreadCount);
-                $('#total-queued').text(controllerStatus.queued);
-
-                // update the connected nodes if applicable
-                if (nf.Common.isDefinedAndNotNull(controllerStatus.connectedNodes)) {
-                    var connectedNodes = controllerStatus.connectedNodes.split(' / ');
-                    if (connectedNodes.length === 2 && connectedNodes[0] !== connectedNodes[1]) {
-                        $('#connected-nodes-count').addClass('alert');
-                    } else {
-                        $('#connected-nodes-count').removeClass('alert');
-                    }
-
-                    // set the connected nodes
-                    $('#connected-nodes-count').text(controllerStatus.connectedNodes);
-                }
-
-                // update the component counts
-                if (nf.Common.isDefinedAndNotNull(controllerStatus.activeRemotePortCount)) {
-                    $('#controller-transmitting-count').text(controllerStatus.activeRemotePortCount);
-                } else {
-                    $('#controller-transmitting-count').text('-');
-                }
-                if (nf.Common.isDefinedAndNotNull(controllerStatus.inactiveRemotePortCount)) {
-                    $('#controller-not-transmitting-count').text(controllerStatus.inactiveRemotePortCount);
-                } else {
-                    $('#controller-not-transmitting-count').text('-');
-                }
-                if (nf.Common.isDefinedAndNotNull(controllerStatus.runningCount)) {
-                    $('#controller-running-count').text(controllerStatus.runningCount);
-                } else {
-                    $('#controller-running-count').text('-');
-                }
-                if (nf.Common.isDefinedAndNotNull(controllerStatus.stoppedCount)) {
-                    $('#controller-stopped-count').text(controllerStatus.stoppedCount);
-                } else {
-                    $('#controller-stopped-count').text('-');
-                }
-                if (nf.Common.isDefinedAndNotNull(controllerStatus.invalidCount)) {
-                    $('#controller-invalid-count').text(controllerStatus.invalidCount);
-                    if(controllerStatus.invalidCount > 0) {
-                        $('#controller-invalid-count').parent().css('color', '#BA554A');
-                    } else {
-                        $('#controller-invalid-count').parent().css('color', '#728E9B');
-                    }
-                } else {
-                    $('#controller-invalid-count').text('-');
-                }
-                if (nf.Common.isDefinedAndNotNull(controllerStatus.disabledCount)) {
-                    $('#controller-disabled-count').text(controllerStatus.disabledCount);
-                } else {
-                    $('#controller-disabled-count').text('-');
-                }
-
-                // icon for system bulletins
-                var bulletinIcon = $('#controller-bulletins');
-                var currentBulletins = bulletinIcon.data('bulletins');
-
-                // update the bulletins if necessary
-                if (nf.Common.doBulletinsDiffer(currentBulletins, controllerStatus.bulletins)) {
-                    bulletinIcon.data('bulletins', controllerStatus.bulletins);
-
-                    // get the formatted the bulletins
-                    var bulletins = nf.Common.getFormattedBulletins(controllerStatus.bulletins);
-
-                    // bulletins for this processor are now gone
-                    if (bulletins.length === 0) {
-                        if (bulletinIcon.data('qtip')) {
-                            bulletinIcon.removeClass('has-bulletins').qtip('api').destroy(true);
-                        }
-
-                        // hide the icon
-                        bulletinIcon.hide();
-                    } else {
-                        var newBulletins = nf.Common.formatUnorderedList(bulletins);
-
-                        // different bulletins, refresh
-                        if (bulletinIcon.data('qtip')) {
-                            bulletinIcon.qtip('option', 'content.text', newBulletins);
-                        } else {
-                            // no bulletins before, show icon and tips
-                            bulletinIcon.addClass('has-bulletins').qtip($.extend({
-                                content: newBulletins
-                            }, nf.CanvasUtils.config.systemTooltipConfig));
-                        }
-
-                        // show the icon
-                        bulletinIcon.show();
-                    }
-                }
-
-                // update controller service and reporting task bulletins
-                nf.Settings.setBulletins(controllerStatus.controllerServiceBulletins, controllerStatus.reportingTaskBulletins);
-
-                // handle any pending user request
-                if (controllerStatus.hasPendingAccounts === true) {
-                    $('#has-pending-accounts').show();
-                } else {
-                    $('#has-pending-accounts').hide();
-                }
-            }
-        }).fail(nf.Common.handleAjaxError);
-    };
-
-    /**
      * Refreshes the graph.
      *
      * @argument {string} processGroupId        The process group id
@@ -775,11 +652,8 @@ nf.Canvas = (function () {
             nf.Canvas.setGroupId(processGroupFlow.id);
 
             // update the breadcrumbs
-            nf.ng.Bridge.call('appCtrl.serviceProvider.breadcrumbsCtrl',
-                'appCtrl.serviceProvider.breadcrumbsCtrl.resetBreadcrumbs');
-            nf.ng.Bridge.call('appCtrl.serviceProvider.breadcrumbsCtrl',
-                'appCtrl.serviceProvider.breadcrumbsCtrl.generateBreadcrumbs',
-                processGroupFlow.breadcrumb);
+            nf.ng.Bridge.get('appCtrl.serviceProvider.breadcrumbsCtrl').resetBreadcrumbs();
+            nf.ng.Bridge.get('appCtrl.serviceProvider.breadcrumbsCtrl').generateBreadcrumbs(processGroupFlow.breadcrumb);
 
             // set the parent id if applicable
             if (nf.Common.isDefinedAndNotNull(processGroupFlow.parentGroupId)) {
@@ -881,12 +755,11 @@ nf.Canvas = (function () {
 
                 // get the process group to refresh everything
                 var processGroupXhr = reloadProcessGroup(nf.Canvas.getGroupId());
-                var statusXhr = reloadFlowStatus();
+                var statusXhr = nf.ng.Bridge.get('appCtrl.serviceProvider.headerCtrl.flowStatusCtrl').reloadFlowStatus();
                 var settingsXhr = nf.Settings.loadSettings(false); // don't reload the status as we want to wait for deferreds to complete
                 $.when(processGroupXhr, statusXhr, settingsXhr).done(function (processGroupResult) {
                     // adjust breadcrumbs if necessary
-                    nf.ng.Bridge.call('appCtrl.serviceProvider.breadcrumbsCtrl',
-                        'appCtrl.serviceProvider.breadcrumbsCtrl.resetScrollPosition');
+                    nf.ng.Bridge.get('appCtrl.serviceProvider.breadcrumbsCtrl').resetScrollPosition();
 
                     // don't load the status until the graph is loaded
                     reloadStatus(nf.Canvas.getGroupId()).done(function () {
@@ -904,7 +777,9 @@ nf.Canvas = (function () {
         reloadStatus: function () {
             return $.Deferred(function (deferred) {
                 // refresh the status and check any bulletins
-                $.when(reloadStatus(nf.Canvas.getGroupId()), reloadFlowStatus(), checkRevision()).done(function () {
+                $.when(reloadStatus(nf.Canvas.getGroupId()),
+                    nf.ng.Bridge.get('appCtrl.serviceProvider.headerCtrl.flowStatusCtrl').reloadFlowStatus(),
+                    checkRevision()).done(function () {
                     deferred.resolve();
                 }).fail(function () {
                     deferred.reject();
@@ -995,22 +870,6 @@ nf.Canvas = (function () {
                     dataType: 'json'
                 });
 
-                // get the about details
-                var aboutXhr = $.ajax({
-                    type: 'GET',
-                    url: config.urls.about,
-                    dataType: 'json'
-                }).done(function (response) {
-                    
-                }).fail(nf.Common.handleAjaxError);
-
-                // get the login config
-                var loginXhr = $.ajax({
-                    type: 'GET',
-                    url: config.urls.accessConfig,
-                    dataType: 'json'
-                });
-
                 // create the deferred cluster request
                 var isClusteredRequest = $.Deferred(function (deferred) {
                     $.ajax({
@@ -1030,10 +889,8 @@ nf.Canvas = (function () {
                 }).promise();
 
                 // ensure the config requests are loaded
-                $.when(configXhr, loginXhr, aboutXhr, userXhr).done(function (configResult, loginResult, aboutResult) {
+                $.when(configXhr, userXhr).done(function (configResult) {
                     var configResponse = configResult[0];
-                    var loginResponse = loginResult[0];
-                    var aboutResponse = aboutResult[0];
 
                     // calculate the canvas offset
                     var canvasContainer = $('#canvas-container');
@@ -1041,17 +898,6 @@ nf.Canvas = (function () {
 
                     // get the config details
                     var configDetails = configResponse.config;
-                    var loginDetails = loginResponse.config;
-                    var aboutDetails = aboutResponse.about;
-                    
-                    // set the document title and the about title
-                    document.title = aboutDetails.title;
-                    $('#nf-version').text(aboutDetails.version);
-                    
-                    // store the content viewer url if available
-                    if (!nf.Common.isBlank(aboutDetails.contentViewerUrl)) {
-                        $('#nifi-content-viewer-url').text(aboutDetails.contentViewerUrl);
-                    }
 
                     // when both request complete, load the application
                     isClusteredRequest.done(function () {
@@ -1068,9 +914,7 @@ nf.Canvas = (function () {
                         initCanvas();
                         nf.Canvas.View.init();
                         nf.ContextMenu.init();
-                        nf.ng.Bridge.call('appCtrl.serviceProvider.headerCtrl',
-                            'appCtrl.serviceProvider.headerCtrl.init', loginDetails.supportsLogin);
-                        nf.Search.init();
+                        nf.ng.Bridge.get('appCtrl.serviceProvider.headerCtrl').init();
                         nf.Settings.init();
                         nf.Actions.init();
                         nf.QueueListing.init();
@@ -1104,8 +948,7 @@ nf.Canvas = (function () {
                         nf.RemoteProcessGroupDetails.init();
                         nf.GoTo.init();
                         nf.Graph.init().done(function () {
-                            nf.ng.Bridge.call('appCtrl.serviceProvider.graphControlsCtrl',
-                                'appCtrl.serviceProvider.graphControlsCtrl.init');
+                            nf.ng.Bridge.get('appCtrl.serviceProvider.graphControlsCtrl').init();
 
                             // determine the split between the polling
                             var pollingSplit = autoRefreshIntervalSeconds / 2;

http://git-wip-us.apache.org/repos/asf/nifi/blob/3c3304af/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-search.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-search.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-search.js
deleted file mode 100644
index bfd42de..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-search.js
+++ /dev/null
@@ -1,179 +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.Search = (function () {
-
-    var config = {
-        search: 'Search',
-        urls: {
-            search: '../nifi-api/flow/search-results'
-        }
-    };
-
-    return {
-        /**
-         * Initialize the header by register all required listeners.
-         */
-        init: function () {
-            $.widget('nf.searchAutocomplete', $.ui.autocomplete, {
-                reset: function () {
-                    this.term = null;
-                },
-                _resizeMenu: function () {
-                    var ul = this.menu.element;
-                    ul.width(399);
-                },
-                _normalize: function(searchResults) {
-                    var items = [];
-                    items.push(searchResults);
-                    return items;
-                },
-                _renderMenu: function (ul, items) {
-                    var self = this;
-                    
-                    // the object that holds the search results is normalized into a single element array
-                    var searchResults = items[0];
-
-                    // show all processors
-                    if (!nf.Common.isEmpty(searchResults.processorResults)) {
-                        ul.append('<li class="search-header"><div class="search-result-icon"><i class="icon icon-processor"></i></div>Processors</li>');
-                        $.each(searchResults.processorResults, function (i, processorMatch) {
-                            self._renderItem(ul, processorMatch);
-                        });
-                    }
-
-                    // show all process groups
-                    if (!nf.Common.isEmpty(searchResults.processGroupResults)) {
-                        ul.append('<li class="search-header"><div class="search-result-icon"><i class="icon icon-group"></i></div>Process Groups</li>');
-                        $.each(searchResults.processGroupResults, function (i, processGroupMatch) {
-                            self._renderItem(ul, processGroupMatch);
-                        });
-                    }
-
-                    // show all remote process groups
-                    if (!nf.Common.isEmpty(searchResults.remoteProcessGroupResults)) {
-                        ul.append('<li class="search-header"><div class="search-result-icon"><i class="icon icon-group-remote"></i></div>Remote Process Groups</li>');
-                        $.each(searchResults.remoteProcessGroupResults, function (i, remoteProcessGroupMatch) {
-                            self._renderItem(ul, remoteProcessGroupMatch);
-                        });
-                    }
-
-                    // show all connections
-                    if (!nf.Common.isEmpty(searchResults.connectionResults)) {
-                        ul.append('<li class="search-header"><div class="search-result-icon"><i class="icon icon-connect"></i></div>Connections</li>');
-                        $.each(searchResults.connectionResults, function (i, connectionMatch) {
-                            self._renderItem(ul, connectionMatch);
-                        });
-                    }
-
-                    // show all input ports
-                    if (!nf.Common.isEmpty(searchResults.inputPortResults)) {
-                        ul.append('<li class="search-header"><div class="search-result-icon"><i class="icon icon-port-in"></i></div>Input Ports</li>');
-                        $.each(searchResults.inputPortResults, function (i, inputPortMatch) {
-                            self._renderItem(ul, inputPortMatch);
-                        });
-                    }
-
-                    // show all output ports
-                    if (!nf.Common.isEmpty(searchResults.outputPortResults)) {
-                        ul.append('<li class="search-header"><div class="search-result-icon"><i class="icon icon-port-out"></i></div>Output Ports</li>');
-                        $.each(searchResults.outputPortResults, function (i, outputPortMatch) {
-                            self._renderItem(ul, outputPortMatch);
-                        });
-                    }
-
-                    // show all funnels
-                    if (!nf.Common.isEmpty(searchResults.funnelResults)) {
-                        ul.append('<li class="search-header"><div class="search-result-icon"><i class="icon icon-funnel"></i></div>Funnels</li>');
-                        $.each(searchResults.funnelResults, function (i, funnelMatch) {
-                            self._renderItem(ul, funnelMatch);
-                        });
-                    }
-
-                    // ensure there were some results
-                    if (ul.children().length === 0) {
-                        ul.append('<li class="unset search-no-matches">No results matched the search terms</li>');
-                    }
-                },
-                _renderItem: function (ul, match) {
-                    var itemContent = $('<a></a>').append($('<div class="search-match-header"></div>').text(match.name));
-                    $.each(match.matches, function (i, match) {
-                        itemContent.append($('<div class="search-match"></div>').text(match));
-                    });
-                    return $('<li></li>').data('ui-autocomplete-item', match).append(itemContent).appendTo(ul);
-                }
-            });
-
-            // configure the search field
-            $('#search-field').searchAutocomplete({
-                appendTo: '#search-flow-results',
-                position: {
-                    my: 'right top',
-                    at: 'right bottom',
-                    offset: '1 1'
-                },
-                source: function (request, response) {
-                    // create the search request
-                    $.ajax({
-                        type: 'GET',
-                        data: {
-                            q: request.term
-                        },
-                        dataType: 'json',
-                        url: config.urls.search
-                    }).done(function (searchResponse) {
-                        response(searchResponse.searchResultsDTO);
-                    });
-                },
-                select: function (event, ui) {
-                    var item = ui.item;
-
-                    // show the selected component
-                    nf.CanvasUtils.showComponent(item.groupId, item.id);
-
-                    // blur the search field
-                    $(this).blur();
-
-                    // stop event propagation
-                    return false;
-                },
-                open: function (event, ui) {
-                    // show the glass pane
-                    var searchField = $(this);
-                    $('<div class="search-glass-pane"></div>').one('click', function () {
-                        // blur the field
-                        searchField.blur();
-                    }).appendTo('body');
-                },
-                close: function (event, ui) {
-                    // set the text to 'Search' and reset the cached term
-                    $(this).searchAutocomplete('reset');
-
-                    // remove the glass pane
-                    $('div.search-glass-pane').remove();
-                }
-            }).focus(function () {
-                // hide the context menu if necessary
-                nf.ContextMenu.hide();
-                
-                // clear the text for the user to type
-                $(this).val('').removeClass('search-flow');
-            }).blur(function () {
-                $(this).val(config.search).addClass('search-flow');
-            }).val(config.search).addClass('search-flow');
-        }
-    };
-}());
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/3c3304af/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js
index e014445..8e4c0a5 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js
@@ -1618,8 +1618,7 @@ nf.Settings = (function () {
             // refresh the system diagnostics when clicked
             nf.Common.addHoverEffect('#settings-refresh-button', 'button-refresh', 'button-refresh-hover').click(function () {
                 if ($('#settings-refresh-required-icon').is(':visible')) {
-                    nf.ng.Bridge.call('appCtrl.serviceProvider.headerCtrl',
-                        'appCtrl.serviceProvider.headerCtrl.reloadAndClearWarnings');
+                    nf.ng.Bridge.get('appCtrl.serviceProvider.headerCtrl').reloadAndClearWarnings();
                 } else {
                     nf.Settings.loadSettings();
                 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/3c3304af/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-ng-bridge.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-ng-bridge.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-ng-bridge.js
index 9d3485e..2ed2b2a 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-ng-bridge.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-ng-bridge.js
@@ -61,9 +61,10 @@ nf.ng.Bridge = (function () {
             angular.forEach(funArray, function (value) {
                 fun = fun[value];
             });
+
             var args = Array.prototype.slice.call(arguments, 2);
             var result = fun.apply(obj, args);
-            this.rootScope.$apply();
+
             if (result) {
                 return result;
             }
@@ -82,6 +83,7 @@ nf.ng.Bridge = (function () {
             angular.forEach(objArray, function (value) {
                 obj = obj[value];
             });
+
             return obj;
         },
 
@@ -89,7 +91,7 @@ nf.ng.Bridge = (function () {
             this.rootScope.$digest();
         }
     };
-    
+
     var angularBridge = new AngularBridge();
 
     return angularBridge;