Add plugins search box on the top navigation bar

Introduce a top search box to be able to filter the list of plugins.

Specifying a search keyword helps a lot on focusing on what the
administrator is looking for, without having to go through an
alphabetical long list.

Change-Id: I5af06c87c7d1232368bd52ff7ecc000924835824
diff --git a/src/main/resources/static/css/style.css b/src/main/resources/static/css/style.css
index e1d4044..ddcd2b2 100644
--- a/src/main/resources/static/css/style.css
+++ b/src/main/resources/static/css/style.css
@@ -31,4 +31,8 @@
 div.top-header {
   padding-left: 35px;
   padding-right: 35px;
+}
+
+.navbar-form input.searchbox {
+  width: 400px;
 }
\ No newline at end of file
diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html
index be86bd7..9ca7d04 100644
--- a/src/main/resources/static/index.html
+++ b/src/main/resources/static/index.html
@@ -14,21 +14,25 @@
 <link href="css/style.css" rel="stylesheet">
 </head>
 
-<body role="document">
+<body role="document" ng-controller="LoadInstalledPlugins as plugins">
   <nav class="navbar navbar-inverse navbar-fixed-top">
     <div class="container top-header">
       <div class="navbar-header">
         <a class="navbar-brand">Gerrit Plugins</a>
       </div>
       <div class="navbar-collapse collapse">
+        <form class="navbar-form navbar-left" role="search">
+          <div class="form-group">
+            <input type="text" class="form-control searchbox" placeholder="Search" ng-model="searchPlugin">
+          </div>
+        </form>
         <ul class="nav navbar-nav navbar-right">
           <li><a href="/">&gt; Go to Gerrit</a></li>
         </ul>
       </div>
     </div>
   </nav>
-  <div class="container main" role="main"
-    ng-controller="LoadInstalledPlugins as plugins">
+  <div class="container main" role="main">
     <div class="col-md-12">
       <table class="table table-striped">
         <thead>
@@ -41,24 +45,24 @@
           </tr>
         </thead>
         <tbody>
-          <tr ng-repeat="(key, prop) in plugins.list">
-            <td>{{key}}</td>
+          <tr ng-repeat="prop in plugins.list | filter:searchPlugin">
+            <td>{{prop.id}}</td>
             <td>{{prop.version}}</td>
             <td>{{prop.update_version}}</td>
             <td>{{prop.sha1}}</td>
             <td>
               <h5>
-                <span id="installing-{{key}}"
+                <span id="installing-{{prop.id}}"
                   class="label label-default hidden">Installing</span>
                 <span
-                  id="installed-{{key}}"
+                  id="installed-{{prop.id}}"
                   class="label label-success {{ (prop.version != '' && prop.update_version == '') ? '':'hidden' }}">Up to date</span>
                 <span
-                  id="failed-{{key}}" class="label label-warning hidden">Failed</span>
-                <button id="{{key}}" type="button"
+                  id="failed-{{prop.id}}" class="label label-warning hidden">Failed</span>
+                <button id="{{prop.id}}" type="button"
                   class="btn btn-xs btn-primary {{ (prop.version == '' && prop.update_version != undefined) ? '':'hidden' }}"
                   ng-click="install(prop.id,prop.url)">Install</button>
-                <button id="{{key}}" type="button"
+                <button id="{{prop.id}}" type="button"
                   class="btn btn-xs btn-primary {{ (prop.version != '' && prop.update_version != '') ? '':'hidden' }}"
                   ng-click="install(prop.id,prop.url)">Upgrade</button>
               </h5>
diff --git a/src/main/resources/static/js/plugin-manager.js b/src/main/resources/static/js/plugin-manager.js
index f721d42..b458bc2 100644
--- a/src/main/resources/static/js/plugin-manager.js
+++ b/src/main/resources/static/js/plugin-manager.js
@@ -17,22 +17,49 @@
     function($scope, $http) {
       var plugins = this;
 
-      plugins.list = {};
+      plugins.list = [];
 
       plugins.available = {};
 
+      $scope.searchPlugin = '';
+
+      $scope.pluginIndexOf = function(pluginId) {
+        var pluginIndex = -1
+
+        angular.forEach(plugins.list, function(row, rowIndex) {
+          if (row.id == pluginId) {
+            pluginIndex = rowIndex
+          }
+        });
+
+        return pluginIndex;
+      }
+
       $scope.refreshInstalled = function() {
         $http.get('/plugins/?all', plugins.httpConfig).then(
             function successCallback(response) {
 
               angular.forEach(response.data, function(plugin) {
-                plugins.list[plugin.id] = {
-                    id: plugin.id,
-                    index_url: plugin.index_url,
-                    version: plugin.version,
-                    sha1: '',
-                    url: plugin.url,
-                    update_version: ''
+                var currPluginIdx = $scope.pluginIndexOf(plugin.id);
+
+                if (currPluginIdx < 0) {
+                  plugins.list.push({
+                    id : plugin.id,
+                    index_url : plugin.index_url,
+                    version : plugin.version,
+                    sha1 : '',
+                    url : plugin.url,
+                    update_version : ''
+                  });
+                } else {
+                  plugins.list[currPluginIdx] = {
+                    id : plugin.id,
+                    index_url : plugin.index_url,
+                    version : plugin.version,
+                    sha1 : '',
+                    url : plugin.url,
+                    update_version : ''
+                  }
                 }
               });
 
@@ -43,34 +70,43 @@
 
       $scope.refreshAvailable = function() {
         $http.get('/plugins/plugin-manager/available', plugins.httpConfig)
-            .then(function successCallback(response) {
+            .then(
+                function successCallback(response) {
 
-              angular.forEach(response.data, function(plugin) {
-                var currPlugin = plugins.list[plugin.id];
+                  angular.forEach(response.data, function(plugin) {
+                    var currRow = $scope.pluginIndexOf(plugin.id);
+                    var currPlugin = currRow < 0 ? undefined
+                        : plugins.list[currRow];
 
-                if(currPlugin === undefined) {
-                  currPlugin = {
-                      id: plugin.id,
-                      index_url: '',
-                      version: ''
-                  }
-                }
+                    if (currPlugin === undefined) {
+                      currPlugin = {
+                        id : plugin.id,
+                        index_url : '',
+                        version : ''
+                      }
+                    }
 
-                if(plugin.version != currPlugin.version) {
-                  currPlugin.update_version = plugin.version;
-                }
-                currPlugin.sha1 = plugin.sha1;
-                currPlugin.url = plugin.url;
+                    if (plugin.version != currPlugin.version) {
+                      currPlugin.update_version = plugin.version;
+                    }
+                    currPlugin.sha1 = plugin.sha1;
+                    currPlugin.url = plugin.url;
 
-                plugins.list[plugin.id] = currPlugin;
-              });
-              plugins.available = response.data;
-            }, function errorCallback(response) {
-            });
+                    if (currRow < 0) {
+                      plugins.list.push(currPlugin);
+                    } else {
+                      plugins.list[currRow] = currPlugin;
+                    }
+                  });
+                  plugins.available = response.data;
+                }, function errorCallback(response) {
+                });
       }
 
       $scope.install = function(id, url) {
-        var pluginInstallData = { "url" : url };
+        var pluginInstallData = {
+          "url" : url
+        };
         $("button#" + id).addClass("hidden");
         $("span#installing-" + id).removeClass("hidden");
         $http.put('/a/plugins/' + id + ".jar", pluginInstallData).then(