summaryrefslogtreecommitdiffstats
path: root/catalog-ui/src/app/ng2/pages/home
diff options
context:
space:
mode:
authorys9693 <ys9693@att.com>2020-01-19 13:50:02 +0200
committerOfir Sonsino <ofir.sonsino@intl.att.com>2020-01-22 12:33:31 +0000
commit16a9fce0e104a38371a9e5a567ec611ae3fc7f33 (patch)
tree03a2aff3060ddb5bc26a90115805a04becbaffc9 /catalog-ui/src/app/ng2/pages/home
parentaa83a2da4f911c3ac89318b8e9e8403b072942e1 (diff)
Catalog alignment
Issue-ID: SDC-2724 Signed-off-by: ys9693 <ys9693@att.com> Change-Id: I52b4aacb58cbd432ca0e1ff7ff1f7dd52099c6fe
Diffstat (limited to 'catalog-ui/src/app/ng2/pages/home')
-rw-r--r--catalog-ui/src/app/ng2/pages/home/__snapshots__/home.component.spec.ts.snap28
-rw-r--r--catalog-ui/src/app/ng2/pages/home/folders.ts93
-rw-r--r--catalog-ui/src/app/ng2/pages/home/home.component.html88
-rw-r--r--catalog-ui/src/app/ng2/pages/home/home.component.less126
-rw-r--r--catalog-ui/src/app/ng2/pages/home/home.component.spec.ts270
-rw-r--r--catalog-ui/src/app/ng2/pages/home/home.component.ts358
-rw-r--r--catalog-ui/src/app/ng2/pages/home/home.module.ts31
7 files changed, 994 insertions, 0 deletions
diff --git a/catalog-ui/src/app/ng2/pages/home/__snapshots__/home.component.spec.ts.snap b/catalog-ui/src/app/ng2/pages/home/__snapshots__/home.component.spec.ts.snap
new file mode 100644
index 0000000000..ae5445e546
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/home/__snapshots__/home.component.spec.ts.snap
@@ -0,0 +1,28 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`home component should match current snapshot 1`] = `
+<home-page
+ $state={[Function Object]}
+ authService={[Function Object]}
+ cacheService={[Function Object]}
+ componentShouldReload={[Function Function]}
+ homeService={[Function Object]}
+ importVSPService={[Function Object]}
+ initFolders={[Function Function]}
+ isDefaultFilter={[Function Function]}
+ loaderService={[Function Object]}
+ modalService={[Function Object]}
+ modalsHandler={[Function Object]}
+ sdcConfig={[Function Object]}
+ sdcMenu={[Function Object]}
+ translateService={[Function Object]}
+ updateFilter={[Function Function]}
+>
+ <div
+ class="sdc-catalog-container"
+ >
+
+ <top-nav />
+ </div>
+</home-page>
+`;
diff --git a/catalog-ui/src/app/ng2/pages/home/folders.ts b/catalog-ui/src/app/ng2/pages/home/folders.ts
new file mode 100644
index 0000000000..036ae329b7
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/home/folders.ts
@@ -0,0 +1,93 @@
+
+export interface IItemMenu {
+
+}
+
+export interface IMenuItemProperties {
+ text:string;
+ group:string;
+ state:string;
+ dist:string;
+ groupname:string;
+ states:Array<any>;
+}
+
+export class FoldersMenu {
+ private _folders:Array<FoldersItemsMenu> = [];
+
+ constructor(folders:Array<IMenuItemProperties>) {
+ let self = this;
+ folders.forEach(function (folder:IMenuItemProperties) {
+ if (folder.groupname) {
+ self._folders.push(new FoldersItemsMenuGroup(folder));
+ } else {
+ self._folders.push(new FoldersItemsMenu(folder));
+ }
+ });
+ self._folders[0].setSelected(true);
+ }
+
+ public getFolders():Array<FoldersItemsMenu> {
+ return this._folders;
+ }
+
+ public getCurrentFolder():FoldersItemsMenu {
+ let menuItem:FoldersItemsMenu = undefined;
+ this.getFolders().forEach(function (tmpFolder:FoldersItemsMenu) {
+ if (tmpFolder.isSelected()) {
+ menuItem = tmpFolder;
+ }
+ });
+ return menuItem;
+ }
+
+ public setSelected(folder:FoldersItemsMenu):void {
+ this.getFolders().forEach(function (tmpFolder:FoldersItemsMenu) {
+ tmpFolder.setSelected(false);
+ });
+ folder.setSelected(true);
+ }
+}
+
+export class FoldersItemsMenu implements IItemMenu {
+ public text:string;
+ public group:string;
+ public state:string;
+ public dist:string;
+ public states:Array<any>;
+
+ private selected:boolean = false;
+
+ constructor(menuProperties:IMenuItemProperties) {
+ this.text = menuProperties.text;
+ this.group = menuProperties.group;
+ this.state = menuProperties.state;
+ this.states = menuProperties.states;
+ this.dist = menuProperties.dist;
+ }
+
+ public isSelected():boolean {
+ return this.selected;
+ }
+
+ public setSelected(value:boolean):void {
+ this.selected = value;
+ }
+
+ public isGroup():boolean {
+ return false;
+ }
+}
+
+export class FoldersItemsMenuGroup extends FoldersItemsMenu {
+ public groupname:string;
+
+ constructor(menuProperties:IMenuItemProperties) {
+ super(menuProperties);
+ this.groupname = menuProperties.groupname;
+ }
+
+ public isGroup():boolean {
+ return true;
+ }
+}
diff --git a/catalog-ui/src/app/ng2/pages/home/home.component.html b/catalog-ui/src/app/ng2/pages/home/home.component.html
new file mode 100644
index 0000000000..1c8c2b4373
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/home/home.component.html
@@ -0,0 +1,88 @@
+<div class="sdc-catalog-container">
+ <div class="w-sdc-main-container" *ngIf="user">
+
+ <div id="dashboard-main-scroll" infiniteScroll class="w-sdc-main-right-container" (infiniteScroll)="raiseNumberOfElementToDisplay()" [infiniteScrollDistance]="100">
+
+ <div class='w-sdc-row-flex-items'>
+
+ <!-- ADD Component -->
+ <div *ngIf="user.role === 'DESIGNER'" class="w-sdc-dashboard-card-new"
+ (mouseleave)="setDisplayActions(false)"
+ (mouseover)="setDisplayActions(true)">
+ <div class="w-sdc-dashboard-card-new-content" data-tests-id="AddButtonsArea">
+ <div class="w-sdc-dashboard-card-new-content-plus" [hidden]="displayActions"></div>
+ <div class="sdc-dashboard-create-element-container" [hidden]="!displayActions">
+ <sdc-button *ngIf="roles[user.role].dashboard.showCreateNew" testId="createResourceButton" size="medium" type="secondary" text="Add VF" (click)="openCreateModal('RESOURCE')"></sdc-button>
+ <sdc-button *ngIf="roles[user.role].dashboard.showCreateNew" testId="createCRButton" size="medium" type="secondary" text="Add CR" (click)="createCR()"></sdc-button>
+ <sdc-button *ngIf="roles[user.role].dashboard.showCreateNew" testId="createPNFButton" size="medium" type="secondary" text="Add PNF" (click)="createPNF()"></sdc-button>
+ <sdc-button *ngIf="roles[user.role].dashboard.showCreateNew" testId="createServiceButton" size="medium" type="secondary" text="Add Service" (click)="openCreateModal('SERVICE')"></sdc-button>
+ </div>
+ </div>
+ </div>
+
+ <!-- Import Component -->
+ <div *ngIf="user.role === 'DESIGNER'" class="w-sdc-dashboard-card-new"
+ (mouseleave)="setDisplayActions(false)"
+ (mouseover)="setDisplayActions(true)">
+ <div class="w-sdc-dashboard-card-new-content" data-tests-id="importButtonsArea" >
+ <div class="w-sdc-dashboard-card-import-content-plus" [hidden]="displayActions"></div>
+ <div class="sdc-dashboard-import-element-container" [hidden]="!displayActions">
+ <sdc-button-file-opener
+ *ngIf="roles[user.role].dashboard.showCreateNew"
+ size="medium"
+ type="secondary"
+ text="Import VFC"
+ testId="importVFCbutton"
+ [extensions]="sdcConfig.toscaFileExtension"
+ (fileUpload)="onImportVfc($event)"
+ [convertToBase64]="true"
+ ></sdc-button-file-opener>
+ <sdc-button *ngIf="roles[user.role].dashboard.showCreateNew" data-tests-id="importButtonsVSP" size="medium" type="secondary" text="Import VSP" (click)="notificationIconCallback()"></sdc-button>
+ <sdc-button-file-opener
+ *ngIf="roles[user.role].dashboard.showCreateNew"
+ size="medium"
+ type="secondary"
+ text="Import DCAE"
+ testId="importDCAE"
+ [extensions]="sdcConfig.csarFileExtension"
+ (fileUpload)="onImportVf($event)"
+ [convertToBase64]="true"
+ ></sdc-button-file-opener>
+ </div>
+ </div>
+ </div>
+
+ <!-- Tile new -->
+ <ui-tile *ngFor="let item of homeFilteredSlicedItems"
+ [component]="item" (onTileClick)="goToComponent(item)"></ui-tile>
+ <!-- Tile new -->
+
+ </div>
+
+ </div>
+
+ <div class="w-sdc-left-sidebar">
+ <div class="i-sdc-left-sidebar-item "
+ *ngFor="let folder of folders.getFolders()"
+ [ngClass]="{'category-title': folder.isGroup(), 'selectedLink': folder.isSelected()}">
+
+ <span *ngIf="folder.isGroup()" class="title-text">{{folder.text}}</span>
+ <sdc-checkbox *ngIf="!folder.isGroup() && !folder.dist"
+ [label]="folder.text"
+ [attr.data-tests-id]="'filter-' + folder.state"
+ [checked]="homeFilter.selectedStatuses.indexOf(folder.state) !== -1"
+ (checkedChange)="changeCheckboxesFilter(homeFilter.selectedStatuses, folder.state, $event)"></sdc-checkbox>
+
+ <sdc-checkbox *ngIf="!folder.isGroup() && folder.dist"
+ [label]="folder.text"
+ [checked]="homeFilter.distributed.indexOf(folder.dist) !== -1"
+ (checkedChange)="changeCheckboxesFilter(homeFilter.distributed, folder.dist, $event)"></sdc-checkbox>
+ <span class="i-sdc-left-sidebar-item-state-count" [attr.data-tests-id]="'count-' + folder.state">{{entitiesCount(folder)}}</span>
+ </div>
+ </div>
+
+ </div>
+
+ <top-nav [topLvlSelectedIndex]="0" [version]="version" [searchTerm]="homeFilter.search.filterTerm" (searchTermChange)="changeFilterTerm($event)" [notificationIconCallback]="notificationIconCallback"></top-nav>
+
+</div>
diff --git a/catalog-ui/src/app/ng2/pages/home/home.component.less b/catalog-ui/src/app/ng2/pages/home/home.component.less
new file mode 100644
index 0000000000..c5b73748ba
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/home/home.component.less
@@ -0,0 +1,126 @@
+@import '../../../../assets/styles/mixins_old';
+@import '../../../../assets/styles/sprite';
+.w-sdc-left-sidebar-nav {
+ margin-top: 46px;
+}
+
+.w-sdc-main-right-container {
+ height: 100%;
+ overflow-y: scroll;
+}
+
+.w-sdc-main-right-container-element {
+ float: left;
+ height: 217px;
+ width: 217px;
+ margin: 10px;
+ position: relative;
+}
+
+.w-sdc-main-right-container-element-details-container {
+ position: absolute;
+ top: 165px;
+ left: 50px;
+}
+
+.w-sdc-main-right-container-element-name {
+ font-weight: bold;
+}
+
+.i-sdc-left-sidebar-item{
+ display: flex;
+ &.category-title .title-text, sdc-checkbox{
+ flex-grow: 1;
+ }
+ &:not(.category-title).i-sdc-left-sidebar-item-state-count {
+ line-height: 14px;
+ }
+}
+
+
+//////////////////////////////Cards////////////////////
+.w-sdc-dashboard-card-new {
+ border: 2px dashed @color_m;
+ .border-radius(2px);
+ cursor: pointer;
+ display: inline-block;
+ height: 198px;
+ margin: 11px;
+ position: relative;
+ vertical-align: middle;
+ width: 202px;
+}
+
+.w-sdc-dashboard-card-new-content {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+ height: 100%;
+}
+
+.w-sdc-dashboard-card-new-content-plus {
+ .sprite-new;
+ .add-icon;
+ position: relative;
+ margin-bottom: 20px;
+
+ &:after {
+ .n_14_m;
+ content: 'ADD';
+ position: absolute;
+ top: 25px;
+ left: -3px;
+ vertical-align: -50%;
+ }
+}
+
+.w-sdc-dashboard-card-import-content-plus {
+ .sprite-new;
+ .import-icon;
+ position: relative;
+ margin-bottom: 20px;
+
+ &:after {
+ .n_14_m;
+ content: 'IMPORT';
+ position: absolute;
+ top: 25px;
+ left: -16px;
+ vertical-align: -50%;
+ }
+}
+
+.sdc-dashboard-create-element-container,
+.sdc-dashboard-import-element-container {
+
+ width: 140px;
+
+ sdc-button,
+ sdc-button-file-opener {
+ padding-bottom: 5px;
+ &:last-child{
+ padding-bottom: 0;
+ }
+ }
+
+ .import-file{
+ position: relative;
+ file-opener{
+ position: absolute;
+ top: 0;
+ /deep/ input[type="file"] {
+ .hand;
+ filter: alpha(opacity=0);
+ opacity: 0;
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 140px;
+ height: 36px;
+ }
+ }
+ }
+}
+
+
diff --git a/catalog-ui/src/app/ng2/pages/home/home.component.spec.ts b/catalog-ui/src/app/ng2/pages/home/home.component.spec.ts
new file mode 100644
index 0000000000..df854024fa
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/home/home.component.spec.ts
@@ -0,0 +1,270 @@
+
+import { SdcConfigToken, ISdcConfig } from "../../config/sdc-config.config";
+import { SdcMenuToken, IAppMenu } from "../../config/sdc-menu.config";
+
+
+import { async, ComponentFixture, TestBed } from "@angular/core/testing";
+import { HomeComponent } from "./home.component";
+import {ConfigureFn, configureTests} from "../../../../jest/test-config.helper";
+import {NO_ERRORS_SCHEMA} from "@angular/core";
+import { TranslateService } from "../../shared/translator/translate.service";
+import { HomeService, CacheService, AuthenticationService, ImportVSPService } from '../../../../app/services-ng2';
+import { ModalsHandler } from "../../../../app/utils";
+import { SdcUiServices } from "onap-ui-angular";
+import {ComponentType, ResourceType} from "../../../utils/constants";
+import { FoldersMenu, FoldersItemsMenu, FoldersItemsMenuGroup } from './folders';
+import { HomeFilter } from "../../../../app/models/home-filter";
+import {Component} from "../../../models/components/component";
+
+
+
+
+describe('home component', () => {
+
+ // const mockedEvent = <MouseEvent>{ target: {} }
+ let fixture: ComponentFixture<HomeComponent>;
+ // let eventServiceMock: Partial<EventListenerService>;
+
+ let importVspService: Partial<ImportVSPService>;
+ let mockStateService;
+ let modalServiceMock :Partial<SdcUiServices.ModalService>;
+ let translateServiceMock : Partial<TranslateService>;
+ let foldersItemsMenuMock;
+ let homeFilterMock :Partial<HomeFilter>;
+ let foldersMock;
+ let loaderServiceMock;
+
+
+ beforeEach(
+ async(() => {
+ modalServiceMock = {
+ openWarningModal: jest.fn()
+ }
+
+ mockStateService = {
+ // go: jest.fn().mockReturnValue( new Promise.resolve((resolve, reject )=> resolve()))
+ go: jest.fn()
+ }
+
+ translateServiceMock = {
+ translate: jest.fn()
+ }
+
+ homeFilterMock = {
+ search: jest.fn,
+ toUrlParam: jest.fn()
+ }
+
+ foldersMock = {
+ setSelected: jest.fn()
+ }
+
+ loaderServiceMock = {
+ activate: jest.fn(),
+ deactivate: jest.fn()
+ }
+
+ const configure: ConfigureFn = testBed => {
+ testBed.configureTestingModule({
+ declarations: [HomeComponent],
+ imports: [],
+ schemas: [NO_ERRORS_SCHEMA],
+ providers: [
+ {provide: SdcConfigToken, useValue: {"csarFileExtension":"csar", "toscaFileExtension":"yaml,yml"}},
+ {provide: SdcMenuToken, useValue: {}},
+ {provide: "$state", useValue: mockStateService},
+ {provide: HomeService, useValue: {}},
+ {provide: AuthenticationService, useValue: {}},
+ {provide: CacheService, useValue: {}},
+ {provide: TranslateService, useValue: translateServiceMock},
+ {provide: ModalsHandler, useValue: {}},
+ {provide: SdcUiServices.ModalService, useValue: modalServiceMock},
+ {provide: SdcUiServices.LoaderService, useValue: loaderServiceMock},
+ {provide: ImportVSPService, useValue: {}}
+ ],
+ });
+ };
+
+ configureTests(configure).then(testBed => {
+ fixture = testBed.createComponent(HomeComponent);
+ });
+ })
+ );
+
+
+ it('should match current snapshot', () => {
+ expect(fixture).toMatchSnapshot();
+ });
+
+ it('should call on home component openCreateModal with null imported file', () => {
+ const component = TestBed.createComponent(HomeComponent);
+ let componentType:string = 'test';
+ let importedFile:any = null;
+ component.componentInstance.openCreateModal(componentType, importedFile);
+ expect(mockStateService.go).toBeCalledWith('workspace.general', {type: componentType.toLowerCase()});
+ });
+
+
+ it('should call on home component openCreateModal with imported file', () => {
+ const component = TestBed.createComponent(HomeComponent);
+ component.componentInstance.initEntities = jest.fn();
+ let componentType:string = 'test';
+ let importedFile:any = 'importedFile';
+ component.componentInstance.openCreateModal(componentType, importedFile);
+ expect(component.componentInstance.initEntities).toBeCalledWith(true);
+ });
+
+
+ it ('should call on home component onImportVf without file without extension', () => {
+ const component = TestBed.createComponent(HomeComponent);
+ let file:any = {filename : 'test'};
+ let expectedTitle:string = translateServiceMock.translate("NEW_SERVICE_RESOURCE_ERROR_VALID_CSAR_EXTENSIONS_TITLE");
+ let expectedMessage:string = translateServiceMock.translate("NEW_SERVICE_RESOURCE_ERROR_VALID_CSAR_EXTENSIONS", {"csarFileExtension":"csar"});
+ component.componentInstance.onImportVf(file);
+ expect(modalServiceMock.openWarningModal).toBeCalledWith(expectedTitle, expectedMessage , 'error-invalid-csar-ext');
+ });
+
+
+ it ('should call on home component onImportVf with file without extension' , () => {
+ const component = TestBed.createComponent(HomeComponent);
+ let file:any = {filename : 'test.csar'};
+ component.componentInstance.onImportVf(file);
+ expect(mockStateService.go).toBeCalledWith('workspace.general', {
+ type: ComponentType.RESOURCE.toLowerCase(),
+ importedFile: file,
+ resourceType: ResourceType.VF
+ });
+ });
+
+
+ it ('should call on home component onImportVfc without file without extension', () => {
+ const component = TestBed.createComponent(HomeComponent);
+ let file:any = {filename : 'test'};
+ let expectedTitle:string = translateServiceMock.translate("NEW_SERVICE_RESOURCE_ERROR_VALID_TOSCA_EXTENSIONS_TITLE");
+ let expectedMessage:string = translateServiceMock.translate("NEW_SERVICE_RESOURCE_ERROR_VALID_TOSCA_EXTENSIONS", {"toscaFileExtension":"yaml,yml"});
+ component.componentInstance.onImportVfc(file);
+ expect(modalServiceMock.openWarningModal).toBeCalledWith(expectedTitle, expectedMessage , 'error-invalid-tosca-ext');
+ });
+
+ it ('should call on home component onImportVfc with file without extension' , () => {
+ const component = TestBed.createComponent(HomeComponent);
+ let file:any = {filename : 'test.yml'};
+ component.componentInstance.onImportVfc(file);
+ expect(mockStateService.go).toBeCalledWith('workspace.general', {
+ type: ComponentType.RESOURCE.toLowerCase(),
+ importedFile: file,
+ resourceType: ResourceType.VFC
+ });
+ });
+
+ it ('should call on home component createPNF' , () => {
+ const component = TestBed.createComponent(HomeComponent);
+ component.componentInstance.createPNF();
+ expect(mockStateService.go).toBeCalledWith('workspace.general', {
+ type: ComponentType.RESOURCE.toLowerCase(),
+ resourceType: ResourceType.PNF
+ });
+ });
+
+ it ('should call on home component createCR' , () => {
+ const component = TestBed.createComponent(HomeComponent);
+ component.componentInstance.createCR();
+ expect(mockStateService.go).toBeCalledWith('workspace.general', {
+ type: ComponentType.RESOURCE.toLowerCase(),
+ resourceType: ResourceType.CR
+ });
+ });
+
+
+ it ('should call on home component updateFilter' , () => {
+ const component = TestBed.createComponent(HomeComponent);
+ component.componentInstance.homeFilter = homeFilterMock;
+ component.componentInstance.filterHomeItems = jest.fn();
+ component.componentInstance.updateFilter();
+
+ expect(mockStateService.go).toBeCalledWith('.', homeFilterMock.toUrlParam(), {location: 'replace', notify: false});
+ // expect(spy).toHaveBeenCalledTimes(1);
+
+ // let spy = spyOn(homeFilterMock, 'toUrlParam').and.returnValue({
+ // 'filter.term': '',
+ // 'filter.distributed': '',
+ // 'filter.status':''
+ // });
+ });
+
+ // it ('should call on home component setSelectedFolder' , () => {
+ // const component = TestBed.createComponent(HomeComponent);
+ // let folderItem:Partial<FoldersItemsMenu> = { text:'someThing'};
+ // let folderItem1:number;
+ // component.componentInstance.folders = foldersMock;
+ // expect(foldersMock.setSelected).toBeCalledWith(folderItem);
+ // });
+
+ // it ('should call on home component goToComponent' , () => {
+ // const component = TestBed.createComponent(HomeComponent);
+ // let componentParam:Partial<Component> = { uuid:'someThing', uniqueId:'uniqueID', componentType:'componentType'};
+ // component.componentInstance.goToComponent(componentParam);
+ // expect(loaderServiceMock.activate).toHaveBeenCalled();
+ // // expect(mockStateService.go).toBeCalledWith('workspace.general', {id: componentParam.uniqueId, type: componentParam.componentType.toLowerCase()}).then(function(){
+ // // loaderServiceMock.deactivate();
+ // // });
+ // expect(mockStateService.go).toBeCalled();
+ // });
+
+ // it ('should call on home component raiseNumberOfElementToDisplay so numberOfItemToDisplay will be 0' , () => {
+ // const component = TestBed.createComponent(HomeComponent);
+ // component.componentInstance.raiseNumberOfElementToDisplay();
+ // expect(component.componentInstance.numberOfItemToDisplay).toEqual(0);
+ // });
+ //
+ // it ('should call on home component raiseNumberOfElementToDisplay with min(2,70) so numberOfItemToDisplay will be 2' , () => {
+ // const component = TestBed.createComponent(HomeComponent);
+ // component.componentInstance.homeItems = ['item1', 'item2'];
+ // component.componentInstance.numberOfItemToDisplay = 70;
+ // component.componentInstance.raiseNumberOfElementToDisplay(true);
+ // expect(component.componentInstance.numberOfItemToDisplay).toEqual(2);
+ // });
+ //
+ // it ('should call on home component raiseNumberOfElementToDisplay with min(3,35) so numberOfItemToDisplay will be 2 after fullPagesAmount is calculated' , () => {
+ // const component = TestBed.createComponent(HomeComponent);
+ // component.componentInstance.homeItems = ['item1', 'item2', 'item3'];
+ // component.componentInstance.numberOfItemToDisplay = 70;
+ // component.componentInstance.numberOfItemToDisplay = 0;
+ // component.componentInstance.raiseNumberOfElementToDisplay(false);
+ // expect(component.componentInstance.numberOfItemToDisplay).toEqual(3);
+ // });
+ //
+ //
+ // it ('should call on home component changeFilterTerm' , () => {
+ // const component = TestBed.createComponent(HomeComponent);
+ // component.componentInstance.changeFilterTerm("testStr");
+ // // expect ( "testStr" ).toEqual(homeFilterMock.search.)
+ // });
+
+
+
+
+
+
+ // it ('should call on home component entitiesCount' , () => {
+ // const component = TestBed.createComponent(HomeComponent);
+ // component.componentInstance.entitiesCount("aaa");
+ // expect(mockStateService.go).toBeCalledWith('workspace.general', {
+ // type: ComponentType.RESOURCE.toLowerCase(),
+ // resourceType: ResourceType.CR
+ // });
+ // });
+
+
+ // it('should call on home component notificationIconCallback', () => {
+ // const component = TestBed.createComponent(HomeComponent);
+ // component.componentInstance.initEntities = jest.fn();
+ // component.componentInstance.notificationIconCallback();
+ // expect(mockStateService.go).toBeCalledWith('workspace.general', {});
+ // });
+
+
+
+
+
+}); \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/home/home.component.ts b/catalog-ui/src/app/ng2/pages/home/home.component.ts
new file mode 100644
index 0000000000..1b69eba929
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/home/home.component.ts
@@ -0,0 +1,358 @@
+/*-
+ * ============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=========================================================
+ */
+'use strict';
+import { Component as NgComponent, Inject, OnInit } from '@angular/core';
+import { Component, IConfigRoles, IUserProperties, Resource } from 'app/models';
+import { HomeFilter } from 'app/models/home-filter';
+import { AuthenticationService, CacheService, HomeService } from 'app/services-ng2';
+import { ModalsHandler } from 'app/utils';
+import { SdcUiServices } from 'onap-ui-angular';
+import { CHANGE_COMPONENT_CSAR_VERSION_FLAG, ComponentType, ResourceType } from '../../../utils/constants';
+import { ImportVSPService } from '../../components/modals/onboarding-modal/import-vsp.service';
+import { ISdcConfig, SdcConfigToken } from '../../config/sdc-config.config';
+import { IAppMenu, SdcMenuToken } from '../../config/sdc-menu.config';
+import { EntityFilterPipe } from '../../pipes/entity-filter.pipe';
+import { TranslateService } from '../../shared/translator/translate.service';
+import { FoldersItemsMenu, FoldersItemsMenuGroup, FoldersMenu } from './folders';
+
+@NgComponent({
+ selector: 'home-page',
+ templateUrl: './home.component.html',
+ styleUrls: ['./home.component.less']
+})
+export class HomeComponent implements OnInit {
+ public numberOfItemToDisplay: number;
+ public homeItems: Component[];
+ public homeFilteredItems: Component[];
+ public homeFilteredSlicedItems: Component[];
+ public folders: FoldersMenu;
+ public roles: IConfigRoles;
+ public user: IUserProperties;
+ public showTutorial: boolean;
+ public isFirstTime: boolean;
+ public version: string;
+ public homeFilter: HomeFilter;
+ public vfcmtType: string;
+ public displayActions: boolean;
+
+ constructor(
+ @Inject(SdcConfigToken) private sdcConfig: ISdcConfig,
+ @Inject(SdcMenuToken) public sdcMenu: IAppMenu,
+ @Inject('$state') private $state: ng.ui.IStateService,
+ private homeService: HomeService,
+ private authService: AuthenticationService,
+ private cacheService: CacheService,
+ private translateService: TranslateService,
+ private modalsHandler: ModalsHandler,
+ private modalService: SdcUiServices.ModalService,
+ private loaderService: SdcUiServices.LoaderService,
+ private importVSPService: ImportVSPService
+ ) {}
+
+ ngOnInit(): void {
+ this.initHomeComponentVars();
+ this.initFolders();
+ this.initEntities();
+
+ if (this.$state.params) {
+ if (this.$state.params.folder) {
+ const folderName = this.$state.params.folder.replaceAll('_', ' ');
+
+ const selectedFolder = this.folders.getFolders().find((tmpFolder: FoldersItemsMenu) => tmpFolder.text === folderName);
+ if (selectedFolder) {
+ this.setSelectedFolder(selectedFolder);
+ }
+ // Show the tutorial if needed when the dashboard page is opened.<script src="bower_components/angular-filter/dist/angular-filter.min.js"></script>
+ // This is called from the welcome page.
+ } else if (this.$state.params.show === 'tutorial') {
+ this.showTutorial = true;
+ this.isFirstTime = true;
+ }
+ }
+ }
+
+ // Open onboarding modal
+ public notificationIconCallback(): void {
+ this.importVSPService.openOnboardingModal().subscribe((result) => {
+ if (!result.previousComponent || result.previousComponent.csarVersion !== result.componentCsar.csarVersion) {
+ this.cacheService.set(CHANGE_COMPONENT_CSAR_VERSION_FLAG, result.componentCsar.csarVersion);
+ }
+ this.$state.go('workspace.general', {
+ id: result.previousComponent && result.previousComponent.uniqueId,
+ componentCsar: result.componentCsar,
+ type: result.type
+ });
+ });
+ }
+
+ public onImportVf(file: any): void {
+ if (file && file.filename) {
+ // Check that the file has valid extension.
+ const fileExtension: string = file.filename.split('.').pop();
+ if (this.sdcConfig.csarFileExtension.indexOf(fileExtension.toLowerCase()) !== -1) {
+ this.$state.go('workspace.general', {
+ type: ComponentType.RESOURCE.toLowerCase(),
+ importedFile: file,
+ resourceType: ResourceType.VF
+ });
+ } else {
+ const title: string = this.translateService.translate('NEW_SERVICE_RESOURCE_ERROR_VALID_CSAR_EXTENSIONS_TITLE');
+ const message: string = this.translateService.translate('NEW_SERVICE_RESOURCE_ERROR_VALID_CSAR_EXTENSIONS', {extensions: this.sdcConfig.csarFileExtension});
+ this.modalService.openWarningModal(title, message, 'error-invalid-csar-ext');
+ }
+ }
+ }
+
+ public onImportVfc(file: any): void {
+ if (file && file.filename) {
+ // Check that the file has valid extension.
+ const fileExtension: string = file.filename.split('.').pop();
+ if (this.sdcConfig.toscaFileExtension.indexOf(fileExtension.toLowerCase()) !== -1) {
+ this.$state.go('workspace.general', {
+ type: ComponentType.RESOURCE.toLowerCase(),
+ importedFile: file,
+ resourceType: ResourceType.VFC
+ });
+ } else {
+ const title: string = this.translateService.translate('NEW_SERVICE_RESOURCE_ERROR_VALID_TOSCA_EXTENSIONS_TITLE');
+ const message: string = this.translateService.translate('NEW_SERVICE_RESOURCE_ERROR_VALID_TOSCA_EXTENSIONS', {extensions: this.sdcConfig.toscaFileExtension});
+ this.modalService.openWarningModal(title, message, 'error-invalid-tosca-ext');
+ }
+ }
+ }
+
+ public openCreateModal(componentType: string, importedFile: any): void {
+ if (importedFile) {
+ this.initEntities(true); // Return from import
+ } else {
+ this.$state.go('workspace.general', {type: componentType.toLowerCase()});
+ }
+ }
+
+ public createPNF(): void {
+ this.$state.go('workspace.general', {
+ type: ComponentType.RESOURCE.toLowerCase(),
+ resourceType: ResourceType.PNF
+ });
+ }
+
+ public createCR(): void {
+ this.$state.go('workspace.general', {
+ type: ComponentType.RESOURCE.toLowerCase(),
+ resourceType: ResourceType.CR
+ });
+ }
+
+ public entitiesCount(folderItem: FoldersItemsMenu): any {
+ let total: number = 0;
+ if (folderItem.isGroup()) {
+ this.folders.getFolders().forEach((tmpFolder: FoldersItemsMenu) => {
+ if (tmpFolder.group && tmpFolder.group === (folderItem as FoldersItemsMenuGroup).groupname) {
+ total = total + this._getTotalCounts(tmpFolder);
+ }
+ });
+ } else {
+ total = total + this._getTotalCounts(folderItem);
+ }
+ return total;
+ }
+
+ public updateFilter = () => {
+ this.$state.go('.', this.homeFilter.toUrlParam(), {location: 'replace', notify: false});
+ this.filterHomeItems();
+ }
+
+ public getCurrentFolderDistributed(): any[] {
+ const states = [];
+ if (this.folders) {
+ const folderItem: FoldersItemsMenu = this.folders.getCurrentFolder();
+ if (folderItem.isGroup()) {
+ this.folders.getFolders().forEach((tmpFolder: FoldersItemsMenu) => {
+ if (tmpFolder.group && tmpFolder.group === (folderItem as FoldersItemsMenuGroup).groupname) {
+ this._setStates(tmpFolder, states);
+ }
+ });
+ } else {
+ this._setStates(folderItem, states);
+ }
+ }
+ return states;
+ }
+
+ public setSelectedFolder(folderItem: FoldersItemsMenu): void {
+ this.folders.setSelected(folderItem);
+ }
+
+ public goToComponent(component: Component): void {
+ const loaderService = this.loaderService;
+ loaderService.activate();
+ this.$state.go('workspace.general', {id: component.uniqueId, type: component.componentType.toLowerCase()}).then(() => {
+ loaderService.deactivate();
+ });
+ }
+
+ public raiseNumberOfElementToDisplay(recalculate: boolean = false) {
+ const scrollPageAmount = 35;
+ if (!this.homeItems) {
+ this.numberOfItemToDisplay = 0;
+ } else if (this.homeItems.length > this.numberOfItemToDisplay || recalculate) {
+ let fullPagesAmount = Math.ceil(this.numberOfItemToDisplay / scrollPageAmount) * scrollPageAmount;
+ if (!recalculate || fullPagesAmount === 0) { // TODO trigger infiniteScroll to check bottom and fire onBottomHit by itself (sdc-ui)
+ fullPagesAmount += scrollPageAmount;
+ }
+ this.numberOfItemToDisplay = Math.min(this.homeItems.length, fullPagesAmount);
+ this.homeFilteredSlicedItems = this.homeFilteredItems.slice(0, this.numberOfItemToDisplay);
+ }
+ }
+
+ public changeCheckboxesFilter(checkboxesFilterArray: string[], checkboxValue: string, checked?: boolean) {
+ const checkboxIdx = checkboxesFilterArray.indexOf(checkboxValue);
+
+ checked = (checked !== undefined) ? checked : checkboxIdx === -1;
+ if (checked && checkboxIdx === -1) {
+ checkboxesFilterArray.push(checkboxValue);
+ } else if (!checked && checkboxIdx !== -1) {
+ checkboxesFilterArray.splice(checkboxIdx, 1);
+ }
+ this.updateFilter();
+ }
+
+ public changeFilterTerm(filterTerm: string): void {
+ this.homeFilter.search = { filterTerm };
+ this.updateFilter();
+ }
+
+ public setDisplayActions(display?: boolean) {
+ this.displayActions = display !== undefined ? display : !this.displayActions;
+ }
+
+ private _getTotalCounts(tmpFolder): number {
+ let total: number = 0;
+ if (tmpFolder.dist !== undefined) {
+ const distributions = tmpFolder.dist.split(',');
+ distributions.forEach((item: any) => {
+ total = total + this.getEntitiesByStateDist(tmpFolder.state, item).length;
+ });
+ } else {
+ total = total + this.getEntitiesByStateDist(tmpFolder.state, tmpFolder.dist).length;
+ }
+ return total;
+ }
+
+ private _setStates(tmpFolder, states) {
+ if (tmpFolder.states !== undefined) {
+ tmpFolder.states.forEach((item: any) => {
+ states.push({state: item.state, dist: item.dist});
+ });
+ } else {
+ states.push({state: tmpFolder.state, dist: tmpFolder.dist});
+ }
+ }
+
+ private initEntities(reload?: boolean) {
+ if (reload || this.componentShouldReload()) {
+ this.loaderService.activate();
+ this.homeService.getAllComponents(true).subscribe(
+ (components: Component[]) => {
+ this.cacheService.set('breadcrumbsComponentsState', this.$state.current.name); // dashboard
+ this.cacheService.set('breadcrumbsComponents', components);
+ this.homeItems = components;
+ this.loaderService.deactivate();
+ this.filterHomeItems();
+ }, (error) => { this.loaderService.deactivate(); });
+ } else {
+ this.homeItems = this.cacheService.get('breadcrumbsComponents');
+ this.filterHomeItems();
+ }
+ }
+
+ private isDefaultFilter = (): boolean => {
+ const defaultFilter = new HomeFilter();
+ return angular.equals(defaultFilter, this.homeFilter);
+ }
+
+ private componentShouldReload = (): boolean => {
+ const breadcrumbsValid: boolean = (this.$state.current.name === this.cacheService.get('breadcrumbsComponentsState') && this.cacheService.contains('breadcrumbsComponents'));
+ return !breadcrumbsValid || this.isDefaultFilter();
+ }
+
+ private getEntitiesByStateDist(state: string, dist: string): Component[] {
+ let gObj: Component[];
+ if (this.homeItems && (state || dist)) {
+ gObj = this.homeItems.filter((obj: Component) => {
+ if (dist !== undefined && obj.distributionStatus === dist && obj.lifecycleState === state) {
+ return true;
+ } else if (dist === undefined && (obj.lifecycleState === state || obj.distributionStatus === state)) {
+ return true;
+ }
+ return false;
+ });
+ } else {
+ gObj = [];
+ }
+ return gObj;
+ }
+
+ private filterHomeItems() {
+ this.homeFilteredItems = this.makeFilteredItems(this.homeItems, this.homeFilter);
+ this.raiseNumberOfElementToDisplay(true);
+ this.homeFilteredSlicedItems = this.homeFilteredItems.slice(0, this.numberOfItemToDisplay);
+ }
+
+ private makeFilteredItems(homeItems: Component[], filter: HomeFilter) {
+ let filteredComponents: Component[] = homeItems;
+
+ // filter: exclude all resources of type 'vfcmtType':
+ filteredComponents = filteredComponents.filter((c) =>
+ !c.isResource() || (c as Resource).resourceType.indexOf(this.vfcmtType) === -1);
+
+ // common entity filter
+ // --------------------------------------------------------------------------
+ filteredComponents = EntityFilterPipe.transform(filteredComponents, filter);
+
+ return filteredComponents;
+ }
+
+ private initFolders = (): void => {
+ // Note: Do not use SdcUi.ChecklistComponent for folders checkboxes, since from the data structure
+ // it is not determined that all checkboxes under the same group are managed by the same selectedValues array.
+ if (this.user) {
+ this.folders = new FoldersMenu(this.roles[this.user.role].folder);
+ }
+ }
+
+ private initHomeComponentVars(): void {
+ this.version = this.cacheService.get('version');
+ this.numberOfItemToDisplay = 0;
+ this.displayActions = false;
+ this.user = this.authService.getLoggedinUser();
+ this.roles = this.sdcMenu.roles;
+ this.showTutorial = false;
+ this.isFirstTime = false;
+ this.vfcmtType = ResourceType.VFCMT;
+
+ // Checkboxes filter init
+ this.homeFilter = new HomeFilter(this.$state.params);
+
+ // bind callbacks that are transferred as inputs
+ this.notificationIconCallback = this.notificationIconCallback.bind(this);
+ }
+
+}
diff --git a/catalog-ui/src/app/ng2/pages/home/home.module.ts b/catalog-ui/src/app/ng2/pages/home/home.module.ts
new file mode 100644
index 0000000000..3e7c0cd312
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/home/home.module.ts
@@ -0,0 +1,31 @@
+import { NgModule } from "@angular/core";
+import { CommonModule } from "@angular/common";
+import { HomeComponent } from "./home.component";
+import { LayoutModule } from "../../components/layout/layout.module";
+import { UiElementsModule } from "../../components/ui/ui-elements.module";
+import { GlobalPipesModule } from "../../pipes/global-pipes.module";
+import { TranslateModule } from "../../shared/translator/translate.module";
+import { SdcUiComponentsModule } from "onap-ui-angular";
+
+@NgModule({
+ declarations: [
+ HomeComponent
+ ],
+ imports: [
+ CommonModule,
+ SdcUiComponentsModule,
+ LayoutModule,
+ UiElementsModule,
+ GlobalPipesModule,
+ TranslateModule
+ ],
+ exports: [
+ HomeComponent
+ ],
+ entryComponents: [
+ HomeComponent
+ ],
+ providers: []
+})
+export class HomeModule {
+}