Filter catalog in UI based on model

Issue-ID: SDC-3679
Signed-off-by: davsad <david.sadlier@est.tech>
Change-Id: Icd0eeb13dbfb1cc27745c7adf6a3212210e00a4a
diff --git a/catalog-ui/src/app/ng2/pages/catalog/__snapshots__/catalog.component.spec.ts.snap b/catalog-ui/src/app/ng2/pages/catalog/__snapshots__/catalog.component.spec.ts.snap
index d6091cd..b41d7ce 100644
--- a/catalog-ui/src/app/ng2/pages/catalog/__snapshots__/catalog.component.spec.ts.snap
+++ b/catalog-ui/src/app/ng2/pages/catalog/__snapshots__/catalog.component.spec.ts.snap
@@ -13,6 +13,7 @@
   initScopeMembers={[Function Function]}
   isDefaultFilter={[Function Function]}
   loaderService={[Function Object]}
+  models={[Function Array]}
   resourceNamePipe={[Function Object]}
   sdcConfig={[Function Object]}
   sdcMenu={[Function Object]}
@@ -47,6 +48,28 @@
           class="sdc-catalog-leftbar-container"
         >
           <div
+            class="sdc-catalog-model-filter-container"
+          >
+            <div
+              class="i-sdc-designer-leftbar-section-title pointer"
+            >
+              <span
+                class="i-sdc-designer-leftbar-section-title-icon"
+              />
+              <span
+                class="i-sdc-designer-leftbar-section-title-text"
+                data-tests-id="statusFilterTitle"
+              >
+                Model
+              </span>
+            </div>
+            <div
+              class="i-sdc-designer-leftbar-section-content"
+            >
+              <sdc-checklist />
+            </div>
+          </div>
+          <div
             class="sdc-catalog-type-filter-container"
           >
             <div
diff --git a/catalog-ui/src/app/ng2/pages/catalog/catalog.component.html b/catalog-ui/src/app/ng2/pages/catalog/catalog.component.html
index 4a13bee..d130d1e 100644
--- a/catalog-ui/src/app/ng2/pages/catalog/catalog.component.html
+++ b/catalog-ui/src/app/ng2/pages/catalog/catalog.component.html
@@ -19,6 +19,20 @@
         <!-- LEFT SIDE -->
         <div perfectScrollbar class="sdc-catalog-body-container w-sdc-left-sidebar i-sdc-designer-left-sidebar">
             <div class="sdc-catalog-leftbar-container">
+                <!-- Model -->
+                <div class="sdc-catalog-model-filter-container">
+                    <div class="i-sdc-designer-leftbar-section-title pointer" (click)="sectionClick('model')"
+                         [ngClass]="{'expanded': expandedSection.indexOf('model') !== -1}">
+                        <span class="i-sdc-designer-leftbar-section-title-icon"></span>
+                        <span class="i-sdc-designer-leftbar-section-title-text"
+                              data-tests-id="statusFilterTitle">Model</span>
+                    </div>
+                    <div class="i-sdc-designer-leftbar-section-content">
+                        <sdc-checklist [checklistModel]="modelsChecklistModel" [testId]="'checklist-model'"
+                                       (checkedChange)="gui.onModelClick()"></sdc-checklist>
+                    </div>
+                </div>
+
                 <div class="sdc-catalog-type-filter-container">
                     <div class="i-sdc-designer-leftbar-section-title pointer"
                          (click)="sectionClick('type')"
diff --git a/catalog-ui/src/app/ng2/pages/catalog/catalog.component.spec.ts b/catalog-ui/src/app/ng2/pages/catalog/catalog.component.spec.ts
index ff27ec7..5473033 100644
--- a/catalog-ui/src/app/ng2/pages/catalog/catalog.component.spec.ts
+++ b/catalog-ui/src/app/ng2/pages/catalog/catalog.component.spec.ts
@@ -75,18 +75,21 @@
                 components: ["Resource.VF", "Resource.VFC"],
                 order:  ["lastUpdateDate", true],
                 statuses: ["inDesign"],
+                models: ["test"],
                 term: "Vf"
             }
             checkboxesFilterMock = {
                 selectedCategoriesModel: ["serviceNewCategory.network l4+", "resourceNewCategory.allotted resource.allotted resource"],
                 selectedComponentTypes: ["Resource.VF", "Resource.VFC"],
                 selectedResourceSubTypes: ["VF", "VFC"],
-                selectedStatuses: ["NOT_CERTIFIED_CHECKOUT", "NOT_CERTIFIED_CHECKIN"]
+                selectedStatuses: ["NOT_CERTIFIED_CHECKOUT", "NOT_CERTIFIED_CHECKIN"],
+                selectedModels: ["test"]
             };
             checkboxesFilterKeysMock = {
                 categories:{_main: ["serviceNewCategory.network l4+"]},
                 componentTypes: { Resource: ["Resource.VF", "Resource.VFC"], _main: ["Resource.VFC"]},
-                statuses: {_main: ["inDesign"]}
+                statuses: {_main: ["inDesign"]},
+                models: {_main: ["test"]}
             }
 
             stateServiceMock = {
@@ -186,7 +189,7 @@
         expect(component.componentInstance.numberOfItemToDisplay).toEqual(0);
         expect(component.componentInstance.categories).toEqual(categoriesElements);
         expect(component.componentInstance.confStatus).toEqual(component.componentInstance.sdcMenu.statuses);
-        expect(component.componentInstance.expandedSection).toEqual( ["type", "category", "status"]);
+        expect(component.componentInstance.expandedSection).toEqual( ["type", "category", "status", "model"]);
         expect(component.componentInstance.catalogItems).toEqual([]);
         expect(component.componentInstance.search).toEqual({FilterTerm: ""});
         expect(component.componentInstance.initCategoriesMap).toHaveBeenCalled();
@@ -203,10 +206,12 @@
         component.componentInstance.buildChecklistModelForTypes = jest.fn();
         component.componentInstance.buildChecklistModelForCategories = jest.fn();
         component.componentInstance.buildChecklistModelForStatuses = jest.fn();
+		component.componentInstance.buildChecklistModelForModels = jest.fn();
         component.componentInstance.buildCheckboxLists();
         expect(component.componentInstance.buildChecklistModelForTypes).toHaveBeenCalled();
         expect(component.componentInstance.buildChecklistModelForCategories).toHaveBeenCalled();
         expect(component.componentInstance.buildChecklistModelForStatuses).toHaveBeenCalled();
+        expect(component.componentInstance.buildChecklistModelForModels).toHaveBeenCalled();
     });
 
     it ('should call on catalog component getTestIdForCheckboxByText ' , () => {
@@ -266,7 +271,7 @@
         component.componentInstance.initCheckboxesFilter();
         expect(component.componentInstance.checkboxesFilter.selectedComponentTypes).toEqual([]);
         expect(component.componentInstance.checkboxesFilter.selectedResourceSubTypes).toEqual([]);
-        expect(component.componentInstance.checkboxesFilter.selectedCategoriesModel).toEqual([]);
+        expect(component.componentInstance.checkboxesFilter.selectedModels).toEqual([]);
         expect(component.componentInstance.checkboxesFilter.selectedStatuses).toEqual([]);
     });
 
@@ -276,6 +281,7 @@
         expect(component.componentInstance.checkboxesFilterKeys.componentTypes).toEqual({ _main: [] });
         expect(component.componentInstance.checkboxesFilterKeys.categories).toEqual({ _main: [] });
         expect(component.componentInstance.checkboxesFilterKeys.statuses).toEqual({ _main: [] });
+        expect(component.componentInstance.checkboxesFilterKeys.models).toEqual({ _main: [] });
     });
 
     it ('should call on catalog component initCategoriesMap' , () => {
@@ -469,6 +475,7 @@
         component.componentInstance.applyFilterParamsComponents = jest.fn();
         component.componentInstance.applyFilterParamsCategories = jest.fn();
         component.componentInstance.applyFilterParamsStatuses = jest.fn();
+        component.componentInstance.applyFilterParamsModels = jest.fn();
         component.componentInstance.applyFilterParamsOrder = jest.fn();
         component.componentInstance.applyFilterParamsTerm = jest.fn();
         component.componentInstance.filterCatalogItems = jest.fn();
@@ -596,7 +603,7 @@
         component.componentInstance.applyFilterParamsToView = jest.fn();
         component.componentInstance.filterParams =  { active: true, categories: [], components: [], order:  ["lastUpdateDate", true], statuses: [], term: ""};
         component.componentInstance.$state.go = jest.fn().mockImplementation(() => Promise.resolve({ json: () => [] }));
-        const newParams = {"filter.active": true, "filter.categories": "resourceNewCategory.allotted resource.allotted resource,resourceNewCategory.allotted resource.contrail route,resourceNewCategory.application l4+.application server", "filter.components": "Resource.VF,Resource.VFC", "filter.order": "-lastUpdateDate", "filter.statuses": "inDesign", "filter.term": "Vf"}
+        const newParams = {"filter.active": true, "filter.categories": "resourceNewCategory.allotted resource.allotted resource,resourceNewCategory.allotted resource.contrail route,resourceNewCategory.application l4+.application server", "filter.components": "Resource.VF,Resource.VFC", "filter.models": "test", "filter.order": "-lastUpdateDate", "filter.statuses": "inDesign", "filter.term": "Vf"}
         component.componentInstance.changeFilterParams(filterParamsMock);
         expect(component.componentInstance.filterParams).toEqual(filterParamsMock);
         expect(component.componentInstance.$state.go).toHaveBeenCalledWith('.',newParams, {location: 'replace', notify: false});
@@ -610,7 +617,7 @@
         component.componentInstance.buildCheckboxLists = jest.fn();
         component.componentInstance.filterParams =  { active: true, categories: [], components: [], order:  ["lastUpdateDate", true], statuses: [], term: ""};
         component.componentInstance.$state.go = jest.fn().mockImplementation(() => Promise.resolve({ json: () => [] }));
-        const newParams = {"filter.active": true, "filter.categories": "resourceNewCategory.allotted resource.allotted resource,resourceNewCategory.allotted resource.contrail route,resourceNewCategory.application l4+.application server", "filter.components": "Resource.VF,Resource.VFC", "filter.order": "-lastUpdateDate", "filter.statuses": "inDesign", "filter.term": "Vf"}
+        const newParams = {"filter.active": true, "filter.categories": "resourceNewCategory.allotted resource.allotted resource,resourceNewCategory.allotted resource.contrail route,resourceNewCategory.application l4+.application server", "filter.components": "Resource.VF,Resource.VFC", "filter.models": "test", "filter.order": "-lastUpdateDate", "filter.statuses": "inDesign", "filter.term": "Vf"}
         component.componentInstance.typesChecklistModel = checkListModelMock;
         component.componentInstance.categoriesChecklistModel = checkListModelMock;
         component.componentInstance.statusChecklistModel = checkListModelMock;
diff --git a/catalog-ui/src/app/ng2/pages/catalog/catalog.component.ts b/catalog-ui/src/app/ng2/pages/catalog/catalog.component.ts
index 5277648..5d65260 100644
--- a/catalog-ui/src/app/ng2/pages/catalog/catalog.component.ts
+++ b/catalog-ui/src/app/ng2/pages/catalog/catalog.component.ts
@@ -27,12 +27,15 @@
 import { Component, ICategoryBase, IMainCategory, ISubCategory, IConfigStatuses, ICatalogSelector, CatalogSelectorTypes } from "app/models";
 import { ResourceNamePipe } from "../../pipes/resource-name.pipe";
 import { EntityFilterPipe, IEntityFilterObject, ISearchFilter} from "../../pipes/entity-filter.pipe";
+import { Model } from "app/models/model";
+import { DEFAULT_MODEL_NAME } from "app/utils/constants";
 
 interface Gui {
     onComponentSubTypesClick:Function;
     onComponentTypeClick:Function;
     onCategoryClick:Function;
     onStatusClick:Function;
+    onModelClick:Function;
     changeFilterTerm:Function;
 }
 
@@ -40,6 +43,7 @@
     components: string[];
     categories: string[];
     statuses: (string)[];
+    models: string[];
     order: [string, boolean];
     term: string;
     active: boolean;
@@ -54,6 +58,7 @@
     componentTypes: ICheckboxesFilterMap;
     categories: ICheckboxesFilterMap;
     statuses: ICheckboxesFilterMap;
+    models: ICheckboxesFilterMap;
 }
 
 interface ICategoriesMap {
@@ -73,6 +78,7 @@
     public checkboxesFilterKeys:ICheckboxesFilterKeys;
     public gui:Gui;
     public categories:Array<IMainCategory>;
+    public models: Array<string> = new Array();
     public filteredCategories:Array<IMainCategory>;
     public confStatus:IConfigStatuses;
     public componentTypes:{[key:string]: Array<string>};
@@ -96,11 +102,13 @@
     public typesChecklistModel: SdcUiCommon.ChecklistModel;
     public categoriesChecklistModel: SdcUiCommon.ChecklistModel;
     public statusChecklistModel: SdcUiCommon.ChecklistModel;
+    public modelsChecklistModel: SdcUiCommon.ChecklistModel;
 
     private defaultFilterParams:IFilterParams = {
         components: [],
         categories: [],
         statuses: [],
+        models: [],
         order: ['lastUpdateDate', true],
         term: '',
         active: true
@@ -149,8 +157,10 @@
         this.numberOfItemToDisplay = 0;
         this.categories = this.makeSortedCategories(this.cacheService.get('serviceCategories').concat(this.cacheService.get('resourceCategories')))
             .map((cat) => <IMainCategory>cat);
+        this.models = this.cacheService.get('models').map((model:Model) => model.name);
+        this.models.unshift(DEFAULT_MODEL_NAME);
         this.confStatus = this.sdcMenu.statuses;
-        this.expandedSection = ["type", "category", "status"];
+        this.expandedSection = ["type", "category", "status", "model"];
         this.catalogItems = [];
         this.search = {FilterTerm: ""};
         this.categoriesMap = this.initCategoriesMap();
@@ -167,6 +177,7 @@
         this.buildChecklistModelForTypes();
         this.buildChecklistModelForCategories();
         this.buildChecklistModelForStatuses();
+        this.buildChecklistModelForModels();
     }
 
     private getTestIdForCheckboxByText = ( text: string ):string => {
@@ -216,6 +227,18 @@
         );
     }
 
+    private buildChecklistModelForModels() {
+        this.modelsChecklistModel = new SdcUiCommon.ChecklistModel(this.checkboxesFilterKeys.models._main,
+            this.models.map((model) => new SdcUiCommon.ChecklistItemModel(
+                model, 
+                false, 
+                this.checkboxesFilterKeys.models._main.indexOf(model) !== -1, 
+                null, 
+                this.getTestIdForCheckboxByText(model), 
+                model))
+        );
+    }
+
     private buildChecklistModelForStatuses() {
         // For statuses checklist model, use the statuses keys as values. On applying filtering map the statuses keys to statuses values.
         this.statusChecklistModel = new SdcUiCommon.ChecklistModel(this.checkboxesFilterKeys.statuses._main,
@@ -236,6 +259,7 @@
         this.checkboxesFilter.selectedResourceSubTypes = [];
         this.checkboxesFilter.selectedCategoriesModel = [];
         this.checkboxesFilter.selectedStatuses = [];
+        this.checkboxesFilter.selectedModels = [];
     }
 
     private initCheckboxesFilterKeys() {
@@ -244,6 +268,7 @@
         this.checkboxesFilterKeys.componentTypes = { _main: [] };
         this.checkboxesFilterKeys.categories = { _main: [] };
         this.checkboxesFilterKeys.statuses = { _main: [] };
+        this.checkboxesFilterKeys.models = { _main: [] };
     }
 
     private initCategoriesMap(categoriesList?:(ICategoryBase)[], parentCategory:ICategoryBase=null): ICategoriesMap {
@@ -360,6 +385,12 @@
                 term: filterTerm
             });
         };
+ 
+        this.gui.onModelClick = (): void => {
+            this.changeFilterParams({
+                models: this.makeFilterParamsFromCheckboxes(this.modelsChecklistModel)
+            });
+        };
     }
 
     public raiseNumberOfElementToDisplay(recalculate:boolean = false): void {
@@ -444,6 +475,7 @@
         this.applyFilterParamsComponents(filterParams);
         this.applyFilterParamsCategories(filterParams);
         this.applyFilterParamsStatuses(filterParams);
+        this.applyFilterParamsModels(filterParams);
         this.applyFilterParamsOrder(filterParams);
         this.applyFilterParamsTerm(filterParams);
 
@@ -499,6 +531,11 @@
         this.checkboxesFilter.selectedStatuses = _.reduce(_.flatMap(this.checkboxesFilterKeys.statuses), (stats, st:string) => [...stats, ...this.confStatus[st].values], []);
     }
 
+    private applyFilterParamsModels(filterParams: IFilterParams) {
+        this.applyFilterParamsToCheckboxes(this.modelsChecklistModel, filterParams.models);
+        this.checkboxesFilter.selectedModels = _.flatMap(this.checkboxesFilterKeys.models);
+    }
+
     private applyFilterParamsOrder(filterParams: IFilterParams) {
         this.sortBy = filterParams.order[0];
         this.reverse = filterParams.order[1];
@@ -525,6 +562,8 @@
                         paramsChecklist = paramsChecklist || this.categoriesChecklistModel;
                     case 'filter.statuses':
                         paramsChecklist = paramsChecklist || this.statusChecklistModel;
+                    case 'filter.models':
+                        paramsChecklist = paramsChecklist || this.modelsChecklistModel;
 
                         // for those cases above - split param by comma and make reduced checklist values for filter params (url)
                         newVal = _.uniq(params[k].split(','));
@@ -559,6 +598,7 @@
                 case 'components':
                 case 'categories':
                 case 'statuses':
+                case 'models':
                     newVal = changedFilterParams[k] && changedFilterParams[k].length ? changedFilterParams[k].join(',') : null;
                     break;
                 case 'order':
@@ -582,7 +622,8 @@
                 this.changeFilterParams({
                     components: this.makeFilterParamsFromCheckboxes(this.typesChecklistModel),
                     categories: this.makeFilterParamsFromCheckboxes(this.categoriesChecklistModel),
-                    statuses: this.makeFilterParamsFromCheckboxes(this.statusChecklistModel)
+                    statuses: this.makeFilterParamsFromCheckboxes(this.statusChecklistModel),
+                    models: this.makeFilterParamsFromCheckboxes(this.modelsChecklistModel)
                 });
                 // rebuild the checkboxes to show selected
                 this.buildCheckboxLists();
diff --git a/catalog-ui/src/app/ng2/pipes/entity-filter.pipe.ts b/catalog-ui/src/app/ng2/pipes/entity-filter.pipe.ts
index af107ed..b67f42d 100644
--- a/catalog-ui/src/app/ng2/pipes/entity-filter.pipe.ts
+++ b/catalog-ui/src/app/ng2/pipes/entity-filter.pipe.ts
@@ -20,7 +20,7 @@
 
 import {Pipe, PipeTransform} from "@angular/core";
 import {Component, Resource} from "app/models";
-import {ComponentType} from "app/utils/constants";
+import {ComponentType, DEFAULT_MODEL_NAME} from "app/utils/constants";
 
 export interface ISearchFilter {
     [key:string]: string;
@@ -34,6 +34,8 @@
     selectedCategoriesModel?:Array<string>;
     // Statuses
     selectedStatuses?:Array<string>;
+    // Models
+    selectedModels?:Array<string>;
     // distributed
     distributed?:Array<string>;
     // search
@@ -129,6 +131,21 @@
             filteredComponents = filteredDistributed;
         }
 
+        // filter by model
+        // --------------------------------------------------------------------------
+        if (filter.selectedModels && filter.selectedModels.length > 0) {
+            let filteredModels = [];
+            let defaultModelPresent = filter.selectedModels.indexOf(DEFAULT_MODEL_NAME) > -1;
+            angular.forEach(filteredComponents, (component:Component):void => {
+                if (filter.selectedModels.indexOf(component.model) > -1) {
+                    filteredModels.push(component);
+                } else if (!component.model && defaultModelPresent) {
+	                filteredModels.push(component);
+                }
+            });
+            filteredComponents = filteredModels;
+        }
+
         // filter by search
         // --------------------------------------------------------------------------
         if (filter.search != undefined) {
diff --git a/catalog-ui/src/app/ng2/services/config.service.ts b/catalog-ui/src/app/ng2/services/config.service.ts
index 2b9b49c..55e0899 100644
--- a/catalog-ui/src/app/ng2/services/config.service.ts
+++ b/catalog-ui/src/app/ng2/services/config.service.ts
@@ -49,6 +49,7 @@
             this.cacheService.set('serviceCategories', response.categories.serviceCategories);
             this.cacheService.set('resourceCategories', response.categories.resourceCategories);
             this.cacheService.set('UIConfiguration', response.configuration);
+            this.cacheService.set('models', response.models);
         });
         return promise;
     }
diff --git a/catalog-ui/src/app/utils/constants.ts b/catalog-ui/src/app/utils/constants.ts
index f7cbf8d..58aa402 100644
--- a/catalog-ui/src/app/utils/constants.ts
+++ b/catalog-ui/src/app/utils/constants.ts
@@ -28,6 +28,7 @@
 export let CHANGE_COMPONENT_CSAR_VERSION_FLAG = 'changeComponentCsarVersion';
 export let PREVIOUS_CSAR_COMPONENT = 'previousCsarComponent'
 export let CATEGORY_SERVICE_METADATA_KEYS = ["Naming Policy","Service Type","Service Function","Service Role"];
+export let DEFAULT_MODEL_NAME = "SDC AID";
 
 export class GeneralStatus {
   static OK = 'OK';