diff options
author | Michael Lando <ml636r@att.com> | 2017-02-19 10:28:42 +0200 |
---|---|---|
committer | Michael Lando <ml636r@att.com> | 2017-02-19 10:51:01 +0200 |
commit | 451a3400b76511393c62a444f588a4ed15f4a549 (patch) | |
tree | e4f5873a863d1d3e55618eab48b83262f874719d /catalog-ui/app/scripts/view-models/catalog | |
parent | 5abfe4e1fb5fae4bbd5fbc340519f52075aff3ff (diff) |
Initial OpenECOMP SDC commit
Change-Id: I0924d5a6ae9cdc161ae17c68d3689a30d10f407b
Signed-off-by: Michael Lando <ml636r@att.com>
Diffstat (limited to 'catalog-ui/app/scripts/view-models/catalog')
4 files changed, 1115 insertions, 0 deletions
diff --git a/catalog-ui/app/scripts/view-models/catalog/catalog-view-model.ts b/catalog-ui/app/scripts/view-models/catalog/catalog-view-model.ts new file mode 100644 index 0000000000..bf37e92e56 --- /dev/null +++ b/catalog-ui/app/scripts/view-models/catalog/catalog-view-model.ts @@ -0,0 +1,312 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +/// <reference path="../../references"/> +module Sdc.ViewModels { + + 'use strict'; + + interface Checkboxes { + componentTypes:Array<string>; + resourceSubTypes:Array<string>; + } + + interface CheckboxesFilter { + // Types + selectedComponentTypes:Array<string>; + selectedResourceSubTypes:Array<string>; + // Categories + selectedCategoriesModel:Array<string>; + // Statuses + selectedStatuses:Array<string>; + } + + interface Gui { + isLoading: boolean; + onResourceSubTypesClick:Function; + onComponentTypeClick:Function; + onCategoryClick:Function; + onSubcategoryClick:Function; + onGroupClick:Function; + } + + export interface ICatalogViewModelScope extends ng.IScope { + checkboxes:Checkboxes; + checkboxesFilter:CheckboxesFilter; + gui:Gui; + + categories: Array<Models.IMainCategory>; + confStatus: Models.IConfigStatuses; + sdcMenu:Models.IAppMenu; + catalogFilterdItems: Array<Models.Components.Component>; + expandedSection: Array<string>; + actionStrategy: any; + user: Models.IUserProperties; + catalogMenuItem: any; + version:string; + sortBy:string; + reverse:boolean; + + //this is for UI paging + numberOfItemToDisplay:number; + isAllItemDisplay: boolean; + + openViewerModal(isResource: boolean, uniqueId: string): void; + changeLifecycleState(entity:any,state:string): void; + sectionClick (section:string):void; + order(sortBy:string): void; + getNumOfElements(num:number): string; + goToComponent(component:Models.Components.Component):void; + raiseNumberOfElementToDisplay():void; + } + + export class CatalogViewModel { + static '$inject' = [ + '$scope', + '$filter', + 'Sdc.Services.EntityService', + 'sdcConfig', + 'sdcMenu', + '$state', + '$q', + 'Sdc.Services.UserResourceService', + '$modal', + '$templateCache', + 'Sdc.Services.CacheService', + 'ComponentFactory', + 'ChangeLifecycleStateHandler', + 'ModalsHandler', + 'MenuHandler' + ]; + + constructor(private $scope:ICatalogViewModelScope, + private $filter:ng.IFilterService, + private EntityService:Services.EntityService, + private sdcConfig:Models.IAppConfigurtaion, + private sdcMenu:Models.IAppMenu, + private $state:any, + private $q:any, + private userResourceService:Sdc.Services.IUserResourceClass, + private $modal:ng.ui.bootstrap.IModalService, + private $templateCache:ng.ITemplateCacheService, + private cacheService:Services.CacheService, + private ComponentFactory: Sdc.Utils.ComponentFactory, + private ChangeLifecycleStateHandler: Sdc.Utils.ChangeLifecycleStateHandler, + private OpenViewModalHandler: Utils.ModalsHandler, + private MenuHandler: Utils.MenuHandler + ) { + + this.initScopeMembers(); + this.initCatalogData(); // Async task to get catalog from server. + this.initScopeMethods(); + } + + private initCatalogData = ():void => { + let onSuccess = (followedResponse:Array<Models.Components.Component>):void => { + this.$scope.catalogFilterdItems = followedResponse; + this.$scope.isAllItemDisplay = this.$scope.numberOfItemToDisplay >= this.$scope.catalogFilterdItems.length; + this.$scope.categories = this.cacheService.get('serviceCategories').concat(this.cacheService.get('resourceCategories')).concat(this.cacheService.get('productCategories')); + this.$scope.gui.isLoading = false; + }; + + let onError = ():void => { + console.info('Failed to load catalog CatalogViewModel::initCatalog'); + this.$scope.gui.isLoading = false; + }; + this.EntityService.getCatalog().then(onSuccess, onError); + }; + + + + private initScopeMembers = ():void => { + // Gui init + this.$scope.gui = <Gui>{}; + this.$scope.gui.isLoading = true; + this.$scope.numberOfItemToDisplay = 0; + //this.$scope.categories = this.cacheService.get('categoriesMap'); + this.$scope.sdcMenu = this.sdcMenu; + this.$scope.confStatus = this.sdcMenu.statuses; + this.$scope.expandedSection = ["type", "cssClasses", "product-category", "status"]; + this.$scope.user = this.userResourceService.getLoggedinUser(); + this.$scope.catalogMenuItem = this.sdcMenu.catalogMenuItem; + this.$scope.version = this.cacheService.get('version'); + this.$scope.sortBy = 'lastUpdateDate'; + this.$scope.reverse = true; + + + // Checklist init + this.$scope.checkboxes = <Checkboxes>{}; + this.$scope.checkboxes.componentTypes = ['Resource', 'Service', 'Product']; + this.$scope.checkboxes.resourceSubTypes = ['VF', 'VFC', 'CP', 'VL']; + + // Checkboxes filter init + this.$scope.checkboxesFilter = <CheckboxesFilter>{}; + this.$scope.checkboxesFilter.selectedComponentTypes = []; + this.$scope.checkboxesFilter.selectedResourceSubTypes = []; + this.$scope.checkboxesFilter.selectedCategoriesModel = []; + this.$scope.checkboxesFilter.selectedStatuses = []; + + // this.$scope.isAllItemDisplay = this.$scope.numberOfItemToDisplay >= this.$scope.catalogFilterdItems.length; + }; + + private initScopeMethods = ():void => { + this.$scope.sectionClick = (section:string):void => { + let index:number = this.$scope.expandedSection.indexOf(section); + if (index!==-1) { + this.$scope.expandedSection.splice(index,1); + } else { + this.$scope.expandedSection.push(section); + } + }; + + + this.$scope.order = (sortBy:string):void => {//default sort by descending last update. default for alphabetical = ascending + this.$scope.reverse = (this.$scope.sortBy === sortBy) ? !this.$scope.reverse : (sortBy === 'lastUpdateDate') ? true: false; + this.$scope.sortBy = sortBy; + }; + + + this.$scope.goToComponent = (component:Models.Components.Component):void => { + this.$scope.gui.isLoading = true; + this.$state.go('workspace.general', {id: component.uniqueId, type:component.componentType.toLowerCase()}); + }; + + + // Will print the number of elements found in catalog + this.$scope.getNumOfElements = (num:number) : string => { + if (!num || num===0){ + return "No Elements found"; + } else if (num===1){ + return "1 Element found"; + }else { + return num + " Elements found"; + } + }; + + /** + * Select | unselect sub resource when resource is clicked | unclicked. + * @param type + */ + this.$scope.gui.onComponentTypeClick = (type:string): void => { + if (type==='Resource'){ + if (this.$scope.checkboxesFilter.selectedComponentTypes.indexOf('Resource')===-1){ + // If the resource was not selected, unselect all childs. + this.$scope.checkboxesFilter.selectedResourceSubTypes = []; + } else { + // If the resource was selected, select all childs + this.$scope.checkboxesFilter.selectedResourceSubTypes = angular.copy(this.$scope.checkboxes.resourceSubTypes); + } + } + }; + + /** + * Selecting | unselect resources when sub resource is clicked | unclicked. + */ + this.$scope.gui.onResourceSubTypesClick = ():void => { + if (this.$scope.checkboxesFilter.selectedResourceSubTypes && this.$scope.checkboxesFilter.selectedResourceSubTypes.length===this.$scope.checkboxes.resourceSubTypes.length){ + this.$scope.checkboxesFilter.selectedComponentTypes.push('Resource'); + } else { + this.$scope.checkboxesFilter.selectedComponentTypes = _.without(this.$scope.checkboxesFilter.selectedComponentTypes,'Resource'); + } + }; + + this.$scope.gui.onCategoryClick = (category:Models.IMainCategory): void => { + // Select | Unselect all childs + if (this.isCategorySelected(category.uniqueId)){ + this.$scope.checkboxesFilter.selectedCategoriesModel = this.$scope.checkboxesFilter.selectedCategoriesModel.concat(angular.copy(_.map(category.subcategories, (item) => { return item.uniqueId; }))); + if (category.subcategories) { + category.subcategories.forEach((sub:Models.ISubCategory)=> { // Loop on all selected subcategories and mark the childrens + this.$scope.checkboxesFilter.selectedCategoriesModel = this.$scope.checkboxesFilter.selectedCategoriesModel.concat(angular.copy(_.map(sub.groupings, (item) => { + return item.uniqueId; + }))); + }); + } + } else { + this.$scope.checkboxesFilter.selectedCategoriesModel = _.difference(this.$scope.checkboxesFilter.selectedCategoriesModel, _.map(category.subcategories, (item) => { return item.uniqueId; })); + if (category.subcategories) { + category.subcategories.forEach((sub:Models.ISubCategory)=> { // Loop on all selected subcategories and un mark the childrens + this.$scope.checkboxesFilter.selectedCategoriesModel = _.difference(this.$scope.checkboxesFilter.selectedCategoriesModel, _.map(sub.groupings, (item) => { + return item.uniqueId; + })); + }); + } + } + }; + + this.$scope.gui.onSubcategoryClick = (category:Models.IMainCategory, subCategory:Models.ISubCategory) : void => { + // Select | Unselect all childs + if (this.isCategorySelected(subCategory.uniqueId)){ + this.$scope.checkboxesFilter.selectedCategoriesModel = this.$scope.checkboxesFilter.selectedCategoriesModel.concat(angular.copy(_.map(subCategory.groupings, (item) => { return item.uniqueId; }))); + } else { + this.$scope.checkboxesFilter.selectedCategoriesModel = _.difference(this.$scope.checkboxesFilter.selectedCategoriesModel, _.map(subCategory.groupings, (item) => { return item.uniqueId; })); + } + + // Mark | Un mark the parent when all childs selected. + if (this.areAllCategoryChildsSelected(category)){ + // Add the category to checkboxesFilter.selectedCategoriesModel + this.$scope.checkboxesFilter.selectedCategoriesModel.push(category.uniqueId); + } else { + this.$scope.checkboxesFilter.selectedCategoriesModel = _.without(this.$scope.checkboxesFilter.selectedCategoriesModel, category.uniqueId); + } + + }; + + this.$scope.raiseNumberOfElementToDisplay = () : void => { + this.$scope.numberOfItemToDisplay = this.$scope.numberOfItemToDisplay +35; + if(this.$scope.catalogFilterdItems) { + this.$scope.isAllItemDisplay = this.$scope.numberOfItemToDisplay >= this.$scope.catalogFilterdItems.length; + } + }; + + this.$scope.gui.onGroupClick = (subCategory:Models.ISubCategory) : void => { + // Mark | Un mark the parent when all childs selected. + if (this.areAllSubCategoryChildsSelected(subCategory)){ + // Add the category to checkboxesFilter.selectedCategoriesModel + this.$scope.checkboxesFilter.selectedCategoriesModel.push(subCategory.uniqueId); + } else { + this.$scope.checkboxesFilter.selectedCategoriesModel = _.without(this.$scope.checkboxesFilter.selectedCategoriesModel, subCategory.uniqueId); + } + }; + + + }; + + private areAllCategoryChildsSelected = (category:Models.IMainCategory):boolean => { + if (!category.subcategories){return false;} + let allIds = _.map(category.subcategories, (sub:Models.ISubCategory)=>{return sub.uniqueId;}); + let total = _.intersection(this.$scope.checkboxesFilter.selectedCategoriesModel, allIds); + return total.length === category.subcategories.length?true:false; + }; + + private areAllSubCategoryChildsSelected = (subCategory:Models.ISubCategory):boolean => { + if (!subCategory.groupings){return false;} + let allIds = _.map(subCategory.groupings, (group:Models.IGroup)=>{return group.uniqueId;}); + let total = _.intersection(this.$scope.checkboxesFilter.selectedCategoriesModel, allIds); + return total.length === subCategory.groupings.length?true:false; + }; + + private isCategorySelected = (uniqueId:string):boolean => { + if (this.$scope.checkboxesFilter.selectedCategoriesModel.indexOf(uniqueId)!==-1){ + return true; + } + return false; + }; + + } +} diff --git a/catalog-ui/app/scripts/view-models/catalog/catalog-view-tests.ts b/catalog-ui/app/scripts/view-models/catalog/catalog-view-tests.ts new file mode 100644 index 0000000000..3e21835233 --- /dev/null +++ b/catalog-ui/app/scripts/view-models/catalog/catalog-view-tests.ts @@ -0,0 +1,309 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +/// <reference path="../../references"/> +describe("test catalog-view", () => { + + let $controllerMock:ng.IControllerService; + let $qMock:ng.IQService; + let $httpBackendMock:ng.IHttpBackendService; + let $scopeMock:Sdc.ViewModels.ICatalogViewModelScope; + let $stateMock:ng.ui.IStateService; + let $stateParams:any; + let entityServiceMock; + let cacheServiceMock; + + beforeEach(angular.mock.module('sdcApp')); + + let getAllEntitiesResponseMock = [ + { + "uniqueId": "855acdc7-7976-4913-9fa6-25220bd5a069", + "uuid": "8bc54f94-082c-42fa-9049-84767df3ff05", + "contactId": "qa1234", + "category": "VoIP Call Control", + "creationDate": 1447234712398, + "description": "ddddd", + "highestVersion": true, + "icon": "mobility", + "lastUpdateDate": 1447234712398, + "lastUpdaterUserId": "cs0008", + "lastUpdaterFullName": "Carlos Santana", + "lifecycleState": "NOT_CERTIFIED_CHECKOUT", + "distributionStatus": "DISTRIBUTION_NOT_APPROVED", + "projectCode": "233233", + "name": "mas mas mas mas mas mas mas mas mas mas mas mas ma", + "version": "0.1", + "type": 0, + "tags": [ + "mas mas mas mas mas mas mas mas mas mas mas mas ma" + ], + "systemName": "MasMasMasMasMasMasMasMasMasMasMasMasMa", + "vnf": true, + "$$hashKey": "object:30" + }, + { + "uniqueId": "4bb577ce-cb2c-4cb7-bb39-58644b5e73cb", + "uuid": "e27f4723-c9ec-4160-89da-dbf84d19a7e3", + "contactId": "qa1111", + "category": "Mobility", + "creationDate": 1447238503181, + "description": "aqa", + "highestVersion": true, + "icon": "call_controll", + "lastUpdateDate": 1447248991388, + "lastUpdaterUserId": "jm0007", + "lastUpdaterFullName": "Joni Mitchell", + "lifecycleState": "CERTIFIED", + "distributionStatus": "DISTRIBUTION_REJECTED", + "projectCode": "111111", + "name": "martin18", + "version": "1.0", + "type": 0, + "tags": [ + "martin18" + ], + "systemName": "Martin18", + "vnf": true + }, + { + "uniqueId": "f192f4a6-7fbf-42e4-a546-37509df28dc1", + "uuid": "0b77dc0d-222e-4d10-85cd-e420c9481417", + "contactId": "fd1212", + "category": "Application Layer 4+/Web Server", + "creationDate": 1447233679778, + "description": "geefw", + "highestVersion": true, + "icon": "database", + "lastUpdateDate": 1447233681582, + "lastUpdaterUserId": "cs0008", + "lastUpdaterFullName": "Carlos Santana", + "lifecycleState": "NOT_CERTIFIED_CHECKOUT", + "name": "ger", + "version": "0.1", + "type": 1, + "tags": [ + "ger" + ], + "vendorName": "fewwfe", + "vendorRelease": "fewew", + "systemName": "Ger", + "$$hashKey": "object:31" + }, + { + "uniqueId": "78392d08-1859-47c2-b1f2-1a35b7f8c30e", + "uuid": "8cdd63b2-6a62-4376-9012-624f424f71d4", + "contactId": "qw1234", + "category": "Application Layer 4+/Application Servers", + "creationDate": 1447234046114, + "description": "test", + "highestVersion": true, + "icon": "router", + "lastUpdateDate": 1447234050545, + "lastUpdaterUserId": "cs0008", + "lastUpdaterFullName": "Carlos Santana", + "lifecycleState": "NOT_CERTIFIED_CHECKOUT", + "name": "test", + "version": "0.1", + "type": 1, + "tags": [ + "test" + ], + "vendorName": "test", + "vendorRelease": "test", + "systemName": "Test", + "$$hashKey": "object:32" + }, + { + "uniqueId": "939e153d-2236-410f-b4a9-3b4bf8c79c9e", + "uuid": "84862547-4f56-4058-b78e-40df5f374d7e", + "contactId": "qw1234", + "category": "Application Layer 4+/Application Servers", + "creationDate": 1447235242560, + "description": "jlk", + "highestVersion": true, + "icon": "database", + "lastUpdateDate": 1447235328062, + "lastUpdaterUserId": "cs0008", + "lastUpdaterFullName": "Carlos Santana", + "lifecycleState": "NOT_CERTIFIED_CHECKIN", + "name": "new", + "version": "0.1", + "type": 1, + "tags": [ + "new" + ], + "vendorName": "e", + "vendorRelease": "e", + "systemName": "New", + "$$hashKey": "object:33" + }, + { + "uniqueId": "ece818e0-fd59-477a-baf6-e27461a7ce23", + "uuid": "8db823c2-6a9c-4636-8676-f5e713270dd7", + "contactId": "uf2345", + "category": "Network Layer 2-3/Router", + "creationDate": 1447235352429, + "description": "u", + "highestVersion": true, + "icon": "network", + "lastUpdateDate": 1447235370064, + "lastUpdaterUserId": "cs0008", + "lastUpdaterFullName": "Carlos Santana", + "lifecycleState": "NOT_CERTIFIED_CHECKOUT", + "name": "u", + "version": "0.1", + "type": 1, + "tags": [ + "u" + ], + "vendorName": "u", + "vendorRelease": "u", + "systemName": "U", + "$$hashKey": "object:34" + } + ]; + + let resourceCategoriesResponseMock = [{"name":"Network L2-3","normalizedName":"network l2-3","uniqueId":"resourceNewCategory.network l2-3","subcategories":[{"name":"Gateway","normalizedName":"gateway","uniqueId":"resourceNewCategory.network l2-3.gateway","icons":["gateway"]},{"name":"Infrastructure","normalizedName":"infrastructure","uniqueId":"resourceNewCategory.network l2-3.infrastructure","icons":["ucpe"]},{"name":"WAN Connectors","normalizedName":"wan connectors","uniqueId":"resourceNewCategory.network l2-3.wan connectors","icons":["network","connector","port"]},{"name":"LAN Connectors","normalizedName":"lan connectors","uniqueId":"resourceNewCategory.network l2-3.lan connectors","icons":["network","connector","port"]},{"name":"Router","normalizedName":"router","uniqueId":"resourceNewCategory.network l2-3.router","icons":["router","vRouter"]}]},{"name":"Network L4+","normalizedName":"network l4+","uniqueId":"resourceNewCategory.network l4+","subcategories":[{"name":"Common Network Resources","normalizedName":"common network resources","uniqueId":"resourceNewCategory.network l4+.common network resources","icons":["network"]}]},{"name":"Application L4+","normalizedName":"application l4+","uniqueId":"resourceNewCategory.application l4+","subcategories":[{"name":"Load Balancer","normalizedName":"load balancer","uniqueId":"resourceNewCategory.application l4+.load balancer","icons":["loadBalancer"]},{"name":"Media Servers","normalizedName":"media servers","uniqueId":"resourceNewCategory.application l4+.media servers","icons":["applicationServer"]},{"name":"Application Server","normalizedName":"application server","uniqueId":"resourceNewCategory.application l4+.application server","icons":["applicationServer"]},{"name":"Database","normalizedName":"database","uniqueId":"resourceNewCategory.application l4+.database","icons":["database"]},{"name":"Call Control","normalizedName":"call control","uniqueId":"resourceNewCategory.application l4+.call control","icons":["call_controll"]},{"name":"Border Element","normalizedName":"border element","uniqueId":"resourceNewCategory.application l4+.border element","icons":["borderElement"]},{"name":"Web Server","normalizedName":"web server","uniqueId":"resourceNewCategory.application l4+.web server","icons":["applicationServer"]},{"name":"Firewall","normalizedName":"firewall","uniqueId":"resourceNewCategory.application l4+.firewall","icons":["firewall"]}]},{"name":"Generic","normalizedName":"generic","uniqueId":"resourceNewCategory.generic","subcategories":[{"name":"Database","normalizedName":"database","uniqueId":"resourceNewCategory.generic.database","icons":["database"]},{"name":"Abstract","normalizedName":"abstract","uniqueId":"resourceNewCategory.generic.abstract","icons":["objectStorage","compute"]},{"name":"Network Elements","normalizedName":"network elements","uniqueId":"resourceNewCategory.generic.network elements","icons":["network","connector"]},{"name":"Infrastructure","normalizedName":"infrastructure","uniqueId":"resourceNewCategory.generic.infrastructure","icons":["connector"]}]},{"name":"NewCategory","normalizedName":"newcategory","uniqueId":"resourceNewCategory.newcategory","subcategories":[{"name":"MyNewSubCategory","normalizedName":"mynewsubcategory","uniqueId":"resourceNewCategory.newcategory.mynewsubcategory"}]}]; + + let getAllEntitiesDefered:ng.IDeferred<any> = null; + + beforeEach(angular.mock.inject((_$controller_:ng.IControllerService, + _$httpBackend_:ng.IHttpBackendService, + _$rootScope_, + _$q_:ng.IQService, + _$state_:ng.ui.IStateService, + _$stateParams_:any) => { + + $controllerMock = _$controller_; + $httpBackendMock = _$httpBackend_ + $scopeMock = _$rootScope_.$new(); + $qMock = _$q_; + $stateMock = _$state_; + $stateParams = _$stateParams_; + + + //handle all http request thet not relevant to the tests + $httpBackendMock.expectGET(/.*languages\/en_US.json.*/).respond(200, JSON.stringify({})); + $httpBackendMock.expectGET(/.*rest\/version.*/).respond(200, JSON.stringify({})); + $httpBackendMock.expectGET(/.*configuration\/ui.*/).respond(200, JSON.stringify({})); + $httpBackendMock.expectGET(/.*user\/authorize.*/).respond(200, JSON.stringify({})); + $httpBackendMock.expectGET(/.*categories\/services.*/).respond(200, JSON.stringify({})); + $httpBackendMock.expectGET(/.*categories\/resources.*/).respond(200, JSON.stringify({})); + $httpBackendMock.expectGET(/.*categories\/products.*/).respond(200, JSON.stringify({})); + $httpBackendMock.expectGET('http://feHost:8181/sdc1/feProxy/rest/version').respond(200, JSON.stringify({})); + + /** + * Mock the service + * @type {any} + */ + getAllEntitiesDefered = $qMock.defer(); + getAllEntitiesDefered.resolve(getAllEntitiesResponseMock); + + cacheServiceMock = jasmine.createSpyObj('cacheServiceMock', ['get']); + cacheServiceMock.get.and.callFake(function(string){return resourceCategoriesResponseMock;}); + /* + cacheServiceMock.get.and.callFake(function(value:string){ + switch(value){ + case 'serviceCategories': + console.log('serviceCategories'); + break; + case 'resourceCategories': + console.log('resourceCategories'); + break; + case 'productCategories': + console.log('productCategories'); + break; + default : + console.log('default'); + break; + } + }); + */ + + entityServiceMock = jasmine.createSpyObj('entityServiceMock', ['getCatalog']); + entityServiceMock.getCatalog.and.returnValue(getAllEntitiesDefered.promise); + + // $stateParams['show'] = ''; + + /** + * Need to inject into the controller only the objects that we want to MOCK + * those that we need to change theirs behaviors + */ + $controllerMock(Sdc.ViewModels.CatalogViewModel, { + '$scope': $scopeMock, + '$stateParams': $stateParams, + 'Sdc.Services.EntityService': entityServiceMock, + 'Sdc.Services.CacheService': cacheServiceMock + }); + + })); + + + beforeEach(function () { + }); + + describe("test GUI events on checkbox type resource click", function () { + + /** + * The function checks only for resource type. + * Select the Resource and verify that the sub resources are selected. + * + */ + it('test onComponentTypeClick (check select checkbox of Resource type)', function () { + $scopeMock.$apply(); + $scopeMock.checkboxesFilter.selectedComponentTypes = ['Resource']; + $scopeMock.gui.onComponentTypeClick('Resource'); + expect($scopeMock.checkboxesFilter.selectedResourceSubTypes.length === 4).toBeTruthy(); + }); + + /** + * The function checks only for resource type. + * Un select the Resource and verify that the sub resources are selected. + * + */ + it('test onComponentTypeClick (check un select checkbox of Resource type)', function () { + $scopeMock.$apply(); + $scopeMock.gui.onComponentTypeClick('Resource'); + expect($scopeMock.checkboxesFilter.selectedResourceSubTypes.length === 0).toBeTruthy(); + }); + + }); + + describe("test GUI events on checkbox main category click -> sub categories are selected", function () { + + /** + * The function checks that after selecting 2 main categories, the subcategories are selected also. + * + */ + it('test onComponentTypeClick (check select checkbox of Resource type)', function () { + let category1 = resourceCategoriesResponseMock[0]; + let category2 = resourceCategoriesResponseMock[1]; + + $scopeMock.$apply(); + $scopeMock.checkboxesFilter.selectedCategoriesModel = [category1.uniqueId, category2.uniqueId]; + $scopeMock.gui.onCategoryClick(category1); + $scopeMock.gui.onCategoryClick(category2); + + expect($scopeMock.checkboxesFilter.selectedCategoriesModel.length===8).toBeTruthy(); + }); + + }); + + +}); diff --git a/catalog-ui/app/scripts/view-models/catalog/catalog-view.html b/catalog-ui/app/scripts/view-models/catalog/catalog-view.html new file mode 100644 index 0000000000..0d46dc2a24 --- /dev/null +++ b/catalog-ui/app/scripts/view-models/catalog/catalog-view.html @@ -0,0 +1,190 @@ +<div class="sdc-catalog-container"> + + <loader data-display="gui.isLoading"></loader> +<!-- + <ecomp-header menu-data="menuItems" version="{{version}}"></ecomp-header> +--> + + <div class="w-sdc-main-container"> + + <!-- LEFT SIDE --> + <perfect-scrollbar scroll-y-margin-offset="0" class="sdc-catalog-body-container w-sdc-left-sidebar" include-padding="true"> + <div class="sdc-catalog-leftbar-container"> + + <div class="sdc-catalog-type-filter-container"> + <div + class="i-sdc-designer-leftbar-section-title pointer" + data-ng-click="sectionClick('type')" + data-ng-class="{'expanded': expandedSection.indexOf('type') !== -1}"> + <span class="i-sdc-designer-leftbar-section-title-icon"></span> + <span class="i-sdc-designer-leftbar-section-title-text" data-tests-id="typeFilterTitle">Type</span> + </div> + <div class="i-sdc-designer-leftbar-section-content"> + <ul class="list-unstyled i-sdc-designer-leftbar-section-content-ul"> + <li class="i-sdc-designer-leftbar-section-content-ul-li" data-ng-repeat="type in checkboxes.componentTypes"> + + <sdc-checkbox elem-id="checkbox-{{type | lowercase | clearWhiteSpaces}}" + sdc-checklist-model="checkboxesFilter.selectedComponentTypes" + sdc-checklist-value="type" + data-ng-click="gui.onComponentTypeClick(type)" + text="{{type}}"></sdc-checkbox> + + <ul class="list-unstyled i-sdc-catalog-subcategories-checkbox" data-ng-if="type==='Resource'"> + <li data-ng-repeat="subType in checkboxes.resourceSubTypes"> + + <sdc-checkbox elem-id="checkbox-{{subType | lowercase | clearWhiteSpaces}}" + sdc-checklist-model="checkboxesFilter.selectedResourceSubTypes" + sdc-checklist-value="subType" + data-ng-click="gui.onResourceSubTypesClick()" + text="{{subType}}"></sdc-checkbox> + + </li> + </ul> + </li> + </ul> + </div> + </div> + + <div class="sdc-catalog-categories-filter-container"> + <div + class="i-sdc-designer-leftbar-section-title pointer" + data-ng-click="sectionClick('category')" + data-ng-class="{'expanded': expandedSection.indexOf('category') !== -1}"> + <span class="i-sdc-designer-leftbar-section-title-icon"></span> + <span class="i-sdc-designer-leftbar-section-title-text" data-tests-id="categoriesFilterTitle">Categories</span> + </div> + <div class="i-sdc-designer-leftbar-section-content"> + + <!-- CATEGORY CHECKBOX --> + <ul class="list-unstyled i-sdc-designer-leftbar-section-content-ul"> + <li class="i-sdc-designer-leftbar-section-content-ul-li" + data-ng-repeat="category in categories track by category.uniqueId | categoryTypeFilter:checkboxesFilter.selectedComponentTypes | orderBy: category"> + + <sdc-checkbox elem-id="checkbox-{{category.uniqueId | lowercase | clearWhiteSpaces}}" + sdc-checklist-model="checkboxesFilter.selectedCategoriesModel" + sdc-checklist-value="category.uniqueId" + data-tests-id="{{category.uniqueId}}" + data-ng-click="gui.onCategoryClick(category)" + text="{{category.name}}"></sdc-checkbox> + + <!-- SUB CATEGORY CHECKBOX --> + <ul class="list-unstyled i-sdc-catalog-subcategories-checkbox" data-ng-if="category.subcategories && category.subcategories.length>0"> + <li ng-repeat="subcategory in category.subcategories track by subcategory.uniqueId | orderBy:'name'"> + + <sdc-checkbox elem-id="checkbox-{{subcategory.uniqueId | lowercase | clearWhiteSpaces}}" + sdc-checklist-model="checkboxesFilter.selectedCategoriesModel" + sdc-checklist-value="subcategory.uniqueId" + data-tests-id="{{subcategory.uniqueId}}" + data-ng-click="gui.onSubcategoryClick($parent.category, subcategory)" + text="{{subcategory.name}}"></sdc-checkbox> + + <!-- GROUPING CHECKBOX --> + <ul class=" list-unstyled i-sdc-catalog-grouping-checkbox" data-ng-if="subcategory.groupings && subcategory.groupings.length>0"> + <li ng-repeat="grouping in subcategory.groupings track by grouping.uniqueId | orderBy:'name'"> + + <sdc-checkbox elem-id="checkbox-{{grouping.uniqueId | lowercase | clearWhiteSpaces}}" + sdc-checklist-model="checkboxesFilter.selectedCategoriesModel" + sdc-checklist-value="grouping.uniqueId" + data-ng-click="gui.onGroupClick($parent.subcategory)" + text="{{grouping.name}}"></sdc-checkbox> + + </li> + </ul> + </li><!-- Close subcategory --> + </ul><!-- Close subcategories --> + </li><!-- Close main category --> + </ul><!-- Close main categories --> + + </div> + </div> + + <!-- STATUS --> + <div class="sdc-catalog-status-filter-container"> + <div + class="i-sdc-designer-leftbar-section-title pointer" + data-ng-click="sectionClick('status')" + data-ng-class="{'expanded': expandedSection.indexOf('status') !== -1}"> + <span class="i-sdc-designer-leftbar-section-title-icon"></span> + <span class="i-sdc-designer-leftbar-section-title-text" data-tests-id="statusFilterTitle">Status</span> + </div> + + <div class="i-sdc-designer-leftbar-section-content"> + <ul class="list-unstyled i-sdc-designer-leftbar-section-content-ul"> + <!--li data-ng-repeat="(key, value) in confStatus" --> + + <li class="i-sdc-designer-leftbar-section-content-ul-li" + data-ng-repeat="(key, state) in confStatus | catalogStatusFilter"> + + <sdc-checkbox elem-id="checkbox-{{key | lowercase | clearWhiteSpaces}}" + sdc-checklist-model="checkboxesFilter.selectedStatuses" + sdc-checklist-value="state.values" + text="{{state.name}}"></sdc-checkbox> + + <div class="i-sdc-categories-list-item-icon"></div> + </label> + </li> + </ul> + </div> + </div> + + </div> + </perfect-scrollbar> + + <!-- RIGHT SIDE --> + <perfect-scrollbar id="catalog-main-scroll" include-padding="true" class="w-sdc-main-right-container w-sdc-catalog-main"> + + <!-- HEADER --> + <div> + <div class="w-sdc-dashboard-catalog-header"> + {{getNumOfElements((catalogFilterdItems | entityFilter:checkboxesFilter | filter:search).length)}} + </div> + <div class="w-sdc-dashboard-catalog-header-right"> + <span class="w-sdc-dashboard-catalog-header-order" translate="SORT_CAPTION"></span> + <a class="w-sdc-dashboard-catalog-sort" data-tests-id="sort-by-last-update" data-ng-class="{'blue' : sortBy==='lastUpdateDate'}" + ng-click="order('lastUpdateDate')" translate="SORT_BY_UPDATE_DATE"></a> + <span data-ng-show="sortBy === 'lastUpdateDate'" class="w-sdc-catalog-sort-arrow" data-ng-class="{'down': reverse, 'up':!reverse}"></span> + | + <a class="w-sdc-dashboard-catalog-sort" data-tests-id="sort-by-alphabetical" data-ng-class="{'blue' : sortBy!=='lastUpdateDate'}" + ng-click="order('name | resourceName')" translate="SORT_ALPHABETICAL"></a> + <span data-ng-show="sortBy !== 'lastUpdateDate'" class="w-sdc-catalog-sort-arrow" data-ng-class="{'down': reverse, 'up':!reverse}"></span> + </div> + </div> + + <div infinite-scroll-disabled='isAllItemDisplay' infinite-scroll="raiseNumberOfElementToDisplay()" infinite-scroll-container="'#catalog-main-scroll'" infinite-scroll-parent> + <!-- CARDS --> + <div data-ng-class="{'sdc-hide-popover': hidePopover}" + data-ng-init="component.filterTerm = component.name + ' ' + component.description + ' ' + component.tags.toString() + ' ' + component.version" + class="w-sdc-dashboard-card" + data-ng-repeat="component in catalogFilterdItems | entityFilter:checkboxesFilter | filter:search | orderBy:sortBy:reverse | limitTo:numberOfItemToDisplay" + data-ng-class="{'resource' : component.isResource(), 'service' : component.isService(), 'product' : component.isProduct()}"> + + <div class="w-sdc-dashboard-card-body" data-ng-click="gui.isLoading || goToComponent(component)"> + <div class="w-sdc-dashboard-card-avatar"><span data-tests-id="asset-type" class="{{component.getComponentSubType()}}"></span></div> + <!--<div class="w-sdc-dashboard-card-edit " data-ng-class="component.lifecycleState" data-tests-id="assetlifecycleState {{getStatus()}}"></div>--> + <div class="w-sdc-dashboard-card-schema-image {{component.icon}}" data-tests-id="{{component.categories[0].subcategories[0].uniqueId}}" data-ng-class="{'sprite-resource-icons':component.isResource(), 'sprite-services-icons':component.isService(), 'sprite-product-icons':component.isProduct()}"></div> + <!--<div class="w-sdc-dashboard-card-description">{{component.description}}</div>--> + <div class="w-sdc-dashboard-card-info-name-container"> + <span class="w-sdc-dashboard-card-info-name" tooltips + tooltip-content="{{component.name | resourceName}}"> {{component.name | resourceName}}</span> + </div> + </div> + + <div class="w-sdc-dashboard-card-footer"> + <div class="w-sdc-dashboard-card-info"> + <div class="w-sdc-dashboard-card-info-lifecycleState"> + <span class="w-sdc-dashboard-card-info-lifecycleState" tooltips + tooltip-content="{{component.getStatus(sdcMenu)}}"> {{component.getStatus(sdcMenu)}}</span> + </div> + <div class="w-sdc-dashboard-card-info-user">V {{component.version}}</div> + </div> + <!--<div class="w-sdc-dashboard-card-info-lifecycleState-icon sprite-new {{sdcMenu.LifeCycleStatuses[component.lifecycleState].icon}}"></div>--> + </div> + </div> + </div> + </perfect-scrollbar> + + </div> + + <top-nav top-lvl-selected-index="1" search-bind="search.filterTerm" version="{{version}}"></top-nav> + +</div> diff --git a/catalog-ui/app/scripts/view-models/catalog/catalog.less b/catalog-ui/app/scripts/view-models/catalog/catalog.less new file mode 100644 index 0000000000..8be90a6a59 --- /dev/null +++ b/catalog-ui/app/scripts/view-models/catalog/catalog.less @@ -0,0 +1,304 @@ +.sdc-catalog-container { + + .i-sdc-categories-list-item { + font-weight: normal; + } + + // Checkboxes + .i-sdc-designer-leftbar-section-content-ul { + padding: 0; + margin: 0; + + .i-sdc-catalog-subcategories-checkbox { + padding: 0 0 0 20px; + margin: 0; + + .i-sdc-catalog-grouping-checkbox { + padding: 0 0 0 20px; + margin: 0; + } + + } + + } + + .i-sdc-designer-leftbar-section-content-li { + &:last-child { + .i-sdc-categories-list-item { + margin: 0; + } + } + } + + .i-sdc-categories-list-item { + display: block; + //margin-bottom: 5px; + //padding-left: 15px; + //text-indent: -24px; + vertical-align: top; + font-weight: bold; + } + + .i-sdc-subcategories-list-item { + display: block; + //padding-left: 20px; + vertical-align: top; + font-weight: normal; + margin: 0; + //text-indent: -10px; + } + + /*Added by - Ikram */ + .i-sdc-product-input, + .i-sdc-product-select { + border: 1px solid @border_color_f; + min-height: 30px; + padding: 0; + width: 100%; + margin: 1px 0; + background-color: #F2F2F2; + outline: none; + + &:disabled { + .disabled; + } + optgroup{ + color: @color_u; + option{ + color: @color_b; + } + } + } + + .i-sdc-categories-list-item-icon { + display: inline-block; + float: right; + position: relative; + right: -8px; + top: 6px; + } + + .i-sdc-categories-list-item { + margin-top: 7px; + &.NOT_CERTIFIED_CHECKOUT, + &.NOT_CERTIFIED_CHECKIN { + .i-sdc-categories-list-item-icon { + background: url('../../../styles/images/sprites/sprite-global-old.png') no-repeat -53px -2889px; + width: 14px; + height: 14px; + + } + } + + &.CERTIFIED { + .i-sdc-categories-list-item-icon { + background: url('../../../styles/images/sprites/sprite-global-old.png') no-repeat -53px -3034px; + width: 14px; + height: 16px; + } + } + + &.READY_FOR_CERTIFICATION { + .i-sdc-categories-list-item-icon { + background: url('../../../styles/images/sprites/sprite-global-old.png') no-repeat -53px -2985px; + width: 14px; + height: 16px; + } + } + + &.CERTIFICATION_IN_PROGRESS { + .i-sdc-categories-list-item-icon { + background: url('../../../styles/images/sprites/sprite-global-old.png') no-repeat -53px -2934px; + width: 14px; + height: 16px; + } + } + + &.DISTRIBUTED, + &.TBD { + .i-sdc-categories-list-item-icon { + background: url('../../../styles/images/sprites/sprite-global-old.png') no-repeat -43px -3087px; + width: 24px; + height: 14px; + + } + } + } + + .i-sdc-categories-list-input { + margin: 8px; + + } + + .i-sdc-subcategories-list-input { + + margin: 8px; + } + .i-sdc-subcategories-list-input-container { + margin: 0px 0px 0px 20px; + padding: 2px; + } + + .w-sdc-header-catalog-search-container { + display: table; + padding: 21px 0; + position: relative; + + .w-sdc-designer-leftbar-search-input { + color: #000; + width: 300px; + } + + // .magnification { + // .sprite; + // .sprite.magnification-glass; + // .hand; + // position: absolute; + // top: 40px; + // right: 42px; + // } + } + + .w-sdc-catalog-main { + padding: 10px 12px; + } + .w-sdc-dashboard-catalog-header { + .b_9; + display: inline-block; + font-style: italic; + font-weight: bold; + padding-left: 10px; + } + + .w-sdc-dashboard-catalog-header-order { + .b_9; + font-weight: 800; + } + + .w-sdc-dashboard-catalog-sort { + .b_9; + font-weight: bold; + white-space:pre; + &:hover{ + .hand; + text-decoration: none; + .a_9; + } + &.blue { + .a_9; + } + } + + .w-sdc-catalog-sort-arrow{ + display: inline-block; + &.up{ + .b_9; + width: 0; + height: 0; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid ; + } + &.down{ + .b_9; + width: 0; + height: 0; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid; + } + } + + + + + .w-sdc-dashboard-catalog-header-right{ + float: right; + display: inline-block; + padding-right:34px; + } + + .w-sdc-header-catalog-search-input { + width: 420px; + display: table-cell; + padding: 0 25px 1px 10px; + border: 1px solid #bcbcbc; + .border-radius(10px); + height: 30px; + margin: 10px 30px; + outline: none; + } + + .sdc-catalog-type-filter-container { + margin-top: -1px; + } + + .i-sdc-designer-leftbar-section-title { + text-transform: uppercase; + .l_14_m; + line-height: 30px; + } + + .i-sdc-designer-leftbar-section-title-icon { + .hand; + .tlv-sprite; + .footer-close; + transition: .3s all; + margin-top: -4px; + } + + .i-sdc-designer-leftbar-section-title-text { + margin-left: 20px; + } + + .seperator-left, + .seperator-right { + border-right: solid 1px @color_m; + display: table-cell; + width: 2px; + } + + // Rotate catalog left side arrows + .i-sdc-designer-leftbar-section-title.expanded .i-sdc-designer-leftbar-section-title-icon { + transform: rotate(180deg); + } + + // Transform catalog left side sections + .i-sdc-designer-leftbar-section-title + .i-sdc-designer-leftbar-section-content { + max-height: 0px; + margin: 0 auto; + transition: all .3s; + overflow: hidden; + padding: 0 10px 0 18px; + } + + .i-sdc-designer-leftbar-section-title.expanded + .i-sdc-designer-leftbar-section-content { + max-height: 9999px; + margin: 0 auto 1px; + transition: all .3s; + padding: 10px 18px 10px 18px; + overflow: hidden; + } + +} + +.w-sdc-search-icon{ + position: absolute; + right: 40px; + top: 40px; + &.leftbar{ + top: 19px; + right: 18px; + } + &.magnification { + .sprite; + .sprite.magnification-glass; + .hand; + } + + &.cancel { + .sprite; + .sprite.clear-text; + .hand; + } +} |