diff options
Diffstat (limited to 'catalog-ui/src/app/view-models/modals/onboarding-modal')
3 files changed, 541 insertions, 0 deletions
diff --git a/catalog-ui/src/app/view-models/modals/onboarding-modal/onboarding-modal-view-model.ts b/catalog-ui/src/app/view-models/modals/onboarding-modal/onboarding-modal-view-model.ts new file mode 100644 index 0000000000..8e7e79c576 --- /dev/null +++ b/catalog-ui/src/app/view-models/modals/onboarding-modal/onboarding-modal-view-model.ts @@ -0,0 +1,249 @@ +'use strict'; +import {ComponentType, CHANGE_COMPONENT_CSAR_VERSION_FLAG, SEVERITY, FileUtils, ModalsHandler, ComponentFactory} from "app/utils"; +import {OnboardingService, CacheService} from "app/services"; +import {Component, IComponent, IUser, IAppConfigurtaion, Resource} from "app/models"; +import {IServerMessageModalModel} from "../message-modal/message-server-modal/server-message-modal-view-model"; +import {Dictionary} from "app/utils"; +import * as _ from 'underscore'; + +interface IOnboardingModalViewModelScope { + modalOnboarding:ng.ui.bootstrap.IModalServiceInstance; + componentsList:Array<IComponent>; + tableHeadersList:Array<any>; + selectedComponent:Component; + componentFromServer:Component; + reverse:boolean; + sortBy:string; + searchBind:string; + okButtonText:string; + isCsarComponentExists:boolean; + user:IUser; + isLoading:boolean; + + //this is for UI paging + numberOfItemsToDisplay:number; + allItemsDisplayed:boolean; + + doSelectComponent(component:Component):void; + doUpdateCsar():void; + doImportCsar():void; + sort(sortBy:string):void; + downloadCsar(packageId:string):void; + increaseNumItemsToDisplay():void; +} + +export class OnboardingModalViewModel { + + static '$inject' = [ + '$scope', + '$filter', + '$state', + 'sdcConfig', + '$uibModalInstance', + 'Sdc.Services.OnboardingService', + 'okButtonText', + 'currentCsarUUID', + 'Sdc.Services.CacheService', + 'FileUtils', + 'ComponentFactory', + 'ModalsHandler' + ]; + + constructor(private $scope:IOnboardingModalViewModelScope, + private $filter:ng.IFilterService, + private $state:any, + private sdcConfig:IAppConfigurtaion, + private $uibModalInstance:ng.ui.bootstrap.IModalServiceInstance, + private onBoardingService:OnboardingService, + private okButtonText:string, + private currentCsarUUID:string, + private cacheService:CacheService, + private fileUtils:FileUtils, + private componentFactory:ComponentFactory, + private modalsHandler:ModalsHandler) { + + this.init(); + } + + /** + * Called from controller constructor, this will call onboarding service to get list + * of "mini" components (empty components created from CSAR). + * The list is inserted to componentsList on $scope. + * And then call initScope method. + */ + private init = ():void => { + this.initOnboardingComponentsList(); + }; + + private initScope = ():void => { + + this.initSortedTableScope(); + this.initModalScope(); + this.$scope.sortBy = "name"; // Default sort by + this.$scope.user = this.cacheService.get('user'); + this.$scope.okButtonText = this.okButtonText; + this.$scope.numberOfItemsToDisplay = 0; + this.$scope.allItemsDisplayed = false; + + // Dismiss the modal and pass the "mini" component to workspace general page + this.$scope.doImportCsar = ():void => { + this.$uibModalInstance.dismiss(); + this.$state.go('workspace.general', { + type: ComponentType.RESOURCE.toLowerCase(), + componentCsar: this.$scope.selectedComponent + }); + }; + + this.$scope.doUpdateCsar = ():void => { + // In case user select on update the checkin and submit for testing buttons (in general page) should be disabled. + // to do that we need to pass to workspace.general state parameter to know to disable the buttons. + this.$uibModalInstance.close(); + // Change the component version to the CSAR version we want to update. + /*(<Resource>this.$scope.componentFromServer).csarVersion = (<Resource>this.$scope.selectedComponent).csarVersion; + let component:Components.Component = this.componentFactory.createComponent(this.$scope.componentFromServer); + this.$state.go('workspace.general', {vspComponent: component, disableButtons: true });*/ + this.cacheService.set(CHANGE_COMPONENT_CSAR_VERSION_FLAG, (<Resource>this.$scope.selectedComponent).csarVersion); + this.$state.go('workspace.general', { + id: this.$scope.componentFromServer.uniqueId, + type: this.$scope.componentFromServer.componentType.toLowerCase(), + disableButtons: true + }); + }; + + this.$scope.downloadCsar = (packageId:string):void => { + this.$scope.isLoading = true; + this.onBoardingService.downloadOnboardingCsar(packageId).then( + (file:any):void => { + this.$scope.isLoading = false; + if (file) { + this.fileUtils.downloadFile(file, packageId + '.csar'); + } + }, ():void => { + this.$scope.isLoading = false; + var data:IServerMessageModalModel = { + title: 'Download error', + message: "Error downloading file", + severity: SEVERITY.ERROR, + messageId: "", + status: "" + }; + this.modalsHandler.openServerMessageModal(data); + } + ); + }; + + this.$scope.increaseNumItemsToDisplay = ():void => { + this.$scope.numberOfItemsToDisplay = this.$scope.numberOfItemsToDisplay + 40; + if (this.$scope.componentsList) { + this.$scope.allItemsDisplayed = this.$scope.numberOfItemsToDisplay >= this.$scope.componentsList.length; + } + }; + + // When the user select a row, set the component as selectedComponent + this.$scope.doSelectComponent = (component:Component):void => { + + if (this.$scope.selectedComponent === component) { + // Collapse the item + this.$scope.selectedComponent = undefined; + return; + } + + this.$scope.isLoading = true; + this.$scope.componentFromServer = undefined; + this.$scope.selectedComponent = component; + + let onSuccess = (componentFromServer:Component):void => { + this.$scope.isLoading = false; + if (componentFromServer) { + this.$scope.componentFromServer = componentFromServer; + this.$scope.isCsarComponentExists = true; + } else { + this.$scope.componentFromServer = component; + this.$scope.isCsarComponentExists = false; + } + }; + + let onError = ():void => { + this.$scope.isLoading = false; + this.$scope.componentFromServer = component; + this.$scope.isCsarComponentExists = false; + }; + + this.onBoardingService.getComponentFromCsarUuid((<Resource>component).csarUUID).then(onSuccess, onError); + }; + + }; + + private initSortedTableScope = ():void => { + this.$scope.tableHeadersList = [ + {title: 'Name', property: 'name'}, + {title: 'Vendor', property: 'vendorName'}, + {title: 'Category', property: 'categories'}, + {title: 'Version', property: 'csarVersion'}, + {title: '#', property: 'importAndUpdate'} + //{title: 'Date', property: 'componentDate'} + ]; + + this.$scope.sort = (sortBy:string):void => { + this.$scope.reverse = (this.$scope.sortBy === sortBy) ? !this.$scope.reverse : false; + this.$scope.sortBy = sortBy; + }; + }; + + private initModalScope = ():void => { + // Enable the modal directive to close + this.$scope.modalOnboarding = this.$uibModalInstance; + }; + + private initOnboardingComponentsList = ():void => { + let onSuccess = (onboardingResponse:Array<IComponent>):void => { + initMaxVersionOfItemsInList(onboardingResponse); + + if (this.currentCsarUUID) { + //this.$scope.componentsList = this.$filter('filter')(this.$scope.componentsList, {csarUUID: this.currentCsarUUID}); + this.$scope.componentsList = this.$filter('filter')(this.$scope.componentsList, + (input):boolean => { + return input.csarUUID === this.currentCsarUUID; + } + ); + } + this.initScope(); + }; + + let onError = ():void => { + console.log("Error getting onboarding list"); + this.initScope(); + }; + + let initMaxVersionOfItemsInList = (onboardingResponse:Array<IComponent>):void => { + // Get only the latest version of each item + this.$scope.componentsList = []; + + // Get all unique items from the list + let uniqueItems:Array<any> = _.uniq(onboardingResponse, false, (item:any):void=>{ + return item.packageId; + }); + + // Loop on all the items with unique packageId + _.each(uniqueItems, (item:any):void=> { + // Find all the items that has same packageId + let ItemsFound:Array<IComponent> = _.filter(onboardingResponse, (inListItem:any):any => { + return inListItem.packageId === item.packageId; + }); + + // Loop on all the items with same packageId and find the max version. + let maxItem:any; + _.each(ItemsFound, (ItemFound:any):void=> { + if (!maxItem) { + maxItem = ItemFound; + } else if (maxItem && parseInt(maxItem.csarVersion) < parseInt(ItemFound.csarVersion)) { + maxItem = ItemFound; + } + }); + this.$scope.componentsList.push(maxItem); + }); + }; + + this.onBoardingService.getOnboardingComponents().then(onSuccess, onError); + }; +} diff --git a/catalog-ui/src/app/view-models/modals/onboarding-modal/onboarding-modal-view.html b/catalog-ui/src/app/view-models/modals/onboarding-modal/onboarding-modal-view.html new file mode 100644 index 0000000000..3657fad017 --- /dev/null +++ b/catalog-ui/src/app/view-models/modals/onboarding-modal/onboarding-modal-view.html @@ -0,0 +1,144 @@ +<sdc-modal modal="modalOnboarding" class="w-sdc-modal-onboarding w-sdc-classic-top-line-modal" buttons="footerButtons" header="Import VF" show-close-button="true"> + <info-tooltip class="general-info-button" info-message-translate="ON_BOARDING_GENERAL_INFO "></info-tooltip> + <div class="title-wrapper"> + <div> + <p class="sub-title">Select one of the software product component below:</p> + </div> + + <div class="top-search"> + <input type="text" + class="search-text" + placeholder="Search" + data-ng-model="searchBind" + data-tests-id="onboarding-search" + ng-model-options="{ debounce: 500 }" /> + <span class="w-sdc-search-icon magnification"></span> + </div> + </div> + + <div class="table-container-flex"> + <div class="table" data-ng-class="{'view-mode': isViewMode()}"> + + <!-- Table headers --> + <div class="head flex-container"> + <div class="table-header head-row hand flex-item" ng-repeat="header in tableHeadersList track by $index" data-ng-click="sort(header.property)" data-tests-id="{{header.title}}">{{header.title}} + <span data-ng-show="sortBy === header.property" class="table-header-sort-arrow" data-ng-class="{'down': reverse, 'up':!reverse}"> </span> + </div> + </div> + + <!-- Table body --> + <div class="body"> + <perfect-scrollbar suppress-scroll-x="true" scroll-y-margin-offset="0" include-padding="true" class="scrollbar-container" id="onboarding-modal-scrollbar-container"> + + <!-- In case the component list is empty --> + <div data-ng-if="!componentsList || componentsList.length===0" class="no-row-text"> + There are no software product component to display + </div> + + <div infinite-scroll-disabled='allItemsDisplayed' infinite-scroll="increaseNumItemsToDisplay()" infinite-scroll-container="'#onboarding-modal-scrollbar-container'"> + + <!-- Loop on components list --> + <div data-ng-repeat-start="component in componentsList | filter: searchBind | orderBy:sortBy:reverse | limitTo:numberOfItemsToDisplay track by $index" + class="flex-container data-row" + data-ng-class="{'selected': component === selectedComponent}" + data-ng-click="doSelectComponent(component);" + data-tests-id="csar-row" + > + + <!-- Name --> + <div class="table-col-general flex-item" sdc-smart-tooltip> + <span class="sprite table-arrow" data-ng-class="{'opened': component === selectedComponent}" data-tests-id="{{component.name}}"></span> + {{component.name}} + </div> + + <!-- Vendor --> + <div class="table-col-general flex-item" data-tests-id="{{component.vendorName}}" sdc-smart-tooltip> + {{component.vendorName}} + </div> + + <!-- Category --> + <div class="table-col-general flex-item" sdc-smart-tooltip> + {{component.categories[0].name}} {{component.categories[0].subcategories[0].name}} + </div> + + <!-- Version --> + <div class="table-col-general flex-item" sdc-smart-tooltip> + {{component.csarVersion}} + </div> + + <!-- Import And Update --> + <div class="table-col-general flex-item" sdc-smart-tooltip></div> + + </div> + + <div data-ng-repeat-end="" data-ng-if="component===selectedComponent" class="item-opened"> + + <div class="item-opened-description"> + <div class="item-opened-description-title">VSP Description:</div> + {{component.description}} + </div> + + <div class="item-opened-metadata1"> + <div data-ng-if="isCsarComponentExists===true"> + <div class="item-opened-metadata-title">VF'S Meta Data:</div> + <div><span class="th">Name:</span> {{componentFromServer.name}}</div> + <div><span class="th">Lifecycle:</span> {{componentFromServer.lifecycleState}}</div> + <div><span class="th">Creator:</span> {{componentFromServer.creatorFullName}}</div> + </div> + </div> + + <div class="item-opened-metadata2"> + <div data-ng-if="isCsarComponentExists===true"> + <div class="item-opened-metadata-title"> </div> + <div><span class="th">UUID:</span> {{componentFromServer.uuid}}</div> + <div><span class="th">Version:</span> {{componentFromServer.version}}</div> + <div><span class="th">Modifier:</span> {{componentFromServer.lastUpdaterFullName}}</div> + <div data-ng-if="componentFromServer.lifecycleState==='NOT_CERTIFIED_CHECKOUT' && componentFromServer.lastUpdaterUserId !== user.userId"> + <span class="note">Designers cannot update a VSP if the VF is checked out by another user.</span> + </div> + <div data-ng-if="componentFromServer.lifecycleState==='READY_FOR_CERTIFICATION'"> + <span class="note">Designers cannot update a VSP if the VF is in Ready for testing state.</span> + </div> + </div> + </div> + + <div class="item-opened-metadata3"> + <info-tooltip class="info-button" info-message-translate="{{isCsarComponentExists?'ON_BOARDING_UPDATE_INFO':'ON_BOARDING_IMPORT_INFO'}}" direction="left"></info-tooltip> + </div> + + <div class="item-opened-icon"> + <span data-ng-if="isCsarComponentExists!==true" + class="sprite-new import-file-btn" + data-ng-click="doImportCsar()" + uib-tooltip="Import VSP" + tooltip-class="uib-custom-tooltip" + tooltip-placement="bottom" + data-tests-id="import-csar"></span> + + <span data-ng-if="isCsarComponentExists===true" + class="sprite-new refresh-file-btn" + uib-tooltip="Update VSP" + tooltip-class="uib-custom-tooltip" + tooltip-placement="bottom" + data-ng-class="{'disabled': (componentFromServer.lifecycleState==='NOT_CERTIFIED_CHECKOUT' && componentFromServer.lastUpdaterUserId!==user.userId) || componentFromServer.lifecycleState==='READY_FOR_CERTIFICATION'}" + data-ng-click="doUpdateCsar()" + data-tests-id="update-csar"></span> + + <span data-ng-click="downloadCsar(component.packageId)" + class="sprite-new download-file-btn hand" + uib-tooltip="Download VSP" + tooltip-class="uib-custom-tooltip" + tooltip-placement="bottom" + data-tests-id="download-csar"></span> + </div> + <loader data-display="isLoading" relative="true" size="small"></loader> + </div> + </div> + + </perfect-scrollbar> + </div><!-- End table body --> + </div><!-- End table --> + </div><!-- End table-container-flex --> + <div class="w-sdc-modal-footer classic"></div> + +</sdc-modal> diff --git a/catalog-ui/src/app/view-models/modals/onboarding-modal/onboarding-modal.less b/catalog-ui/src/app/view-models/modals/onboarding-modal/onboarding-modal.less new file mode 100644 index 0000000000..c745a86888 --- /dev/null +++ b/catalog-ui/src/app/view-models/modals/onboarding-modal/onboarding-modal.less @@ -0,0 +1,148 @@ +.w-sdc-modal-onboarding { + + width: 100%; + display: inline-block; + + .general-info-button{ + position: relative; + top: -40px; + left: 86px; + float: left; + } + + .title-wrapper { + display: flex; + justify-content: space-between; + align-items: flex-end; + + .sub-title { + .m_14_r; + float:left; + } + } + + .w-sdc-classic-btn { + float: right; + margin-bottom: 10px; + } + + .table{ + height: 472px; + margin-bottom: 0; + } + + .table-container-flex { + margin-top: 10px; + + .table { + .body { + .data-row + div.item-opened { + word-wrap: break-word; + display: flex; + justify-content: space-between; + padding: 10px 0; + + .item-opened-description-title, + .item-opened-metadata-title { + .m_14_m; + } + + .item-opened-description, + .item-opened-metadata1, + .item-opened-metadata2, + .item-opened-metadata3 { + .th { .m_14_m; } + flex-basis: 0; + overflow: hidden; + padding: 5px 15px; + } + + .item-opened-description, + .item-opened-metadata3 { + border-right: 1px solid @main_color_o; + } + + .item-opened-metadata2 { + word-break: break-word; + .note { + color: @func_color_q; + } + } + + .item-opened-icon { + flex-basis: 0; + overflow: hidden; + padding: 5px 15px; + align-self: center; + } + + .item-opened-description {flex-grow: 25;} + .item-opened-metadata1 {flex-grow: 25;} + .item-opened-metadata2 {flex-grow: 30;} + .item-opened-metadata3 { + flex-grow: 10; + .info-button{ + float: right; + } + } + .item-opened-icon {flex-grow: 10;} + } + } + } + + .flex-item:nth-child(1) { + flex-grow: 25; + .hand; + span.table-arrow { + margin-right: 7px; + } + } + + .flex-item:nth-child(2) {flex-grow: 25;} + .flex-item:nth-child(3) {flex-grow: 30;} + .flex-item:nth-child(4) {flex-grow: 10; text-align: center; } + .flex-item:nth-child(5) {flex-grow: 10; } + + } + + .download-file-btn { + cursor: pointer; + margin-left: 4px; + } + + .refresh-file-btn, + .import-file-btn { + cursor: pointer; + margin-left: 20px; + } + + .top-search { + float: right; + position: relative; + + input.search-text { + .border-radius(2px); + width: 245px; + height: 32px; + line-height: 32px; + border: 1px solid @main_color_o; + margin: 0; + outline: none; + text-indent: 10px; + + &::-webkit-input-placeholder { font-style: italic; } /* Safari, Chrome and Opera */ + &:-moz-placeholder { font-style: italic; } /* Firefox 18- */ + &::-moz-placeholder { font-style: italic; } /* Firefox 19+ */ + &:-ms-input-placeholder { font-style: italic; } /* IE 10+ */ + &:-ms-input-placeholder { font-style: italic; } /* Edge */ + } + + .magnification { + position: absolute; + top: 10px; + right: 10px; + } + + } + +} |