Add dynamic content to hardware inventory page

Change-Id: I3b34e58ada63c32e2476e37b7116232f5763bbdb
Signed-off-by: Iftekharul Islam <iislam@us.ibm.com>
diff --git a/app/common/services/api-utils.js b/app/common/services/api-utils.js
index ed10768..b044328 100644
--- a/app/common/services/api-utils.js
+++ b/app/common/services/api-utils.js
@@ -599,7 +599,7 @@
               getBMCEthernetInfo: function(callback){
                 $http({
                   method: 'GET',
-                  url: SERVICE.API_CREDENTIALS.host + "/xyz/openbmc_project/inventory/system/chassis/motherboard/boxelder/bmc/ethernet",
+                  url: SERVICE.API_CREDENTIALS.host + "/xyz/openbmc_project/inventory",
                   headers: {
                       'Accept': 'application/json',
                       'Content-Type': 'application/json'
@@ -620,7 +620,7 @@
               getBMCInfo: function(callback){
                 $http({
                   method: 'GET',
-                  url: SERVICE.API_CREDENTIALS.host + "/xyz/openbmc_project/inventory/system/chassis/motherboard/boxelder/bmc",
+                  url: SERVICE.API_CREDENTIALS.host + "/xyz/openbmc_project/inventory",
                   headers: {
                       'Accept': 'application/json',
                       'Content-Type': 'application/json'
@@ -638,6 +638,110 @@
                   console.log(error);
                 });
               },
+              getHardwares: function(callback){
+                $http({
+                  method: 'GET',
+                  url: SERVICE.API_CREDENTIALS.host + "/xyz/openbmc_project/inventory/system",
+                  headers: {
+                      'Accept': 'application/json',
+                      'Content-Type': 'application/json'
+                  },
+                  withCredentials: true
+                }).success(function(response){
+                      var json = JSON.stringify(response);
+                      var content = JSON.parse(json);
+                      var hardwareData = [];
+                      var keyIndexMap = {};
+                      var title = "";
+                      var data = [];
+                      var searchText = "";
+                      var componentIndex = -1;
+                      var tempParts = [];
+
+
+                      function isSubComponent(key){
+
+                        for(var i = 0; i < Constants.HARDWARE.parent_components.length; i++){
+                          if(key.split(Constants.HARDWARE.parent_components[i]).length == 2) return true;
+                        }
+
+                        return false;
+                      }
+
+                      function titlelize(title){
+                        title = title.replace(/([A-Z0-9]+)/g, " $1").replace(/^\s+/, "");
+                        for(var i = 0; i < Constants.HARDWARE.uppercase_titles.length; i++){
+                          if(title.toLowerCase().indexOf((Constants.HARDWARE.uppercase_titles[i] + " ")) > -1){
+                            return title.toUpperCase();
+                          }
+                        }
+
+                        return title;
+                      }
+
+                      function camelcaseToLabel(obj){
+                        var transformed = [], label = "";
+                        for(var key in obj){
+                          label = key.replace(/([A-Z0-9]+)/g, " $1").replace(/^\s+/, "");
+                          if(obj[key] !== ""){
+                            transformed.push({key:label, value: obj[key]});
+                          }
+                        }
+
+                        return transformed;
+                      }
+
+                      function getSearchText(data){
+                        var searchText = "";
+                        for(var i = 0; i < data.length; i++){
+                          searchText += " " + data[i].key + " " + data[i].value;
+                        }
+
+                        return searchText; 
+                      }
+
+                      for(var key in content.data){
+                        if(content.data.hasOwnProperty(key) && 
+                           key.indexOf(Constants.HARDWARE.component_key_filter) == 0){
+
+                          data = camelcaseToLabel(content.data[key]);
+                          searchText = getSearchText(data);
+                          title = key.split("/").pop();
+
+                          title = titlelize(title);
+
+                          if(!isSubComponent(key)){
+                              hardwareData.push(Object.assign({
+                                path: key,
+                                title: title,
+                                selected: false,
+                                expanded: false,
+                                search_text: title.toLowerCase() + " " + searchText.toLowerCase(),
+                                sub_components: [], 
+                                original_data: {key: key, value: content.data[key]}
+                              }, {items: data}));
+
+                              keyIndexMap[key] = hardwareData.length - 1;
+                          }else{
+                            var tempParts = key.split("/");
+                            tempParts.pop();
+                            tempParts = tempParts.join("/");
+                            componentIndex = keyIndexMap[tempParts];
+                            data = content.data[key];
+                            data.title = title;
+                            hardwareData[componentIndex].sub_components.push(data);
+                            hardwareData[componentIndex].search_text += " " + title.toLowerCase();
+                          }
+                      }
+                    }
+
+                    if(callback){
+                       callback(hardwareData, content.data);
+                    }else{
+                       return { data: hardwareData, original_data: content.data};
+                    }
+                });
+              },
           };
           return SERVICE;
         }]);
diff --git a/app/common/services/constants.js b/app/common/services/constants.js
index 7616b3e..1445081 100644
--- a/app/common/services/constants.js
+++ b/app/common/services/constants.js
@@ -20,7 +20,7 @@
                     password: "testpass",
                 },
                 API_CREDENTIALS: {
-                    host: 'https://9.3.185.173',
+                    host: 'https://9.3.164.177',
                     mock_host: 'http://localhost:3000'
                 },
                 API_RESPONSE: {
@@ -61,6 +61,15 @@
                 PAGINATION: {
                     LOG_ITEMS_PER_PAGE: 4
                 },
+                HARDWARE: {
+                  component_key_filter: '/xyz/openbmc_project/inventory/system',
+                  parent_components: [
+                   /xyz\/openbmc_project\/inventory\/system\/chassis\/motherboard\/cpu\d+\//
+                  ],
+                  uppercase_titles: [
+                   'cpu', 'dimm'
+                  ]
+                },
                 SENSOR_DATA_TEMPLATE: {
                     sensors: [
                         {
diff --git a/app/server-health/controllers/inventory-overview-controller.html b/app/server-health/controllers/inventory-overview-controller.html
index 98a8339..e8e2a5b 100644
--- a/app/server-health/controllers/inventory-overview-controller.html
+++ b/app/server-health/controllers/inventory-overview-controller.html
@@ -2,15 +2,17 @@
 	<div class="row column no-padding">
 		<h1>Hardware status</h1>
 		<div class="page-header">
-			<button class="inline btn-export float-right">Export</button>
+
+			<a ng-href="data:text/json;charset=utf-8,{{originalData}}" class="inline btn-export float-right"  download="export_inventory.json" ng-show="hardwares.length">Export</a>
+
 		</div>
 	</div>
 	<section class="row column">
 		<!-- search -->
 		<div class="content__search">
 			<label for="content__search-input">Search</label> <input id="content__search-input" type="text"
-				placeholder="Filter hardware components"/>
-			<input id="content__search-submit" type="submit" class="btn btn-primary" value="Filter"/>
+				placeholder="Filter hardware components" ng-model="customSearch" ng-keydown="doSearchOnEnter($event)"/>
+			<input id="content__search-submit" type="submit" class="btn btn-primary" value="Filter" ng-click="doSearchOnClick()"/>
 		</div>
 
 	</section>
@@ -20,354 +22,30 @@
 			<div class="column large-12 header__actions-bar">
 				<div class="inline inventory__heading inventory__device-col">Hardware</div>
 				<div class="inline inventory__heading inventory__function-col">&nbsp;</div>
-				<div class="inline inventory__heading inventory__assoc-event sort-heading sort-down">Associated events</div>
+				<div class="inline inventory__heading inventory__assoc-event"><!--Associated events--></div>
 			</div>
 		</div>
-		<!-- hardware item -->
-		<div class="inventory__group" ng-class="{'active': inv.meta}" ng-click="inv.meta = ! inv.meta">
-			<p class="inline inventory__device-col">System</p>
+		<div ng-repeat="inventory in hardwares|filter:filterBySearchTerms" class="inventory__group"  ng-class="{'active': inventory.expanded}" ng-click="inventory.expanded = ! inventory.expanded">
+			<p class="inline inventory__device-col">{{inventory.title}}</p>
 			<p class="inline inventory__function-col"></p>
-			<p class="inline inventory__assoc-event"></p>
-			<button class="accord-trigger float-right" ng-class="{'active': inv.meta}"></button>
-			<div class="row inventory__metadata" ng-class="{'active': inv.meta}">
+			<p class="inline inventory__assoc-event"><!--<a href="#/server-health/event-log">View 3 events</a>--></p>
+			<button class="accord-trigger float-right" ng-class="{'active': inventory.expanded}"></button>
+			<div class="row inventory__metadata" ng-class="{'active': inventory.expanded}">
 				<div class="column large-9 no-padding">
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Name</p>
-						<p class="courier-bold">System</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Serial Number</p>
-						<p class="courier-bold">2230123ab-04</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Part Number</p>
-						<p class="courier-bold">12355123ab</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Manufacturer</p>
-						<p class="courier-bold">IBM</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Version</p>
-						<p class="courier-bold">10</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Functional</p>
-						<p class="courier-bold">Yes</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Field replaceable</p>
-						<p class="courier-bold">Not replaceable</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Higher level FRU</p>
-						<p class="courier-bold">Motherboard</p>
+					<div  ng-repeat="item in inventory.items" class="inline inventory__metadata-block">
+						<p class="content-label">{{item.key}}</p>
+						<p class="courier-bold">{{item.value}}</p>
 					</div>
 				</div>
-				<div class="column large-3">
-
-				</div>
-			</div>
-		</div>
-
-		<!-- hardware item -->
-		<div class="inventory__group">
-			<p class="inline inventory__device-col">Chassis</p>
-			<p class="inline inventory__function-col"></p>
-			<p class="inline inventory__assoc-event"></p>
-			<button class="accord-trigger float-right"></button>
-			<div class="row inventory__metadata">
-				<div class="column large-9 no-padding">
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Name</p>
-						<p class="courier-bold">Processor module</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Serial Number</p>
-						<p class="courier-bold">2230123ab-04</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Part Number</p>
-						<p class="courier-bold">12355123ab</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Manufacturer</p>
-						<p class="courier-bold">IBM</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Version</p>
-						<p class="courier-bold">10</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Functional</p>
-						<p class="courier-bold">Yes</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Field replaceable</p>
-						<p class="courier-bold">Not replaceable</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Higher level FRU</p>
-						<p class="courier-bold">Motherboard</p>
-					</div>
-				</div>
-				<div class="column large-3 no-padding">
-				</div>
-			</div>
-		</div>
-		<!-- hardware item -->
-		<div class="inventory__group ">
-			<p class="inline inventory__device-col">Motherboard</p>
-			<p class="inline inventory__function-col"></p>
-			<p class="inline inventory__assoc-event"></p>
-			<button class="accord-trigger float-right"></button>
-			<div class="row inventory__metadata ">
-				<div class="column large-9 no-padding">
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Name</p>
-						<p class="courier-bold">Processor module</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Serial Number</p>
-						<p class="courier-bold">2230123ab-04</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Part Number</p>
-						<p class="courier-bold">12355123ab</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Manufacturer</p>
-						<p class="courier-bold">IBM</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Version</p>
-						<p class="courier-bold">10</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Functional</p>
-						<p class="courier-bold">Yes</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Field replaceable</p>
-						<p class="courier-bold">Not replaceable</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Higher level FRU</p>
-						<p class="courier-bold">Motherboard</p>
-					</div>
-				</div>
-				<div class="column large-3 no-padding">
-
-				</div>
-			</div>
-		</div>
-		<!-- hardware item w/ sub categories -->
-		<div class="inventory__group"  ng-class="{'active': invCpu.meta}" ng-click="invCpu.meta = ! invCpu.meta">
-			<p class="inline inventory__device-col">CPU 0</p>
-			<p class="inline inventory__function-col"></p>
-			<p class="inline inventory__assoc-event"><a href="#/server-health/event-log">View 3 events</a></p>
-			<button class="accord-trigger float-right" ng-class="{'active': invCpu.meta}"></button>
-			<div class="row inventory__metadata" ng-class="{'active': invCpu.meta}">
-				<div class="column large-9 no-padding">
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Name</p>
-						<p class="courier-bold">Processor module</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Serial Number</p>
-						<p class="courier-bold">YA3933853282</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Part Number</p>
-						<p class="courier-bold">01HL982</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Manufacturer</p>
-						<p class="courier-bold">IBM</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Version</p>
-						<p class="courier-bold">10</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Functional</p>
-						<p class="courier-bold">Yes</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Field replaceable</p>
-						<p class="courier-bold">Replaceable</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Higher level FRU</p>
-						<p class="courier-bold">Motherboard</p>
-					</div>
-				</div>
-				<div class="column large-3 no-padding">
+				<div class="column large-3 no-padding" ng-show="inventory.sub_components.length">
 					<div class="inventory__metadata-scroll show-scroll"> <!-- If content overflows; add 'show-scroll' class via JS to force visible scrollbar in webkit browsers-->
 						<div class="content-label">Subcomponents</div>
-						<div class="inline inventory__metadata-block">
-							<p class="courier-bold">Core 0</p>
-						</div>
-						<div class="inline inventory__metadata-block">
-							<p class="courier-bold"><span class="icon icon__warning"></span>Core 1</p>
-						</div>
-						<div class="inline inventory__metadata-block">
-							<p class="courier-bold">Core 2</p>
-						</div>
-						<div class="inline inventory__metadata-block">
-							<p class="courier-bold">Core 3</p>
-						</div>
-						<div class="inline inventory__metadata-block">
-							<p class="courier-bold">Core 4</p>
-						</div>
-						<div class="inline inventory__metadata-block">
-							<p class="courier-bold">Core 5</p>
-						</div>
-						<div class="inline inventory__metadata-block">
-							<p class="courier-bold">Core 6</p>
-						</div>
-						<div class="inline inventory__metadata-block">
-							<p class="courier-bold">Core 7</p>
-						</div>
-						<div class="inline inventory__metadata-block">
-							<p class="courier-bold">Core 8</p>
-						</div>
-						<div class="inline inventory__metadata-block">
-							<p class="courier-bold">Core 9</p>
-						</div>
-						<div class="inline inventory__metadata-block">
-							<p class="courier-bold">Core 10</p>
-						</div>
-						<div class="inline inventory__metadata-block">
-							<p class="courier-bold">Core 11</p>
-						</div>
-						<div class="inline inventory__metadata-block">
-							<p class="courier-bold">Core 12</p>
-						</div>
-						<div class="inline inventory__metadata-block">
-							<p class="courier-bold">Core 13</p>
-						</div>
-						<div class="inline inventory__metadata-block">
-							<p class="courier-bold">Core 14</p>
-						</div>
-						<div class="inline inventory__metadata-block">
-							<p class="courier-bold">Core 15</p>
-						</div>
-						<div class="inline inventory__metadata-block">
-							<p class="courier-bold">Core 16</p>
-						</div>
-						<div class="inline inventory__metadata-block">
-							<p class="courier-bold">Core 17</p>
-						</div>
-						<div class="inline inventory__metadata-block">
-							<p class="courier-bold">Core 18</p>
-						</div>
-						<div class="inline inventory__metadata-block">
-							<p class="courier-bold">Core 19</p>
-						</div>
-						<div class="inline inventory__metadata-block">
-							<p class="courier-bold">Core 20</p>
-						</div>
-						<div class="inline inventory__metadata-block">
-							<p class="courier-bold">Core 21</p>
-						</div>
-						<div class="inline inventory__metadata-block">
-							<p class="courier-bold">Core 22</p>
-						</div>
-						<div class="inline inventory__metadata-block">
-							<p class="courier-bold">Core 23</p>
+						<div ng-repeat="sub_component in inventory.sub_components" class="inline inventory__metadata-block">
+							<p class="courier-bold"><span class="icon icon__warning" ng-if="sub_component.Present"></span>{{sub_component.title}}</p>
 						</div>
 					</div>
 				</div>
 			</div>
 		</div>
-		<!-- hardware item -->
-		<div class="inventory__group ">
-			<p class="inline inventory__device-col">Ethernet</p>
-			<p class="inline inventory__function-col">Inactive</p>
-			<p class="inline inventory__assoc-event"><a href="#/server-health/event-log">View 1 event</a></p>
-			<button class="accord-trigger float-right"></button>
-			<div class="row inventory__metadata ">
-				<div class="column large-9 no-padding">
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Name</p>
-						<p class="courier-bold">Processor module</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Serial Number</p>
-						<p class="courier-bold">2230123ab-04</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Part Number</p>
-						<p class="courier-bold">12355123ab</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Manufacturer</p>
-						<p class="courier-bold">IBM</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Version</p>
-						<p class="courier-bold">10</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Functional</p>
-						<p class="courier-bold">Yes</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Field replaceable</p>
-						<p class="courier-bold">Not replaceable</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Higher level FRU</p>
-						<p class="courier-bold">Motherboard</p>
-					</div>
-				</div>
-				<div class="column large-3 no-padding"></div>
-			</div>
-		</div>
-		<!-- hardware item no sub items -->
-		<div class="inventory__group inv-disabled">
-			<p class="inline inventory__device-col">DIMM 0</p>
-			<p class="inline inventory__function-col">Not present</p>
-			<p class="inline inventory__assoc-event"></p>
-			<button class="accord-trigger float-right"></button>
-			<div class="row inventory__metadata ">
-				<div class="column large-9 no-padding">
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Name</p>
-						<p class="courier-bold">Processor module</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Serial Number</p>
-						<p class="courier-bold">2230123ab-04</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Part Number</p>
-						<p class="courier-bold">12355123ab</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Manufacturer</p>
-						<p class="courier-bold">IBM</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Version</p>
-						<p class="courier-bold">10</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Functional</p>
-						<p class="courier-bold">Yes</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Field replaceable</p>
-						<p class="courier-bold">Not replaceable</p>
-					</div>
-					<div class="inline inventory__metadata-block">
-						<p class="content-label">Higher level FRU</p>
-						<p class="courier-bold">Motherboard</p>
-					</div>
-				</div>
-				<div class="column large-3 no-padding"></div>
-			</div>
-		</div>
 	</section>
 </div>
\ No newline at end of file
diff --git a/app/server-health/controllers/inventory-overview-controller.js b/app/server-health/controllers/inventory-overview-controller.js
index 3eda37b..81fd833 100644
--- a/app/server-health/controllers/inventory-overview-controller.js
+++ b/app/server-health/controllers/inventory-overview-controller.js
@@ -19,6 +19,48 @@
             'dataService',
             function($scope, $window, APIUtils, dataService){
                 $scope.dataService = dataService;
+                $scope.hardwares = [];
+                $scope.originalData = {};
+                $scope.customSearch = "";
+                $scope.searchTerms = [];
+
+                APIUtils.getHardwares(function(data, originalData){
+                    $scope.hardwares = data;
+                    $scope.originalData = JSON.stringify(originalData);
+                });
+
+                $scope.doSearchOnEnter = function (event) {
+                    var search = $scope.customSearch.replace(/^\s+/g,'').replace(/\s+$/g,'');
+                    if (event.keyCode === 13 &&
+                        search.length >= 2) {
+                        $scope.searchTerms = $scope.customSearch.split(" ");
+                    }else{
+                        if(search.length == 0){
+                            $scope.searchTerms = [];
+                        }
+                    }
+                };
+
+                $scope.doSearchOnClick = function() {
+                    var search = $scope.customSearch.replace(/^\s+/g,'').replace(/\s+$/g,'');
+                    if (search.length >= 2) {
+                        $scope.searchTerms = $scope.customSearch.split(" ");
+                    }else{
+                        if(search.length == 0){
+                            $scope.searchTerms = [];
+                        }
+                    }
+                }
+
+                $scope.filterBySearchTerms = function(hardware){
+
+                    if(!$scope.searchTerms.length) return true; 
+
+                    for(var i = 0, length = $scope.searchTerms.length; i < length; i++){
+                        if(hardware.search_text.indexOf($scope.searchTerms[i].toLowerCase()) == -1) return false;
+                    }
+                    return true;
+                }
             }
         ]
     );