Modernize web GUI and make it installable on BMC

1. Move from gulp server to webpack.  This allows the proper
compression to allow the webui to be embedded in the BMC.
2. Update js paths to use requires, not hardcoded paths.  This was
required to make the packaging work correctly.
3. Add babel config to do translation.
4. Update angularjs directive calls to use the angular 1.6 syntax for
promises intead of success and fail.

https://docs.angularjs.org/guide/migration#migrate1.5to1.6-ng-services-$http

5. As a consequence of using NPM/webpack, the versions of angular and
associated modules that were checked in have been updated.

Change-Id: Icb71e2eedb0d9a8943fc914f9dc4be11d0983c00
Signed-off-by: Ed Tanous <ed.tanous@intel.com>
Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
diff --git a/.babelrc b/.babelrc
new file mode 100644
index 0000000..c13c5f6
--- /dev/null
+++ b/.babelrc
@@ -0,0 +1,3 @@
+{
+  "presets": ["es2015"]
+}
diff --git a/.gitignore b/.gitignore
index 8574c3b..b36a8c0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@
 *.swp
 .idea
 app/styles/index.css
+yarn.lock
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index b0bbc50..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="ProjectModuleManager">
-    <modules>
-      <module fileurl="file://$PROJECT_DIR$/.idea/openbmc.iml" filepath="$PROJECT_DIR$/.idea/openbmc.iml" />
-    </modules>
-  </component>
-</project>
\ No newline at end of file
diff --git a/app/common/directives/app-header.html b/app/common/directives/app-header.html
index 0ba8607..e5071e4 100644
--- a/app/common/directives/app-header.html
+++ b/app/common/directives/app-header.html
@@ -5,7 +5,7 @@
 		<a href="" class="header__logout" ng-click="logout()">Log out</a>
 	</header>
 	<div class="header__functions-wrapper" role="heading">
-		<div class="logo__wrapper"><img src="assets/images/logo.svg" class="header__logo" alt="company logo"/></div>
+		<div class="logo__wrapper"><img src="../../assets/images/logo.svg" class="header__logo" alt="company logo"/></div>
 		<!-- <button class="inline header__multi-server" aria-label="multi server select" ng-class="{'active': multi_server_recent}" ng-click="multiRecent();">
 			<span class="icon icon-angle" aria-hidden="true"></span><span class="accessible-text">Multi server switcher</span>
 		</button>-->
@@ -31,4 +31,4 @@
 </div>
 
 <!-- multi-server recent dropdown -->
-<div ng-include="" src="'multi-server/controllers/multi-server-recent-controller.html'"></div>
\ No newline at end of file
+<div ng-include="" src="'multi-server/controllers/multi-server-recent-controller.html'"></div>
diff --git a/app/common/directives/app-header.js b/app/common/directives/app-header.js
index 6844c9c..69a9c7b 100644
--- a/app/common/directives/app-header.js
+++ b/app/common/directives/app-header.js
@@ -6,7 +6,7 @@
         .directive('appHeader', ['APIUtils', function (APIUtils) {
             return {
                 'restrict': 'E',
-                'templateUrl': 'common/directives/app-header.html',
+                'template': require('./app-header.html'),
                 'scope': {
                    'path': '='
                 },
diff --git a/app/common/directives/app-navigation.js b/app/common/directives/app-navigation.js
index daccb2f..2b7ad32 100644
--- a/app/common/directives/app-navigation.js
+++ b/app/common/directives/app-navigation.js
@@ -6,7 +6,7 @@
         .directive('appNavigation', function () {
             return {
                 'restrict': 'E',
-                'templateUrl': 'common/directives/app-navigation.html',
+                'template': require('./app-navigation.html'),
                 'scope': {
                     'path': '=',
                     'showNavigation': '='
diff --git a/app/common/directives/confirm.js b/app/common/directives/confirm.js
index ed8c9dc..5bb699a 100644
--- a/app/common/directives/confirm.js
+++ b/app/common/directives/confirm.js
@@ -6,7 +6,7 @@
         .directive('confirm', ['$timeout', function($timeout){
             return {
                 'restrict': 'E',
-                'templateUrl': 'common/directives/confirm.html',
+                'template': require('./confirm.html'),
                 'scope': {
                    'title': '@',
                    'message': '@',
diff --git a/app/common/directives/firmware-list.js b/app/common/directives/firmware-list.js
index 6cfa3a1..781257e 100644
--- a/app/common/directives/firmware-list.js
+++ b/app/common/directives/firmware-list.js
@@ -6,7 +6,7 @@
         .directive('firmwareList', ['APIUtils', function (APIUtils) {
             return {
                 'restrict': 'E',
-                'templateUrl': 'common/directives/firmware-list.html',
+                'template': require('./firmware-list.html'),
                 'scope': {
                    'title': '@',
                    'firmwares': '=',
diff --git a/app/common/directives/loader.js b/app/common/directives/loader.js
index 9a06055..b37a898 100644
--- a/app/common/directives/loader.js
+++ b/app/common/directives/loader.js
@@ -6,11 +6,11 @@
         .directive('loader', function () {
             return {
                 'restrict': 'E',
-                'templateUrl': 'common/directives/loader.html',
+                'template': require('./loader.html'),
                 scope: {
                     loading: '='
                 }
             };
         });
 
-})(window.angular);
\ No newline at end of file
+})(window.angular);
diff --git a/app/common/directives/log-event.html b/app/common/directives/log-event.html
index 350cc8d..970598d 100644
--- a/app/common/directives/log-event.html
+++ b/app/common/directives/log-event.html
@@ -41,7 +41,7 @@
              <div>
                  <div class="event__actions">
                      <button class="btn-meta-copy" clipboard text="event.additional_data" on-copied="copySuccess(event)" on-error="copyfailed(err)">
-                        <img class="event__icon" src="assets/images/icon-copy.svg" alt=""/><span ng-if="!event.copied">Copy</span><span ng-if="event.copied">Copied</span>
+                        <img class="event__icon" src="../../assets/images/icon-copy.svg" alt=""/><span ng-if="!event.copied">Copy</span><span ng-if="event.copied">Copied</span>
                      </button>
                      <button
                              class="btn-delete"
@@ -50,10 +50,10 @@
                              ng-disabled="multiSelected">
                              <img
                              class="event__icon"
-                             src="assets/images/icon-trashcan.svg"
+                             src="../../assets/images/icon-trashcan.svg"
                              alt=""/>Delete
                      </button>
-                     <button class="btn-resolve" ng-class="{'disabled': (event.Resolved == 1 || multiSelected)}" ng-click="resolveEvent(event)" ng-disabled="event.Resolved == 1 || multiSelected"><img class="event__icon" src="assets/images/icon-check.svg" alt=""/>Mark as resolved</button>
+                     <button class="btn-resolve" ng-class="{'disabled': (event.Resolved == 1 || multiSelected)}" ng-click="resolveEvent(event)" ng-disabled="event.Resolved == 1 || multiSelected"><img class="event__icon" src="../../assets/images/icon-check.svg" alt=""/>Mark as resolved</button>
                  </div>
                  <div class="event__related" ng-show="event.related_items.length">
                      <p class="inline event__related-label">Related items:</p>
@@ -62,4 +62,4 @@
              </div>
          </div>
      </div>
-</div>
\ No newline at end of file
+</div>
diff --git a/app/common/directives/log-event.js b/app/common/directives/log-event.js
index 51bb5dd..e858239 100644
--- a/app/common/directives/log-event.js
+++ b/app/common/directives/log-event.js
@@ -6,7 +6,7 @@
         .directive('logEvent', ['APIUtils', function (APIUtils) {
             return {
                 'restrict': 'E',
-                'templateUrl': 'common/directives/log-event.html',
+                'template': require('./log-event.html'),
                 'scope': {
                    'event': '=',
                    'tmz': '=',
diff --git a/app/common/directives/log-filter.js b/app/common/directives/log-filter.js
index 527d347..bc2da0e 100644
--- a/app/common/directives/log-filter.js
+++ b/app/common/directives/log-filter.js
@@ -6,7 +6,7 @@
         .directive('logFilter', ['APIUtils', function (APIUtils) {
             return {
                 'restrict': 'E',
-                'templateUrl': 'common/directives/log-filter.html',
+                'template': require('./log-filter.html'),
                 'controller': ['$rootScope', '$scope','dataService', '$location', function($rootScope, $scope, dataService, $location){
                     $scope.dataService = dataService;
                     $scope.toggleSeverityAll = function(){
diff --git a/app/common/directives/log-search-control.js b/app/common/directives/log-search-control.js
index b198f2d..c610c18 100644
--- a/app/common/directives/log-search-control.js
+++ b/app/common/directives/log-search-control.js
@@ -6,7 +6,7 @@
         .directive('logSearchControl', ['APIUtils', function (APIUtils) {
             return {
                 'restrict': 'E',
-                'templateUrl': 'common/directives/log-search-control.html',
+                'template': require('./log-search-control.html'),
                 'controller': ['$rootScope', '$scope','dataService', '$location', function($rootScope, $scope, dataService, $location){
                     $scope.dataService = dataService;
                     $scope.doSearchOnEnter = function (event) {
diff --git a/app/common/services/api-utils.js b/app/common/services/api-utils.js
index a7a6a58..3d0f853 100644
--- a/app/common/services/api-utils.js
+++ b/app/common/services/api-utils.js
@@ -31,11 +31,11 @@
                       'Content-Type': 'application/json'
                   },
                   withCredentials: true
-                }).success(function(response){
-                      var json = JSON.stringify(response);
+                }).then(function(response){
+                      var json = JSON.stringify(response.data);
                       var content = JSON.parse(json);
                       callback(content.data.CurrentPowerState);
-                }).error(function(error){
+                }, function(error){
                   console.log(error);
                 });
               },
@@ -48,11 +48,11 @@
                       'Content-Type': 'application/json'
                   },
                   withCredentials: true
-                }).success(function(response){
-                      var json = JSON.stringify(response);
+                }).then(function(response){
+                      var json = JSON.stringify(response.data);
                       var content = JSON.parse(json);
                       callback(content.data.CurrentHostState);
-                }).error(function(error){
+                }, function(error){
                   console.log(error);
                 });
               },
@@ -66,8 +66,8 @@
                       'Content-Type': 'application/json'
                   },
                   withCredentials: true
-                }).success(function(response){
-                    var json = JSON.stringify(response);
+                }).then(function(response){
+                    var json = JSON.stringify(response.data);
                     var content = JSON.parse(json);
                     var hostname = "";
                     var macAddress = "";
@@ -139,7 +139,7 @@
                       mac_address: macAddress,
                       formatted_data: parseNetworkData(content)
                     });
-                }).error(function(error){
+                }, function(error){
                   console.log(error);
                   deferred.reject(error);
                 });
@@ -155,11 +155,11 @@
                       'Content-Type': 'application/json'
                   },
                   withCredentials: true
-                }).success(function(response){
-                    var json = JSON.stringify(response);
+                }).then(function(response){
+                    var json = JSON.stringify(response.data);
                     var content = JSON.parse(json);
                     deferred.resolve(content.data.Asserted);
-                }).error(function(error){
+                }, function(error){
                   console.log(error);
                   deferred.reject(error);
                 });
@@ -175,11 +175,11 @@
                   },
                   withCredentials: true,
                   data: JSON.stringify({"data": [username, password]})
-                }).success(function(response){
+                }).then(function(response){
                   if(callback){
-                      callback(response);
+                      callback(response.data);
                   }
-                }).error(function(error){
+                }, function(error){
                   if(callback){
                       if(error && error.status && error.status == 'error'){
                         callback(error);
@@ -200,11 +200,11 @@
                   },
                   withCredentials: true,
                   data: JSON.stringify({"data": []})
-                }).success(function(response){
+                }).then(function(response){
                   if(callback){
                       callback(response);
                   }
-                }).error(function(error){
+                }, function(error){
                   if(callback){
                       callback(null, error);
                   }
@@ -221,13 +221,13 @@
                   },
                   withCredentials: true,
                   data: JSON.stringify({"data": []})
-                }).success(function(response){
-                      var json = JSON.stringify(response);
+                }).then(function(response){
+                      var json = JSON.stringify(response.data);
                       var content = JSON.parse(json);
                       if(callback){
                           return callback(content.data.CurrentPowerState);
                       }
-                }).error(function(error){
+                }, function(error){
                   if(callback){
                       callback(error);
                   }else{
@@ -245,13 +245,13 @@
                   },
                   withCredentials: true,
                   data: JSON.stringify({"data": []})
-                }).success(function(response){
-                      var json = JSON.stringify(response);
+                }).then(function(response){
+                      var json = JSON.stringify(response.data);
                       var content = JSON.parse(json);
                       if(callback){
                           return callback(content.data.CurrentPowerState);
                       }
-                }).error(function(error){
+                }, function(error){
                   if(callback){
                       callback(error);
                   }else{
@@ -269,13 +269,13 @@
                   },
                   withCredentials: true,
                   data: JSON.stringify({"data": state})
-                }).success(function(response){
-                      var json = JSON.stringify(response);
+                }).then(function(response){
+                      var json = JSON.stringify(response.data);
                       var content = JSON.parse(json);
                       if(callback){
                           return callback(content.status);
                       }
-                }).error(function(error){
+                }, function(error){
                   if(callback){
                       callback(error);
                   }else{
@@ -293,13 +293,13 @@
                   },
                   withCredentials: true,
                   data: JSON.stringify({"data": "xyz.openbmc_project.State.BMC.Transition.Reboot"})
-                }).success(function(response){
-                      var json = JSON.stringify(response);
+                }).then(function(response){
+                      var json = JSON.stringify(response.data);
                       var content = JSON.parse(json);
                       if(callback){
                           return callback(content.status);
                       }
-                }).error(function(error){
+                }, function(error){
                   if(callback){
                       callback(error);
                   }else{
@@ -317,13 +317,13 @@
                   },
                   withCredentials: true,
                   data: JSON.stringify({"data": "xyz.openbmc_project.State.Host.Transition.On"})
-                }).success(function(response){
-                      var json = JSON.stringify(response);
+                }).then(function(response){
+                      var json = JSON.stringify(response.data);
                       var content = JSON.parse(json);
                       if(callback){
                           return callback(content.status);
                       }
-                }).error(function(error){
+                }, function(error){
                   if(callback){
                       callback(error);
                   }else{
@@ -341,13 +341,13 @@
                   },
                   withCredentials: true,
                   data: JSON.stringify({"data": "xyz.openbmc_project.State.Host.Transition.Off"})
-                }).success(function(response){
-                      var json = JSON.stringify(response);
+                }).then(function(response){
+                      var json = JSON.stringify(response.data);
                       var content = JSON.parse(json);
                       if(callback){
                           return callback(content.status);
                       }
-                }).error(function(error){
+                }, function(error){
                   if(callback){
                       callback(error);
                   }else{
@@ -365,13 +365,13 @@
                   },
                   withCredentials: true,
                   data: JSON.stringify({"data": []}),
-                }).success(function(response){
-                      var json = JSON.stringify(response);
+                }).then(function(response){
+                      var json = JSON.stringify(response.data);
                       var content = JSON.parse(json);
                       if(callback){
                           return callback(content);
                       }
-                }).error(function(error){
+                }, function(error){
                   if(callback){
                       callback(error);
                   }else{
@@ -389,13 +389,13 @@
                   },
                   withCredentials: true,
                   data: JSON.stringify({"data": []})
-                }).success(function(response){
-                      var json = JSON.stringify(response);
+                }).then(function(response){
+                      var json = JSON.stringify(response.data);
                       var content = JSON.parse(json);
                       if(callback){
                           return callback(content);
                       }
-                }).error(function(error){
+                }, function(error){
                   if(callback){
                       callback(error);
                   }else{
@@ -413,8 +413,8 @@
                       'Content-Type': 'application/json'
                   },
                   withCredentials: true
-                }).success(function(response){
-                      var json = JSON.stringify(response);
+                }).then(function(response){
+                      var json = JSON.stringify(response.data);
                       var content = JSON.parse(json);
                       var dataClone = JSON.parse(JSON.stringify(content.data));
                       var data = [];
@@ -455,7 +455,7 @@
                         }
                       }
                       deferred.resolve({data: data, original: dataClone});
-                }).error(function(error){
+                }, function(error){
                   console.log(error);
                   deferred.reject(error);
                 });
@@ -471,8 +471,8 @@
                       'Content-Type': 'application/json'
                   },
                   withCredentials: true
-                }).success(function(response){
-                      var json = JSON.stringify(response);
+                }).then(function(response){
+                      var json = JSON.stringify(response.data);
                       var content = JSON.parse(json);
                       var dataClone = JSON.parse(JSON.stringify(content.data));
                       var sensorData = [];
@@ -586,7 +586,7 @@
                       }
 
                       callback(sensorData, dataClone);
-                }).error(function(error){
+                }, function(error){
                   console.log(error);
                 });
               },
@@ -600,8 +600,8 @@
                       'Content-Type': 'application/json'
                   },
                   withCredentials: true
-                }).success(function(response){
-                      var json = JSON.stringify(response);
+                }).then(function(response){
+                      var json = JSON.stringify(response.data);
                       var content = JSON.parse(json);
                       var data = [];
                       var active = false;
@@ -681,7 +681,7 @@
                           bmcActiveVersion: bmcActiveVersion, 
                           hostActiveVersion: hostActiveVersion
                       });
-                }).error(function(error){
+                }, function(error){
                   console.log(error);
                   deferred.reject(error);
                 });
@@ -699,11 +699,11 @@
                   },
                   withCredentials: true,
                   data: JSON.stringify({"data": priority})
-                }).success(function(response){
-                      var json = JSON.stringify(response);
+                }).then(function(response){
+                      var json = JSON.stringify(response.data);
                       var content = JSON.parse(json);
                       deferred.resolve(content);
-                }).error(function(error){
+                }, function(error){
                   console.log(error);
                   deferred.reject(error);
                 });
@@ -721,11 +721,11 @@
                   },
                   withCredentials: true,
                   data: JSON.stringify({"data": []})
-                }).success(function(response){
-                      var json = JSON.stringify(response);
+                }).then(function(response){
+                      var json = JSON.stringify(response.data);
                       var content = JSON.parse(json);
                       deferred.resolve(content);
-                }).error(function(error){
+                }, function(error){
                   console.log(error);
                   deferred.reject(error);
                 });
@@ -743,11 +743,11 @@
                   },
                   withCredentials: true,
                   data: JSON.stringify({"data": Constants.FIRMWARE.ACTIVATE_FIRMWARE})
-                }).success(function(response){
-                      var json = JSON.stringify(response);
+                }).then(function(response){
+                      var json = JSON.stringify(response.data);
                       var content = JSON.parse(json);
                       deferred.resolve(content);
-                }).error(function(error){
+                }, function(error){
                   console.log(error);
                   deferred.reject(error);
                 });
@@ -765,11 +765,11 @@
                   },
                   withCredentials: true,
                   data: file
-                }).success(function(response){
-                      var json = JSON.stringify(response);
+                }).then(function(response){
+                      var json = JSON.stringify(response.data);
                       var content = JSON.parse(json);
                       deferred.resolve(content);
-                }).error(function(error){
+                }, function(error){
                   console.log(error);
                   deferred.reject(error);
                 });
@@ -788,13 +788,13 @@
                   withCredentials: true,
                   data: JSON.stringify({"data": [host, filename]}),
                   responseType: 'arraybuffer'
-                }).success(function(response, status, headers){
+                }).then(function(response, status, headers){
                   deferred.resolve({
                     data: response,
                     status: status,
                     headers: headers
                   });
-                }).error(function(error){
+                }, function(error){
                   console.log(error);
                   deferred.reject(error);
                 });
@@ -811,11 +811,11 @@
                       'Content-Type': 'application/json'
                   },
                   withCredentials: true
-                }).success(function(response){
-                    var json = JSON.stringify(response);
+                }).then(function(response){
+                    var json = JSON.stringify(response.data);
                     var content = JSON.parse(json);
                     deferred.resolve(content.data);
-                }).error(function(error){
+                }, function(error){
                   console.log(error);
                   deferred.reject(error);
                 });
@@ -832,11 +832,11 @@
                       'Content-Type': 'application/json'
                   },
                   withCredentials: true
-                }).success(function(response){
-                    var json = JSON.stringify(response);
+                }).then(function(response){
+                    var json = JSON.stringify(response.data);
                     var content = JSON.parse(json);
                     deferred.resolve(content.data);
-                }).error(function(error){
+                }, function(error){
                   console.log(error);
                   deferred.reject(error);
                 });
@@ -851,8 +851,8 @@
                       'Content-Type': 'application/json'
                   },
                   withCredentials: true
-                }).success(function(response){
-                      var json = JSON.stringify(response);
+                }).then(function(response){
+                      var json = JSON.stringify(response.data);
                       var content = JSON.parse(json);
                       var hardwareData = [];
                       var keyIndexMap = {};
diff --git a/app/common/services/apiInterceptor.js b/app/common/services/apiInterceptor.js
index d1a23ad..8bbb6f4 100644
--- a/app/common/services/apiInterceptor.js
+++ b/app/common/services/apiInterceptor.js
@@ -43,14 +43,19 @@
                     return response;
                 },
                 'responseError': function(rejection){
-                    dataService.server_unreachable = true;
-                    dataService.loading = false;
-                    if(dataService.path != '/login'){
-                        $rootScope.$emit('timedout-user', {});
+                    // If unauthorized, log out
+                    if (rejection.status == 401){
+                        if (dataService.path != '/login'){
+                            $rootScope.$emit('timedout-user', {});
+                        }
+                    } else if (rejection.status == -1){
+                        dataService.server_unreachable = true;
                     }
+
+                    dataService.loading = false;
                     return $q.reject(rejection);
                 }
             };
         }]);
 
-})(window.angular);
\ No newline at end of file
+})(window.angular);
diff --git a/app/common/services/constants.js b/app/common/services/constants.js
index 76bc590..373fab1 100644
--- a/app/common/services/constants.js
+++ b/app/common/services/constants.js
@@ -12,7 +12,7 @@
     'use strict';
 
     angular
-        .module('app.common.services')
+        .module('app.common.services', [])
         .service('Constants', function () {
             return {
                 LOGIN_CREDENTIALS: {
@@ -122,4 +122,4 @@
             };
         });
 
-})(window.angular);
\ No newline at end of file
+})(window.angular);
diff --git a/app/common/services/userModel.js b/app/common/services/userModel.js
index a3fc277..2c9de65 100644
--- a/app/common/services/userModel.js
+++ b/app/common/services/userModel.js
@@ -20,8 +20,9 @@
                 },
                 login : function(username, password, callback){
                     APIUtils.login(username, password, function(response, error){
-                        if(response && 
-                           response.status == APIUtils.API_RESPONSE.SUCCESS_STATUS){
+                        if(response &&
+                            (response.status == APIUtils.API_RESPONSE.SUCCESS_STATUS
+                                || response.status === undefined)){
                             sessionStorage.setItem('LOGIN_ID', username);
                             callback(true);
                         }else{
@@ -52,4 +53,4 @@
             };
         }]);
 
-})(window.angular);
\ No newline at end of file
+})(window.angular);
diff --git a/app/common/styles/base/icons.scss b/app/common/styles/base/icons.scss
index 47523fe..43d3669 100644
--- a/app/common/styles/base/icons.scss
+++ b/app/common/styles/base/icons.scss
@@ -65,7 +65,7 @@
 
 .icon__warning {
   @include status-icon;
-  background-image: url(/assets/images/icon-warning.svg);
+  background-image: url(../assets/images/icon-warning.svg);
 }
 
 .modal .icon__warning {
@@ -75,32 +75,32 @@
 
 .icon__critical {
   @include status-icon;
-  background-image: url(/assets/images/icon-critical.svg);
+  background-image: url(../assets/images/icon-critical.svg);
 }
 
 .icon__good {
   @include status-icon;
-  background-image: url(/assets/images/icon-on.svg);
+  background-image: url(../assets/images/icon-on.svg);
 }
 
 .icon__off {
   @include status-icon;
-  background-image: url(/assets/images/icon-off.svg);
+  background-image: url(../assets/images/icon-off.svg);
 }
 
 .icon__return {
   @include status-icon;
-  background-image: url(/assets/images/icon-return.svg);
+  background-image: url(../assets/images/icon-return.svg);
 }
 
 .icon__standby {
   @include status-icon;
-  background-image: url(/assets/images/icon-standby.svg);
+  background-image: url(../assets/images/icon-standby.svg);
 }
 
 .icon__plus {
   @include status-icon;
-  background-image: url(/assets/images/icon-plus.svg);
+  background-image: url(../assets/images/icon-plus.svg);
 }
 
 .icon__info{
@@ -115,14 +115,14 @@
 .icon__up-arrow {
   margin-right: .4em;
   margin-bottom: -15px;
-  background: url(/assets/images/icon-arrow-blue.svg) center center no-repeat;
+  background: url(../assets/images/icon-arrow-blue.svg) center center no-repeat;
   height: 40px;
   width: 30px;
   &.icon-as-spacer {
-    background: url(/assets/images/icon-arrow-gray.svg) center center no-repeat;
+    background: url(../assets/images/icon-arrow-gray.svg) center center no-repeat;
   }
 }
 .icon__down-arrow {
   @extend .icon__up-arrow;
   transform: rotate(180deg);
-}
\ No newline at end of file
+}
diff --git a/app/common/styles/elements/index.scss b/app/common/styles/elements/index.scss
index 677a4ba..757ff26 100644
--- a/app/common/styles/elements/index.scss
+++ b/app/common/styles/elements/index.scss
@@ -10,4 +10,4 @@
 @import "tags";
 @import "export";
 @import "modals";
-@import "quicklinks";
\ No newline at end of file
+@import "quicklinks";
diff --git a/app/common/styles/elements/tags.scss b/app/common/styles/elements/tags.scss
index d2fff03..e6f9bc7 100644
--- a/app/common/styles/elements/tags.scss
+++ b/app/common/styles/elements/tags.scss
@@ -104,7 +104,7 @@
   &.high-priority {
     color: $critical-lightbg;
     background-color: rgba( $critical-lightbg, .4 );
-    background-image: url(/assets/images/crit-x.svg);
+    background-image: url(../assets/images/crit-x.svg);
     border-color: $critical-lightbg;
     &:before {
       content: '';
@@ -123,7 +123,7 @@
   }
   &.warn-priority {
     border-color: $warning-lightbg;
-    background-image: url(/assets/images/warn-slash.svg);
+    background-image: url(../assets/images/warn-slash.svg);
     background-color: rgba($thresh-warning, .3);
   }
   &.normal-priority {
@@ -137,4 +137,4 @@
     background: $purple;
     padding: 2px 1em;
   }
-}
\ No newline at end of file
+}
diff --git a/app/configuration/index.js b/app/configuration/index.js
index f0918e0..f6339fe 100644
--- a/app/configuration/index.js
+++ b/app/configuration/index.js
@@ -19,29 +19,29 @@
         .config(['$routeProvider', function ($routeProvider) {
             $routeProvider
                 .when('/configuration/network', {
-                    'templateUrl': 'configuration/controllers/network-controller.html',
+                    'template': require('./controllers/network-controller.html'),
                     'controller': 'networkController',
                     authenticated: true
                 })
                 .when('/configuration/security', {
-                    'templateUrl': 'configuration/controllers/security-controller.html',
+                    'template': require('./controllers/security-controller.html'),
                     'controller': 'securityController',
                     authenticated: true
                 }).when('/configuration/date-time', {
-                    'templateUrl': 'configuration/controllers/date-time-controller.html',
+                    'template': require('./controllers/date-time-controller.html'),
                     'controller': 'dateTimeController',
                     authenticated: true
                 })
                 .when('/configuration/file', {
-                    'templateUrl': 'configuration/controllers/file-controller.html',
+                    'template': require('./controllers/file-controller.html'),
                     'controller': 'fileController',
                     authenticated: true
                 }).when('/configuration', {
-                    'templateUrl': 'configuration/controllers/network-controller.html',
+                    'template': require('./controllers/network-controller.html'),
                     'controller': 'networkController',
                     authenticated: true
                 }).when('/configuration/firmware', {
-                'templateUrl': 'configuration/controllers/firmware-controller.html',
+                'template': require('./controllers/firmware-controller.html'),
                 'controller': 'firmwareController',
                 authenticated: true
             });
diff --git a/app/firmware/index.js b/app/firmware/index.js
index 8094a40..01fed6b 100644
--- a/app/firmware/index.js
+++ b/app/firmware/index.js
@@ -19,17 +19,17 @@
         .config(['$routeProvider', function ($routeProvider) {
             $routeProvider
                 .when('/firmware/bmc', {
-                    'templateUrl': 'firmware/controllers/bmc-controller.html',
+                    'template': require('./controllers/bmc-controller.html'),
                     'controller': 'bmcController',
                     authenticated: true
                 })
                 .when('/firmware/server', {
-                    'templateUrl': 'firmware/controllers/server-controller.html',
+                    'template': require('./controllers/server-controller.html'),
                     'controller': 'serverController',
                     authenticated: true
                 })
                 .when('/firmware', {
-                    'templateUrl': 'firmware/controllers/bmc-controller.html',
+                    'template': reqire('./controllers/bmc-controller.html'),
                     'controller': 'bmcController',
                     authenticated: true
                 });
diff --git a/app/index.html b/app/index.html
index 1f2b758..502424d 100644
--- a/app/index.html
+++ b/app/index.html
@@ -1,14 +1,13 @@
-<!DOCTYPE html>
-<html lang="en" ng-app="app">
-<head>
-    <base href="/">
-    <meta charset="UTF-8">
-    <title>openBMC</title>
-    <link rel="icon" href="favicon.ico?v=2"/>
-    <!-- build:css styles/app.min.css -->
-    <link rel="stylesheet" href="styles/index.css">
+<!doctype html>
+<html ng-app="app" lang="en">
 
-    <!-- endbuild -->
+<head>
+    <meta charset="UTF-8">
+    <title>openBMC App</title>
+    <link rel="icon" type="image/x-icon" href="/img/favicon.ico">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+
+    <base href="/">
 </head>
 <body ng-style="dataService.bodyStyle" ng-attr-id="{{!dataService.showNavigation ? 'login': ''}}">
 
@@ -18,73 +17,5 @@
     <main ng-view ng-class="{'content__container': dataService.showNavigation, 'login__wrapper': !dataService.showNavigation}">
     </main>
 
-	<!-- build:js scripts/vendor.min.js -->
-	<script src="../bower_components/angular/angular.min.js"></script>
-	<script src="../bower_components/angular-route/angular-route.min.js"></script>
-	<script src="../bower_components/angular-clipboard/angular-clipboard.min.js"></script>
-    <script src="../bower_components/angularUtils-pagination/dirPagination.min.js"></script>
-    <script src="vendors/hterm/hterm_all.min.js"></script>
-
-	<!-- endbuild -->
-
-	<!-- build:js scripts/app.min.js -->
-	<script src="index.js"></script>
-	<script src="templates.js"></script>
-	<script src="vendors.js"></script>
-
-	<script src="constants/index.js"></script>
-	<script src="constants/environment-constants.js"></script>
-
-	<script src="common/services/index.js"></script>
-	<script src="common/services/constants.js"></script>
-	<script src="common/services/dataService.js"></script>
-	<script src="common/services/api-utils.js"></script>
-	<script src="common/services/userModel.js"></script>
-	<script src="common/services/apiInterceptor.js"></script>
-
-	<script src="common/filters/index.js"></script>
-
-	<script src="common/directives/index.js"></script>
-	<script src="common/directives/app-header.js"></script>
-	<script src="common/directives/app-navigation.js"></script>
-	<script src="common/directives/confirm.js"></script>
-	<script src="common/directives/log-event.js"></script>
-	<script src="common/directives/log-filter.js"></script>
-	<script src="common/directives/log-search-control.js"></script>
-    <script src="common/directives/toggle-flag.js"></script>
-    <script src="common/directives/firmware-list.js"></script>
-    <script src="common/directives/file.js"></script>
-    <script src="common/directives/loader.js"></script>
-
-    <script src="login/index.js"></script>
-    <script src="login/controllers/login-controller.js"></script>
-    <script src="overview/index.js"></script>
-    <script src="overview/controllers/system-overview-controller.js"></script>
-    <script src="server-control/index.js"></script>
-    <script src="server-control/controllers/bmc-reboot-controller.js"></script>
-    <script src="server-control/controllers/power-operations-controller.js"></script>
-    <script src="server-control/controllers/remote-console-controller.js"></script>
-    <script src="server-control/controllers/remote-console-window-controller.js"></script>
-    <script src="server-health/index.js"></script>
-    <script src="server-health/controllers/diagnostics-controller.js"></script>
-    <script src="server-health/controllers/inventory-controller.js"></script>
-    <script src="server-health/controllers/inventory-overview-controller.js"></script>
-    <script src="server-health/controllers/log-controller.js"></script>
-    <script src="server-health/controllers/power-consumption-controller.js"></script>
-    <script src="server-health/controllers/sensors-controller.js"></script>
-    <script src="server-health/controllers/sensors-overview-controller.js"></script>
-    <script src="server-health/controllers/unit-id-controller.js"></script>
-    <script src="configuration/index.js"></script>
-    <script src="configuration/controllers/date-time-controller.js"></script>
-    <script src="configuration/controllers/file-controller.js"></script>
-    <script src="configuration/controllers/network-controller.js"></script>
-    <script src="configuration/controllers/security-controller.js"></script>
-    <script src="configuration/controllers/firmware-controller.js"></script>
-    <script src="users/index.js"></script>
-    <script src="users/controllers/user-accounts-controller.js"></script>
-    <script src="multi-server/index.js"></script>
-    <script src="multi-server/controllers/multi-server-controller.js"></script>
-	<!-- endbuild -->
 </body>
-
 </html>
diff --git a/app/index.js b/app/index.js
index fc781b3..3f277a9 100644
--- a/app/index.js
+++ b/app/index.js
@@ -9,6 +9,90 @@
  * @since 0.0.1
  */
 
+import 'bootstrap/dist/css/bootstrap.css';
+import 'bootstrap/dist/css/bootstrap-theme.css';
+import "font-awesome/css/font-awesome.css"
+import angular from 'angular';
+import angular_cookies from 'angular-cookies';
+import angular_sanitize from 'angular-sanitize';
+import angular_ui_router from 'angular-ui-router';
+import angular_animate from 'angular-animate';
+import angular_clipboard from 'angular-clipboard';
+import angular_ui_bootstrap from 'angular-ui-bootstrap';
+import angular_route from 'angular-route';
+import angular_utils from 'angularUtils/src/angularUtils.js';
+import angular_utils_pagination from 'angularUtils/src/directives/pagination/dirPagination.js';
+require('./styles/index.scss')
+
+// TODO(Ed)  clean this up, add the appropriate imports to phosphor-webui
+
+import constants_index from './constants/index.js'
+import environment_constants from './constants/environment-constants.js'
+
+import services_index from './common/services/index.js'
+import constants from './common/services/constants.js'
+import dataService from './common/services/dataService.js'
+import api_utils from './common/services/api-utils.js'
+import userModel from './common/services/userModel.js'
+import apiInterceptor from './common/services/apiInterceptor.js'
+
+import filters_index from './common/filters/index.js'
+
+import directives_index from './common/directives/index.js'
+import app_header from './common/directives/app-header.js'
+import app_navigation from './common/directives/app-navigation.js'
+import confirm from './common/directives/confirm.js'
+import log_event from './common/directives/log-event.js'
+import log_filter from './common/directives/log-filter.js'
+import log_search_control from './common/directives/log-search-control.js'
+import toggle_flag from './common/directives/toggle-flag.js'
+import firmware_list from './common/directives/firmware-list.js'
+import file from './common/directives/file.js'
+import loader from './common/directives/loader.js'
+import paginate from './common/directives/paginate.js'
+
+import login_index from './login/index.js'
+import login_controller from './login/controllers/login-controller.js'
+
+import overview_index from './overview/index.js'
+import system_overview_controller from './overview/controllers/system-overview-controller.js'
+
+import server_control_index from './server-control/index.js'
+import bmc_reboot_controller from './server-control/controllers/bmc-reboot-controller.js'
+import power_operations_controller from './server-control/controllers/power-operations-controller.js'
+import remote_console_controller from './server-control/controllers/remote-console-controller.js'
+import remote_console_window_controller from './server-control/controllers/remote-console-window-controller.js'
+
+import server_health_index from './server-health/index.js'
+import diagnostics_controller from './server-health/controllers/diagnostics-controller.js'
+import inventory_controller from './server-health/controllers/inventory-controller.js'
+import inventory_overview_controller from './server-health/controllers/inventory-overview-controller.js'
+import log_controller from './server-health/controllers/log-controller.js'
+import power_consumption_controller from './server-health/controllers/power-consumption-controller.js'
+import sensors_controller from './server-health/controllers/sensors-controller.js'
+import sensors_overview_controller from './server-health/controllers/sensors-overview-controller.js'
+import unit_id_controller from './server-health/controllers/unit-id-controller.js'
+
+import configuration_index from './configuration/index.js'
+import date_time_controller from './configuration/controllers/date-time-controller.js'
+import file_controller from './configuration/controllers/file-controller.js'
+import network_controller from './configuration/controllers/network-controller.js'
+import security_controller from './configuration/controllers/security-controller.js'
+import firmware_controller from './configuration/controllers/firmware-controller.js'
+
+import firmware_index from './firmware/index.js'
+import bmc_controller from './firmware/controllers/bmc-controller.js'
+import server_controller from './firmware/controllers/server-controller.js'
+
+import multi_server_index from './multi-server/index.js'
+import multi_server_controller from './multi-server/controllers/multi-server-controller.js'
+
+import users_index from './users/index.js'
+import user_accounts_controller from './users/controllers/user-accounts-controller.js'
+
+import phosphor_templates from './templates.js';
+import phosphor_vendors from './vendors.js';
+
 window.angular && (function (angular) {
     'use strict';
 
@@ -54,7 +138,6 @@
            $rootScope.dataService = dataService;
            dataService.path = $location.path();
            $rootScope.$on('$routeChangeStart', function(event, next, current){
-
              if(next.$$route == null || next.$$route == undefined) return;
              if(next.$$route.authenticated){
                if(!userModel.isLoggedIn()){
diff --git a/app/login/controllers/login-controller.html b/app/login/controllers/login-controller.html
index 77ca583..8217ea3 100644
--- a/app/login/controllers/login-controller.html
+++ b/app/login/controllers/login-controller.html
@@ -1,7 +1,7 @@
 <div>
     <div class="row">
         <div class="columns large-6">
-            <img src="assets/images/logo.svg" class="login__logo" alt="IBM logo" role="img"/>
+            <img src="../../assets/images/logo.svg" class="login__logo" alt="IBM logo" role="img"/>
         </div>
         <div class="columns large-6">
         </div>
diff --git a/app/login/index.js b/app/login/index.js
index a12cb6c..b904383 100644
--- a/app/login/index.js
+++ b/app/login/index.js
@@ -19,12 +19,12 @@
         .config(['$routeProvider', function ($routeProvider) {
             $routeProvider
                 .when('/login/:fake_login', {
-                    'templateUrl': 'login/controllers/login-controller.html',
+                    'template': require('./controllers/login-controller.html'),
                     'controller': 'LoginController',
                     authenticated: false
                 })
                 .when('/login', {
-                    'templateUrl': 'login/controllers/login-controller.html',
+                    'template': require('./controllers/login-controller.html'),
                     'controller': 'LoginController',
                     authenticated: false
                 });
diff --git a/app/multi-server/index.js b/app/multi-server/index.js
index 1340aac..9afaed6 100644
--- a/app/multi-server/index.js
+++ b/app/multi-server/index.js
@@ -19,7 +19,7 @@
         .config(['$routeProvider', function ($routeProvider) {
             $routeProvider
                 .when('/multi-server/overview', {
-                    'templateUrl': 'multi-server/controllers/multi-server-controller.html',
+                    'template': require('./controllers/multi-server-controller.html'),
                     'controller': 'multiServerController',
                     authenticated: true
                 });
diff --git a/app/overview/index.js b/app/overview/index.js
index 6f78188..5d0d240 100644
--- a/app/overview/index.js
+++ b/app/overview/index.js
@@ -19,12 +19,12 @@
         .config(['$routeProvider', function ($routeProvider) {
             $routeProvider
                 .when('/overview/server', {
-                    'templateUrl': 'overview/controllers/system-overview-controller.html',
+                    'template': require('./controllers/system-overview-controller.html'),
                     'controller': 'systemOverviewController',
                     authenticated: true
                 })
                 .when('/overview', {
-                    'templateUrl': 'overview/controllers/system-overview-controller.html',
+                    'template': require('./controllers/system-overview-controller.html'),
                     'controller': 'systemOverviewController',
                     authenticated: true
                 });
diff --git a/app/server-control/controllers/power-operations-controller.html b/app/server-control/controllers/power-operations-controller.html
index c49e4c3..8c23d9c 100644
--- a/app/server-control/controllers/power-operations-controller.html
+++ b/app/server-control/controllers/power-operations-controller.html
@@ -21,7 +21,7 @@
 
         <!-- Power on displays only when server is shutdown -->
         <div class="row column power-option" ng-hide="dataService.server_state == 'Running' || dataService.server_state == 'Quiesced' || dataService.server_state == 'Unreachable'" ng-class="{disabled: dataService.server_unreachable || (confirm && !power_confirm) || dataService.loading, transitionAll: confirm && power_confirm}">
-            <button id="power__power-on" class="btn-secondary inline" ng-click="togglePower()" role="button" ng-disabled="dataService.server_unreachable"><img src="assets/images/icon-power.svg" alt="power on" aria-hidden="true">Power on</button>
+            <button id="power__power-on" class="btn-secondary inline" ng-click="togglePower()" role="button" ng-disabled="dataService.server_unreachable"><img src="../../assets/images/icon-power.svg" alt="power on" aria-hidden="true">Power on</button>
             <p class="inline">Attempts to power on the server</p>
         </div>
 
@@ -37,14 +37,14 @@
             <confirm title="cold reboot" confirm="coldboot_confirm" ng-show="coldboot_confirm" cancel="coldbootCancel" callback="coldReboot"></confirm>
         </div>
         <div class="row column power-option" ng-hide="dataService.server_state == 'Off' || dataService.server_state == 'Unreachable'" ng-class="{disabled: dataService.server_unreachable || (confirm && !orderly_confirm) || dataService.loading, transitionAll: confirm && orderly_confirm}">
-            <button id="power__soft-shutdown" class="btn-secondary inline" ng-click="orderlyShutdownConfirm()" role="button" ng-disabled="dataService.server_unreachable"><img aria-hidden="true" src="assets/images/icon-power.svg" />Orderly shutdown</button>
+            <button id="power__soft-shutdown" class="btn-secondary inline" ng-click="orderlyShutdownConfirm()" role="button" ng-disabled="dataService.server_unreachable"><img aria-hidden="true" src="../../assets/images/icon-power.svg" />Orderly shutdown</button>
             <p class="inline">Attempts to stop all software on the server before removing power</p>
             <confirm title="orderly shutdown" confirm="orderly_confirm" ng-show="orderly_confirm" cancel="orderlyShutdownCancel" callback="orderlyShutdown"></confirm>
         </div>
         <div class="row column power-option" ng-hide="dataService.server_state == 'Off' || dataService.server_state == 'Unreachable'" ng-class="{disabled: dataService.server_unreachable || (confirm && !immediately_confirm) || dataService.loading, transitionAll: confirm && immediately_confirm}">
-            <button id="power__hard-shutdown" class="btn-secondary inline" ng-click="immediateShutdownConfirm()" role="button" ng-disabled="dataService.server_unreachable"><img aria-hidden="true" src="assets/images/icon-power.svg" />Immediate shutdown</button>
+            <button id="power__hard-shutdown" class="btn-secondary inline" ng-click="immediateShutdownConfirm()" role="button" ng-disabled="dataService.server_unreachable"><img aria-hidden="true" src="../../assets/images/icon-power.svg" />Immediate shutdown</button>
             <p class="inline">Removes power from the server without waiting for software to stop</p>
             <confirm title="immediate shutdown" confirm="immediately_confirm" ng-show="immediately_confirm" cancel="immediatelyShutdownCancel" callback="immediateShutdown"></confirm>
         </div>
     </div>
-</div>
\ No newline at end of file
+</div>
diff --git a/app/server-control/controllers/remote-console-controller.js b/app/server-control/controllers/remote-console-controller.js
index fffb139..2b69561 100644
--- a/app/server-control/controllers/remote-console-controller.js
+++ b/app/server-control/controllers/remote-console-controller.js
@@ -7,6 +7,8 @@
  * @version 0.1.0
  */
 
+import {hterm, lib} from 'hterm-umdjs';
+
 window.angular && (function (angular) {
     'use strict';
 
diff --git a/app/server-control/index.js b/app/server-control/index.js
index f3ca75c..acc7f2c 100644
--- a/app/server-control/index.js
+++ b/app/server-control/index.js
@@ -19,32 +19,32 @@
         .config(['$routeProvider', function ($routeProvider) {
             $routeProvider
                 .when('/server-control/bmc-reboot', {
-                    'templateUrl': 'server-control/controllers/bmc-reboot-controller.html',
+                    'template': require('./controllers/bmc-reboot-controller.html'),
                     'controller': 'bmcRebootController',
                     authenticated: true
                 })
                 .when('/server-control/server-led', {
-                    'templateUrl': 'server-health/controllers/unit-id-controller.html',
+                    'template': require('../server-health/controllers/unit-id-controller.html'),
                     'controller': 'unitIdController',
                     authenticated: true
                 })
                 .when('/server-control/power-operations', {
-                    'templateUrl': 'server-control/controllers/power-operations-controller.html',
+                    'template': require('./controllers/power-operations-controller.html'),
                     'controller': 'powerOperationsController',
                     authenticated: true
                 })
                 .when('/server-control/remote-console', {
-                    'templateUrl': 'server-control/controllers/remote-console-controller.html',
+                    'template': require('./controllers/remote-console-controller.html'),
                     'controller': 'remoteConsoleController',
                     authenticated: true
                 })
                 .when('/server-control/remote-console-window', {
-                    'templateUrl': 'server-control/controllers/remote-console-window-controller.html',
+                    'template': require('./controllers/remote-console-window-controller.html'),
                     'controller': 'remoteConsoleWindowController',
                     authenticated: true
                 })
                 .when('/server-control', {
-                    'templateUrl': 'server-control/controllers/power-operations-controller.html',
+                    'template': require('./controllers/power-operations-controller.html'),
                     'controller': 'powerOperationsController',
                     authenticated: true
                 });
diff --git a/app/server-health/controllers/log-controller.html b/app/server-health/controllers/log-controller.html
index 7bf13e5..3e1be4f 100644
--- a/app/server-health/controllers/log-controller.html
+++ b/app/server-health/controllers/log-controller.html
@@ -54,22 +54,22 @@
                 <!-- when logs are selected, this text changes to show how many logs are checked -->
                 <div class="event__actions">
                     <button class="inline btn-delete" ng-show="selectedEvents.length || all" ng-click="confirm= ! confirm">
-                        <img class="event__icon" src="assets/images/icon-trashcan-white.svg" alt="">Delete
+                        <img class="event__icon" src="../../assets/images/icon-trashcan-white.svg" alt="">Delete
                     </button>
                     <button class="inline btn-resolve" ng-class="{'disabled': ((selectedEvents|unResolvedCount) == 0)}" ng-show="selectedEvents.length || all" ng-click="resolve()" ng-disabled="(selectedEvents|unResolvedCount) == 0">
-                        <img class="event__icon" src="assets/images/icon-check-white.svg" alt="">Mark as resolved
+                        <img class="event__icon" src="../../assets/images/icon-check-white.svg" alt="">Mark as resolved
                     </button>
                     <a ng-href="data:text/json;charset=utf-8,{{export_data}}" class="inline btn-export"  download="{{export_name}}" ng-show="selectedEvents.length || all">Export</a>
                 </div>
             </div>
         </div>
-        <log-event 
+        <log-event
         dir-paginate="event in (filteredLogs = (logs|filter:filterBySeverity|filter:filterByStatus|filter:filterByDate|filter:filterBySearchTerms | orderBy:'+Id'))| itemsPerPage: itemsPerPage" 
         event="event" 
         tmz="tmz"
         multi-selected="selectedEvents.length > 1"
         >
         </log-event>
-        <dir-pagination-controls template-url="common/directives/dirPagination.tpl.html"></dir-pagination-controls>
+        <dir-pagination-controls></dir-pagination-controls>
     </section>
-</div> <!-- end event log -->
\ No newline at end of file
+</div> <!-- end event log -->
diff --git a/app/server-health/controllers/log-controller.js b/app/server-health/controllers/log-controller.js
index 9dab22a..62750de 100644
--- a/app/server-health/controllers/log-controller.js
+++ b/app/server-health/controllers/log-controller.js
@@ -11,6 +11,9 @@
     'use strict';
     angular
         .module('app.serverHealth')
+        .config(function(paginationTemplateProvider) {
+            paginationTemplateProvider.setString(require('../../common/directives/dirPagination.tpl.html'));
+        })
         .controller('logController', [
             '$scope', 
             '$window', 
diff --git a/app/server-health/index.js b/app/server-health/index.js
index 117be62..6139e3f 100644
--- a/app/server-health/index.js
+++ b/app/server-health/index.js
@@ -19,52 +19,52 @@
         .config(['$routeProvider', function ($routeProvider) {
             $routeProvider
                 .when('/server-health/event-log', {
-                    'templateUrl': 'server-health/controllers/log-controller.html',
+                    'template': require('./controllers/log-controller.html'),
                     'controller': 'logController',
                     authenticated: true
                 })
                 .when('/server-health/event-log/:type', {
-                    'templateUrl': 'server-health/controllers/log-controller.html',
+                    'template': require('./controllers/log-controller.html'),
                     'controller': 'logController',
                     authenticated: true
                 })
                 .when('/server-health/event-log/:type/:id', {
-                    'templateUrl': 'server-health/controllers/log-controller.html',
+                    'template': require('./controllers/log-controller.html'),
                     'controller': 'logController',
                     authenticated: true
                 })
                 .when('/server-health/inventory-overview', {
-                    'templateUrl': 'server-health/controllers/inventory-overview-controller.html',
+                    'template': require('./controllers/inventory-overview-controller.html'),
                     'controller': 'inventoryOverviewController',
                     authenticated: true
                 })
                 .when('/server-health/inventory', {
-                    'templateUrl': 'server-health/controllers/inventory-controller.html',
+                    'template': require('./controllers/inventory-controller.html'),
                     'controller': 'inventoryController',
                     authenticated: true
                 })
                 .when('/server-health/sensors-overview', {
-                    'templateUrl': 'server-health/controllers/sensors-overview-controller.html',
+                    'template': require('./controllers/sensors-overview-controller.html'),
                     'controller': 'sensorsOverviewController',
                     authenticated: true
                 })
                 .when('/server-health/sensors/:type', {
-                    'templateUrl': 'server-health/controllers/sensors-controller.html',
+                    'template': require('./controllers/sensors-controller.html'),
                     'controller': 'sensorsController',
                     authenticated: true
                 })
                 .when('/server-health/power-consumption', {
-                    'templateUrl': 'server-health/controllers/power-consumption-controller.html',
+                    'template': require('./controllers/power-consumption-controller.html'),
                     'controller': 'powerConsumptionController',
                     authenticated: true
                 })
                 .when('/server-health/diagnostics', {
-                    'templateUrl': 'server-health/controllers/diagnostics-controller.html',
+                    'template': require('./controllers/diagnostics-controller.html'),
                     'controller': 'diagnosticsController',
                     authenticated: true
                 })
                 .when('/server-health', {
-                    'templateUrl': 'server-health/controllers/log-controller.html',
+                    'template': require('./controllers/log-controller.html'),
                     'controller': 'logController',
                     authenticated: true
                 });
diff --git a/app/users/index.js b/app/users/index.js
index becc9b9..bdb7b12 100644
--- a/app/users/index.js
+++ b/app/users/index.js
@@ -19,12 +19,12 @@
         .config(['$routeProvider', function ($routeProvider) {
             $routeProvider
                 .when('/users/manage-accounts', {
-                    'templateUrl': 'users/controllers/user-accounts-controller.html',
+                    'template': require('./controllers/user-accounts-controller.html'),
                     'controller': 'userAccountsController',
                     authenticated: true
                 })
                 .when('/users', {
-                    'templateUrl': 'users/controllers/user-accounts-controller.html',
+                    'template': require('./controllers/user-accounts-controller.html'),
                     'controller': 'userAccountsController',
                     authenticated: true
                 });
diff --git a/karma.conf.js b/karma.conf.js
new file mode 100644
index 0000000..6c355f3
--- /dev/null
+++ b/karma.conf.js
@@ -0,0 +1,55 @@
+// Reference: http://karma-runner.github.io/0.12/config/configuration-file.html
+module.exports = function karmaConfig (config) {
+  config.set({
+    frameworks: [
+      // Reference: https://github.com/karma-runner/karma-jasmine
+      // Set framework to jasmine
+      'jasmine'
+    ],
+
+    reporters: [
+      // Reference: https://github.com/mlex/karma-spec-reporter
+      // Set reporter to print detailed results to console
+      'progress',
+
+      // Reference: https://github.com/karma-runner/karma-coverage
+      // Output code coverage files
+      'coverage'
+    ],
+
+    files: [
+      // Grab all files in the app folder that contain .spec.
+      'src/tests.webpack.js'
+    ],
+
+    preprocessors: {
+      // Reference: http://webpack.github.io/docs/testing.html
+      // Reference: https://github.com/webpack/karma-webpack
+      // Convert files with webpack and load sourcemaps
+      'src/tests.webpack.js': ['webpack', 'sourcemap']
+    },
+
+    browsers: [
+      // Run tests using PhantomJS
+      'PhantomJS'
+    ],
+
+    singleRun: true,
+
+    // Configure code coverage reporter
+    coverageReporter: {
+      dir: 'coverage/',
+      reporters: [
+        {type: 'text-summary'},
+        {type: 'html'}
+      ]
+    },
+
+    webpack: require('./webpack.config'),
+
+    // Hide webpack build information from output
+    webpackMiddleware: {
+      noInfo: 'errors-only'
+    }
+  });
+};
diff --git a/package.json b/package.json
index b8ddec5..5e793b8 100644
--- a/package.json
+++ b/package.json
@@ -8,20 +8,17 @@
     "url": "git://github.com/openbmc/phosphor-webui"
   },
   "scripts": {
-    "bower": "node node_modules/bower/bin/bower",
-    "gulp": "node node_modules/gulp/bin/gulp.js",
-    "distribution": "npm run gulp distribution",
-    "minifyvendors": "npm run gulp minifyvendors",
-    "serve": "npm run gulp server",
-    "shrinkwrap": "npm shrinkwrap --dev",
-    "start-dev": "npm run gulp server",
-    "webapp": "npm run gulp webapp",
-    "start": "npm run gulp server",
-    "postinstall": "bower install"
+    "build": "rimraf dist && webpack --bail --progress --profile",
+    "build-debug": "rimraf dist && webpack --bail --progress --profile --devtool source-map",
+    "server": "webpack-dev-server --history-api-fallback --inline --progress --devtool source-map",
+    "test": "karma start",
+    "test-watch": "karma start --auto-watch --no-single-run",
+    "start": "npm run server"
   },
   "contributors": [
     "Iftekharul Islam <iffy.ryan@ibm.com>",
-    "Michael Davis <michael.s.davis@ibm.com>"
+    "Michael Davis <michael.s.davis@ibm.com>",
+    "Ed Tanous <ed.tanous@intel.com>"
   ],
   "files": [
     "dist"
@@ -29,13 +26,39 @@
   "keywords": [
     "node"
   ],
-  "dependencies": {},
+  "dependencies": {
+    "angular": "^1.5.0",
+    "angular-animate": "^1.6.6",
+    "angular-clipboard": "^1.6.2",
+    "angular-cookies": "^1.5.0",
+    "angular-route": "^1.6.6",
+    "angular-sanitize": "^1.5.0",
+    "angular-ui-bootstrap": "^2.5.0",
+    "angular-ui-router": "^0.4.3",
+    "angular-websocket": "^2.0.1",
+    "angularUtils": "https://github.com/michaelbromley/angularUtils.git",
+    "assets-webpack-plugin": "^3.5.1",
+    "bootstrap": "^3.3.7",
+    "compression-webpack-plugin": "^1.0.1",
+    "font-awesome": "^4.7.0",
+    "hterm-umdjs": "^1.2.0",
+    "html-loader": "^0.5.1",
+    "node-sass": "^4.5.3",
+    "sass-loader": "^6.0.6"
+  },
   "peerDependencies": {},
   "devDependencies": {
-    "autoprefixer": "^6.6.1",
-    "bower": "1.8.0",
+    "angular-mocks": "^1.5.0",
+    "autoprefixer": "^7.1.4",
+    "babel-core": "^6.2.1",
+    "babel-loader": "^7.1.2",
+    "babel-preset-es2015": "^6.1.18",
+    "copy-webpack-plugin": "4.1.1",
+    "css-loader": "0.28.7",
     "eslint-plugin-angular": "2.0.0",
     "event-stream": "3.3.4",
+    "extract-text-webpack-plugin": "3.0.1",
+    "file-loader": "1.1.5",
     "gulp": "3.9.1",
     "gulp-angular-templatecache": "2.0.0",
     "gulp-clean": "^0.3.2",
@@ -59,10 +82,28 @@
     "gulp-useref": "^1.2.0",
     "gulp-util": "^3.0.6",
     "html-minifier": "^3.3.0",
-    "node-sass": "^4.3.0",
+    "html-webpack-plugin": "^2.7.1",
+    "istanbul-instrumenter-loader": "3.0.0",
+    "jasmine-core": "^2.3.4",
+    "karma": "^1.1.0",
+    "karma-coverage": "^1.0.0",
+    "karma-jasmine": "^1.0.2",
+    "karma-phantomjs-launcher": "^1.0.0",
+    "karma-sourcemap-loader": "^0.3.7",
+    "karma-spec-reporter": "0.0.31",
+    "karma-webpack": "2.0.4",
+    "node-libs-browser": "2.0.0",
+    "null-loader": "^0.1.1",
     "onchange": "^3.2.1",
     "parallelshell": "^2.0.0",
-    "run-sequence": "^1.1.2"
+    "phantomjs-prebuilt": "^2.1.4",
+    "postcss-loader": "2.0.6",
+    "raw-loader": "^0.5.1",
+    "rimraf": "^2.5.1",
+    "run-sequence": "^1.1.2",
+    "style-loader": "^0.19.0",
+    "webpack": "^3.6.0",
+    "webpack-dev-server": "^2.9.1"
   },
   "license": "MIT",
   "engines": {
diff --git a/postcss.config.js b/postcss.config.js
new file mode 100644
index 0000000..3691590
--- /dev/null
+++ b/postcss.config.js
@@ -0,0 +1,7 @@
+module.exports = {
+  plugins: {
+    autoprefixer: {
+      browsers: ['last 2 versions']
+    },
+  },
+};
diff --git a/webpack.config.js b/webpack.config.js
new file mode 100644
index 0000000..e848662
--- /dev/null
+++ b/webpack.config.js
@@ -0,0 +1,244 @@
+'use strict';
+
+// Modules
+var webpack = require('webpack');
+var autoprefixer = require('autoprefixer');
+var HtmlWebpackPlugin = require('html-webpack-plugin');
+var ExtractTextPlugin = require('extract-text-webpack-plugin');
+var CopyWebpackPlugin = require('copy-webpack-plugin');
+var CompressionPlugin = require('compression-webpack-plugin');
+var AssetsPlugin = require('assets-webpack-plugin');
+var CopyWebpackPlugin = require('copy-webpack-plugin');
+var path = require('path');
+
+/**
+ * Env
+ * Get npm lifecycle event to identify the environment
+ */
+var ENV = process.env.npm_lifecycle_event;
+var isTest = ENV === 'test' || ENV === 'test-watch';
+var isProd = ENV === 'build';
+
+module.exports = [
+  function makeWebpackConfig() {
+    /**
+     * Config
+     * Reference: http://webpack.github.io/docs/configuration.html
+     * This is the object where all configuration gets set
+     */
+    var config = {};
+
+    /**
+     * Entry
+     * Reference: http://webpack.github.io/docs/configuration.html#entry
+     * Should be an empty object if it's generating a test build
+     * Karma will set this when it's a test build
+     */
+    config.entry = isTest ? void 0 : {
+      app : './app/index.js'
+
+    };
+
+    /**
+     * Output
+     * Reference: http://webpack.github.io/docs/configuration.html#output
+     * Should be an empty object if it's generating a test build
+     * Karma will handle setting it up for you when it's a test build
+     */
+    config.output = isTest ? {} : {
+      // Absolute output directory
+      path : __dirname + '/dist',
+
+      // Output path from the view of the page
+      // Uses webpack-dev-server in development
+      publicPath : '/',
+
+      // Filename for entry points
+      // Only adds hash in build mode
+      filename : isProd ? '[name].[hash].js' : '[name].bundle.js',
+
+      // Filename for non-entry points
+      // Only adds hash in build mode
+      chunkFilename : isProd ? '[name].[hash].js' : '[name].bundle.js'
+    };
+
+    /**
+     * Devtool
+     * Reference: http://webpack.github.io/docs/configuration.html#devtool
+     * Type of sourcemap to use per build type
+     */
+    if (isTest) {
+      https:
+          // unix.stackexchange.com/questions/144208/find-files-without-extension
+          config.devtool = 'inline-source-map';
+      }
+    else if (isProd) {
+      config.devtool = 'source-map';
+      }
+    else {
+      config.devtool = 'eval-source-map';
+    }
+
+    /**
+     * Loaders
+     * Reference:
+     * http://webpack.github.io/docs/configuration.html#module-loaders
+     * List: http://webpack.github.io/docs/list-of-loaders.html
+     * This handles most of the magic responsible for converting modules
+     */
+
+    // Initialize module
+    config.module = {
+      rules : [
+        {
+          // JS LOADER
+          // Reference: https://github.com/babel/babel-loader
+          // Transpile .js files using babel-loader
+          // Compiles ES6 and ES7 into ES5 code
+          test : /\.js$/,
+          loader : 'babel-loader',
+          exclude : /node_modules/
+        },
+        {
+          // CSS LOADER
+          // Reference: https://github.com/webpack/css-loader
+          // Allow loading css through js
+          //
+          // Reference: https://github.com/postcss/postcss-loader
+          // Postprocess your css with PostCSS plugins
+          test : /\.css$/,
+          // Reference: https://github.com/webpack/extract-text-webpack-plugin
+          // Extract css files in production builds
+          //
+          // Reference: https://github.com/webpack/style-loader
+          // Use style-loader in development.
+
+          loader : isTest ? 'null-loader' : ExtractTextPlugin.extract({
+            fallback : 'style-loader',
+            use : [
+              {loader : 'css-loader', query : {sourceMap : true}},
+              {loader : 'postcss-loader'}
+            ],
+          })
+        },
+        {
+          // ASSET LOADER
+          // Reference: https://github.com/webpack/file-loader
+          // Copy png, jpg, jpeg, gif, svg, woff, woff2, ttf, eot files to
+          // output
+          // Rename the file using the asset hash
+          // Pass along the updated reference to your code
+          // You can add here any file extension you want to get copied to your
+          // output
+          test : /\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)$/,
+          loader : 'file-loader',
+          options : {
+            name(file) {
+              if (!isProd) {
+                return '[path][name].[ext]'
+                }
+
+              return '[hash].[ext]'
+            }
+          }
+        },
+        {
+          // HTML LOADER
+          // Reference: https://github.com/webpack/raw-loader
+          // Allow loading html through js
+          test : /\.html$/,
+          use : {loader : 'html-loader'}
+        },
+        // JSON LOADER
+        {test : /\.json$/, loader : 'json-loader'}, {
+          test : /\.scss$/,
+          use : [
+            {
+              loader : 'style-loader'  // creates style nodes from JS strings
+            },
+            {
+              loader : 'css-loader'  // translates CSS into CommonJS
+            },
+            {
+              loader : 'sass-loader'  // compiles Sass to CSS
+            }
+          ]
+        }
+      ]
+    };
+
+    // ISTANBUL LOADER
+    // https://github.com/deepsweet/istanbul-instrumenter-loader
+    // Instrument JS files with istanbul-lib-instrument for subsequent code
+    // coverage reporting
+    // Skips node_modules and files that end with .spec.js
+    if (isTest) {
+      config.module.rules.push({
+        enforce : 'pre',
+        test : /\.js$/,
+        exclude : [ /node_modules/, /\.spec\.js$/],
+        loader : 'istanbul-instrumenter-loader',
+        query : {esModules : true}
+      })
+    }
+
+    /**
+     * PostCSS
+     * Reference: https://github.com/postcss/autoprefixer-core
+     * Add vendor prefixes to your css
+     */
+    // NOTE: This is now handled in the `postcss.config.js`
+    //       webpack2 has some issues, making the config file necessary
+
+    /**
+     * Plugins
+     * Reference: http://webpack.github.io/docs/configuration.html#plugins
+     * List: http://webpack.github.io/docs/list-of-plugins.html
+     */
+    config.plugins = [ new webpack.LoaderOptionsPlugin({
+      test : /\.scss$/i,
+      options : {postcss : {plugins : [ autoprefixer ]}},
+      debug : !isProd
+    }) ];
+
+    // Skip rendering index.html in test mode
+    if (!isTest) {
+      // Reference: https://github.com/ampedandwired/html-webpack-plugin
+      // Render index.html
+      config.plugins.push(
+          new HtmlWebpackPlugin(
+              {template : './app/index.html', inject : 'body'}),
+
+          // Reference: https://github.com/webpack/extract-text-webpack-plugin
+          // Extract css files
+          // Disabled when in test mode or not in build mode
+          new ExtractTextPlugin({
+            filename : 'css/[name].css',
+            disable : !isProd,
+            allChunks : true
+          }))
+      }
+
+    // Add build specific plugins
+    if (isProd) {
+      config.plugins.push(
+          // Reference:
+          // http://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin
+          // Minify all javascript, switch loaders to minimizing mode
+          new webpack.optimize.UglifyJsPlugin(),
+
+          // Copy assets from the public folder
+          // Reference: https://github.com/kevlened/copy-webpack-plugin
+          new CopyWebpackPlugin([ {from : __dirname + '/app/assets'} ]),
+          new CompressionPlugin({deleteOriginalAssets : true}))
+    }
+
+    /**
+     * Dev server configuration
+     * Reference: http://webpack.github.io/docs/configuration.html#devserver
+     * Reference: http://webpack.github.io/docs/webpack-dev-server.html
+     */
+    config.devServer = {contentBase : './src/public', stats : 'minimal'};
+
+    return config;
+  }()];