diff options
Diffstat (limited to 'catalog-ui/src/app/view-models')
51 files changed, 2336 insertions, 1263 deletions
diff --git a/catalog-ui/src/app/view-models/admin-dashboard/add-category-modal/add-category-modal-view.html b/catalog-ui/src/app/view-models/admin-dashboard/add-category-modal/add-category-modal-view.html index a9df3e6009..2196aedd5b 100644 --- a/catalog-ui/src/app/view-models/admin-dashboard/add-category-modal/add-category-modal-view.html +++ b/catalog-ui/src/app/view-models/admin-dashboard/add-category-modal/add-category-modal-view.html @@ -1,4 +1,4 @@ -<sdc-modal modal="modalInstance" +<ng1-modal modal="modalInstance" type="classic" class="i-sdc-admin-add-category-modal modal-type-confirmation" header-translate="CREATE_CATEGORY_MODAL_HEADER" @@ -38,4 +38,4 @@ </form> -</sdc-modal> +</ng1-modal> diff --git a/catalog-ui/src/app/view-models/catalog/catalog-view-model.ts b/catalog-ui/src/app/view-models/catalog/catalog-view-model.ts index 2296aa7cdf..8840afd79d 100644 --- a/catalog-ui/src/app/view-models/catalog/catalog-view-model.ts +++ b/catalog-ui/src/app/view-models/catalog/catalog-view-model.ts @@ -20,11 +20,13 @@ 'use strict'; import * as _ from "lodash"; -import {Component, IMainCategory, IGroup, IConfigStatuses, IAppMenu, IAppConfigurtaion, IUserProperties, ISubCategory} from "app/models"; +import {Component, IMainCategory, IGroup, IConfigStatuses, IAppMenu, IAppConfigurtaion, IUserProperties, ISubCategory, ICategoryBase} from "app/models"; import {EntityService, CacheService} from "app/services"; import {ComponentFactory, ResourceType, MenuHandler, ChangeLifecycleStateHandler} from "app/utils"; import {UserService} from "../../ng2/services/user.service"; - +import {ArchiveService} from "../../ng2/services/archive.service"; +import { ICatalogSelector, CatalogSelectorTypes } from "../../models/catalogSelector"; +import {IConfigStatus} from "../../models/app-config"; interface Checkboxes { componentTypes:Array<string>; @@ -38,16 +40,32 @@ interface CheckboxesFilter { // Categories selectedCategoriesModel:Array<string>; // Statuses - selectedStatuses:Array<string>; + selectedStatuses:Array<Array<string>>; } interface Gui { isLoading:boolean; - onResourceSubTypesClick:Function; + onComponentSubTypesClick:Function; onComponentTypeClick:Function; onCategoryClick:Function; - onSubcategoryClick:Function; - onGroupClick:Function; + onStatusClick:Function; + changeFilterTerm:Function; +} + +interface IFilterParams { + components: string[]; + categories: string[]; + statuses: (string)[]; + order: [string, boolean]; + term: string; + active: boolean; +} + +interface ICategoriesMap { + [key: string]: { + category: ICategoryBase, + parent: ICategoryBase + } } export interface ICatalogViewModelScope extends ng.IScope { @@ -71,13 +89,22 @@ export interface ICatalogViewModelScope extends ng.IScope { //this is for UI paging numberOfItemToDisplay:number; isAllItemDisplay:boolean; - + catalogFilteredItemsNum:number; changeLifecycleState(entity:any, state:string):void; sectionClick (section:string):void; order(sortBy:string):void; - getNumOfElements(num:number):string; + getElementFoundTitle(num:number):string; goToComponent(component:Component):void; raiseNumberOfElementToDisplay():void; + + selectedCatalogItem: ICatalogSelector; + catalogSelectorItems: Array<ICatalogSelector>; + showCatalogSelector: boolean; + catalogAllItems:Array<Component>; /* fake data */ + elementFoundTitle: string; + elementTypeTitle: string; + + selectLeftSwitchItem (item: ICatalogSelector): void; } export class CatalogViewModel { @@ -93,9 +120,20 @@ export class CatalogViewModel { 'Sdc.Services.CacheService', 'ComponentFactory', 'ChangeLifecycleStateHandler', - 'MenuHandler' + 'MenuHandler', + 'ArchiveServiceNg2' ]; + private defaultFilterParams:IFilterParams = { + components: [], + categories: [], + statuses: [], + order: ['lastUpdateDate', true], + term: '', + active: true + }; + private categoriesMap:ICategoriesMap; + constructor(private $scope:ICatalogViewModelScope, private $filter:ng.IFilterService, private EntityService:EntityService, @@ -107,64 +145,112 @@ export class CatalogViewModel { private cacheService:CacheService, private ComponentFactory:ComponentFactory, private ChangeLifecycleStateHandler:ChangeLifecycleStateHandler, - private MenuHandler:MenuHandler) { + private MenuHandler:MenuHandler, + private ArchiveService:ArchiveService + ) { + this.initLeftSwitch(); this.initScopeMembers(); + this.loadFilterParams(); this.initCatalogData(); // Async task to get catalog from server. this.initScopeMethods(); } - private initCatalogData = ():void => { - let onSuccess = (followedResponse:Array<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')); - 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 initLeftSwitch = ():void => { + this.$scope.showCatalogSelector = false; + + this.$scope.catalogSelectorItems = [ + {value: CatalogSelectorTypes.Active, title: "Active Items", header: "Active"}, + {value: CatalogSelectorTypes.Archive, title: "Archive", header: "Archived"} + ]; + // set active items is default + this.$scope.selectedCatalogItem = this.$scope.catalogSelectorItems[0]; }; + private initCatalogData = ():void => { + if(this.$scope.selectedCatalogItem.value === CatalogSelectorTypes.Archive){ + this.getArchiveCatalogItems(); + } else { + this.getActiveCatalogItems(); + } + }; 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.categories = this.cacheService.get('serviceCategories').concat(this.cacheService.get('resourceCategories')).map((cat) => <IMainCategory>cat); this.$scope.sdcMenu = this.sdcMenu; this.$scope.confStatus = this.sdcMenu.statuses; this.$scope.expandedSection = ["type", "category", "status"]; this.$scope.user = this.userService.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']; this.$scope.checkboxes.resourceSubTypes = ['VF', 'VFC', 'CR', 'PNF', 'CP', 'VL']; + this.categoriesMap = this.initCategoriesMap(); + + this.initCheckboxesFilter(); + this.$scope.version = this.cacheService.get('version'); + this.$scope.sortBy = 'lastUpdateDate'; + this.$scope.reverse = true; + + }; + private initCheckboxesFilter() { // 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 initCategoriesMap(categoriesList?:(ICategoryBase)[], parentCategory:ICategoryBase=null): ICategoriesMap { + categoriesList = (categoriesList) ? categoriesList : this.$scope.categories; + + // Init categories map + return categoriesList.reduce((acc, cat) => { + acc[cat.uniqueId] = { + category: cat, + parent: parentCategory + }; + const catChildren = ((<IMainCategory>cat).subcategories) + ? (<IMainCategory>cat).subcategories + : (((<ISubCategory>cat).groupings) + ? (<ISubCategory>cat).groupings + : null); + if (catChildren) { + Object.assign(acc, this.initCategoriesMap(catChildren, cat)); + } + return acc; + }, <ICategoriesMap>{}); + } private initScopeMethods = ():void => { - this.$scope.sectionClick = (section:string):void => { - let index:number = this.$scope.expandedSection.indexOf(section); + this.$scope.selectLeftSwitchItem = (item: ICatalogSelector): void => { + + if (this.$scope.selectedCatalogItem.value !== item.value) { + this.$scope.selectedCatalogItem = item; + switch (item.value) { + case CatalogSelectorTypes.Active: + this.getActiveCatalogItems(true); + break; + + case CatalogSelectorTypes.Archive: + this.getArchiveCatalogItems(true); + break; + } + this.changeFilterParams({active: (item.value === CatalogSelectorTypes.Active)}) + } + }; + + this.$scope.sectionClick = (section: string): void => { + let index: number = this.$scope.expandedSection.indexOf(section); if (index !== -1) { this.$scope.expandedSection.splice(index, 1); } else { @@ -173,13 +259,16 @@ export class CatalogViewModel { }; - 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.order = (sortBy: string): void => {//default sort by descending last update. default for alphabetical = ascending + this.changeFilterParams({ + order: (this.$scope.filterParams.order[0] === sortBy) + ? [sortBy, !this.$scope.filterParams.order[1]] + : [sortBy, sortBy === 'lastUpdateDate'] + }); }; - this.$scope.goToComponent = (component:Component):void => { + this.$scope.goToComponent = (component: Component): void => { this.$scope.gui.isLoading = true; this.$state.go('workspace.general', {id: component.uniqueId, type: component.componentType.toLowerCase()}); }; @@ -188,11 +277,11 @@ export class CatalogViewModel { // Will print the number of elements found in catalog this.$scope.getNumOfElements = (num:number):string => { if (!num || num === 0) { - return "No Elements found"; + return `No <b>${this.$scope.selectedCatalogItem.header}</b> Elements found`; } else if (num === 1) { - return "1 Element found"; + return `1 <b>${this.$scope.selectedCatalogItem.header}</b> Element found`; } else { - return num + " Elements found"; + return num + ` <b>${this.$scope.selectedCatalogItem.header}</b> Elements found`; } }; @@ -200,124 +289,392 @@ export class CatalogViewModel { * 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); - } + this.$scope.gui.onComponentTypeClick = (compType: string, checked?: boolean): void => { + let components = angular.copy(this.$scope.filterParams.components); + const compIdx = components.indexOf(compType); + checked = (checked !== undefined) ? checked : compIdx === -1; + if (checked && compIdx === -1) { + components.push(compType); + components = this.cleanSubsFromList(components); + } else if (!checked && compIdx !== -1) { + components.splice(compIdx, 1); } + this.changeFilterParams({ + components: components + }); }; /** * 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.onComponentSubTypesClick = (compSubType: string, compType: string, checked?: boolean): void => { + const componentSubTypesCheckboxes = this.$scope.checkboxes[compType.toLowerCase() + 'SubTypes']; + if (componentSubTypesCheckboxes) { + let components = angular.copy(this.$scope.filterParams.components); + let componentSubTypes = components.filter((st) => st.startsWith(compType + '.')); + + const compSubTypeValue = compType + '.' + compSubType; + const compSubTypeValueIdx = components.indexOf(compSubTypeValue); + checked = (checked !== undefined) ? checked : compSubTypeValueIdx === -1; + if (checked && compSubTypeValueIdx === -1) { + components.push(compSubTypeValue); + componentSubTypes.push(compSubTypeValue); + + // if all sub types are checked, then check the main component type + if (componentSubTypes.length === componentSubTypesCheckboxes.length) { + this.$scope.gui.onComponentTypeClick(compType, true); + return; + } + } else if (!checked) { + const compIdx = components.indexOf(compType); + // if sub type exists, then remove it + if (compSubTypeValueIdx !== -1) { + components.splice(compSubTypeValueIdx, 1); + } + // else, if sub type doesn't exists, but its parent main component type exists, + // then remove the main type and push all sub types except the current + else if (compIdx !== -1) { + components.splice(compIdx, 1); + componentSubTypesCheckboxes.forEach((st) => { + if (st !== compSubType) { + components.push(compType + '.' + st); + } + }); + } + } + + this.changeFilterParams({ + components + }); } }; - this.$scope.gui.onCategoryClick = (category: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: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; - }))); - }); + this.$scope.gui.onCategoryClick = (category: ICategoryBase, checked?: boolean): void => { + let categories: string[] = angular.copy(this.$scope.filterParams.categories); + let parentCategory: ICategoryBase = this.categoriesMap[category.uniqueId].parent; + + // add the category to selected categories list + const categoryIdx = categories.indexOf(category.uniqueId); + checked = (checked !== undefined) ? checked : categoryIdx === -1; + if (checked && categoryIdx === -1) { + categories.push(category.uniqueId); + + // check if all parent category children are checked, then check the parent category + if (parentCategory) { + if (this.getParentCategoryChildren(parentCategory).every((ch) => categories.indexOf(ch.uniqueId) !== -1)) { + this.$scope.gui.onCategoryClick(parentCategory, true); + return; + } } - } else { - this.$scope.checkboxesFilter.selectedCategoriesModel = _.difference(this.$scope.checkboxesFilter.selectedCategoriesModel, _.map(category.subcategories, (item) => { - return item.uniqueId; - })); - if (category.subcategories) { - category.subcategories.forEach((sub: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; - })); - }); + + categories = this.cleanSubsFromList(categories); + } else if (!checked) { + // if category exists, then remove it + if (categoryIdx !== -1) { + categories.splice(categoryIdx, 1); + } + // else, if category doesn't exists, but one of its parent categories exists, + // then remove that parent category and push all its children categories except the current + else { + let prevParentCategory: ICategoryBase = category; + let additionalCategories: string[] = []; + while (parentCategory) { + // add parent category children to list for replacing the parent category (if will be found later) + additionalCategories = additionalCategories.concat( + this.getParentCategoryChildren(parentCategory) + .filter((ch) => ch.uniqueId !== prevParentCategory.uniqueId) + .map((ch) => ch.uniqueId)); + + const parentCategoryIdx = categories.indexOf(parentCategory.uniqueId); + if (parentCategoryIdx !== -1) { + categories.splice(parentCategoryIdx, 1); + categories = categories.concat(additionalCategories); + break; + } else { + prevParentCategory = parentCategory; + parentCategory = this.categoriesMap[parentCategory.uniqueId].parent; + } + } } } + + this.changeFilterParams({ + categories + }); }; - this.$scope.gui.onSubcategoryClick = (category:IMainCategory, subCategory: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; - })); - } + this.$scope.gui.onStatusClick = (statusKey: string, status: IConfigStatus, checked?: boolean) => { + const statuses = angular.copy(this.$scope.filterParams.statuses); - // 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); + // add the status key to selected statuses list + const statusIdx = statuses.indexOf(statusKey); + checked = (checked !== undefined) ? checked : statusIdx === -1; + if (checked && statusIdx === -1) { + statuses.push(statusKey); + } else if (!checked && statusIdx !== -1) { + statuses.splice(statusIdx, 1); } + this.changeFilterParams({ + statuses + }); + }; + + this.$scope.gui.changeFilterTerm = (filterTerm: string) => { + this.changeFilterParams({ + term: filterTerm + }); }; - this.$scope.raiseNumberOfElementToDisplay = ():void => { + 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: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 getAllCategoryChildrenIdsFlat(category:ICategoryBase) { + let catChildrenIds = []; + if ((<IMainCategory>category).subcategories) { + catChildrenIds = (<IMainCategory>category).subcategories.reduce((acc, scat) => { + return acc.concat(this.getAllCategoryChildrenIdsFlat(scat)); + }, (<IMainCategory>category).subcategories.map((scat) => scat.uniqueId)); + } + else if ((<ISubCategory>category).groupings) { + catChildrenIds = (<ISubCategory>category).groupings.map((g) => g.uniqueId); + } + return catChildrenIds; + } - }; + private getParentCategoryChildren(parentCategory:ICategoryBase): ICategoryBase[] { + if ((<IMainCategory>parentCategory).subcategories) { + return (<IMainCategory>parentCategory).subcategories; + } else if ((<ISubCategory>parentCategory).groupings) { + return (<ISubCategory>parentCategory).groupings; + } + return []; + } - private areAllCategoryChildsSelected = (category:IMainCategory):boolean => { - if (!category.subcategories) { - return false; + private cleanSubsFromList(list:Array<string>, delimiter:string='.', removeSubsList?:Array<string>) { + let curRemoveSubsList = (removeSubsList || list).slice().sort(); // by default remove any children of any item in list + while (curRemoveSubsList.length) { + const curRemoveSubItem = curRemoveSubsList.shift(); + const removeSubListFilter = (x) => !x.startsWith(curRemoveSubItem + delimiter); + list = list.filter(removeSubListFilter); + curRemoveSubsList = curRemoveSubsList.filter(removeSubListFilter); } - let allIds = _.map(category.subcategories, (sub:ISubCategory)=> { - return sub.uniqueId; + return list; + } + + private applyFilterParamsToView(filterParams:IFilterParams) { + // reset checkboxes filter + this.initCheckboxesFilter(); + + this.applyFilterParamsComponents(filterParams); + this.applyFilterParamsCategories(filterParams); + this.applyFilterParamsStatuses(filterParams); + this.applyFilterParamsOrder(filterParams); + this.applyFilterParamsTerm(filterParams); + } + + private applyFilterParamsComponents(filterParams:IFilterParams) { + const componentList = []; + const componentSubTypesLists = {}; + filterParams.components.forEach((compStr) => { + const compWithSub = compStr.split('.', 2); + const mainComp = compWithSub[0]; + const subComp = compWithSub[1]; + if (!subComp) { // main component type + componentList.push(mainComp); + + // if component type has sub types list, then add all component sub types + const checkboxesSubTypeKey = mainComp.toLowerCase() + 'SubTypes'; + if (this.$scope.checkboxes.hasOwnProperty(checkboxesSubTypeKey)) { + componentSubTypesLists[mainComp] = angular.copy(this.$scope.checkboxes[checkboxesSubTypeKey]); + } + } else { // sub component type + // init component sub types list + if (!componentSubTypesLists.hasOwnProperty(mainComp)) { + componentSubTypesLists[mainComp] = []; + } + // add sub type to list if not exist + if (componentSubTypesLists[mainComp].indexOf(subComp) === -1) { + componentSubTypesLists[mainComp].push(subComp); + } + } }); - let total = _.intersection(this.$scope.checkboxesFilter.selectedCategoriesModel, allIds); - return total.length === category.subcategories.length ? true : false; - }; + this.$scope.checkboxesFilter.selectedComponentTypes = componentList; + Object.keys(componentSubTypesLists).forEach((tKey) => { + const compSelectedSubTypeKey = 'selected' + tKey + 'SubTypes'; + if (this.$scope.checkboxesFilter.hasOwnProperty(compSelectedSubTypeKey)) { + this.$scope.checkboxesFilter[compSelectedSubTypeKey] = componentSubTypesLists[tKey]; + } + }); + + let selectedCatalogIndex = filterParams.active ? CatalogSelectorTypes.Active : CatalogSelectorTypes.Archive; + this.$scope.selectedCatalogItem = this.$scope.catalogSelectorItems[selectedCatalogIndex]; + + } + + private applyFilterParamsCategories(filterParams:IFilterParams) { + this.$scope.checkboxesFilter.selectedCategoriesModel = filterParams.categories.reduce((acc, c) => { + acc.push(c); + const cat = this.categoriesMap[c].category; + if (cat) { + acc = acc.concat(this.getAllCategoryChildrenIdsFlat(cat)); + } + return acc; + }, []); + } + + private getActiveCatalogItems(forceReload?: boolean): void { - private areAllSubCategoryChildsSelected = (subCategory:ISubCategory):boolean => { - if (!subCategory.groupings) { - return false; + if (forceReload || this.componentShouldReload()) { + this.$scope.gui.isLoading = true; + let onSuccess = (followedResponse:Array<Component>):void => { + this.updateCatalogItems(followedResponse); + this.$scope.gui.isLoading = false; + this.cacheService.set('breadcrumbsComponentsState', this.$state.current.name); //catalog + this.cacheService.set('breadcrumbsComponents', followedResponse); + }; + + let onError = ():void => { + console.info('Failed to load catalog CatalogViewModel::getActiveCatalogItems'); + this.$scope.gui.isLoading = false; + }; + this.EntityService.getCatalog().then(onSuccess, onError); + } else { + let cachedComponents = this.cacheService.get('breadcrumbsComponents'); + this.updateCatalogItems(cachedComponents); } - let allIds = _.map(subCategory.groupings, (group: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; + private getArchiveCatalogItems(forceReload?: boolean): void { + if(forceReload || !this.cacheService.contains("archiveComponents")) { + this.$scope.gui.isLoading = true; + let onSuccess = (followedResponse:Array<Component>):void => { + this.cacheService.set("archiveComponents", followedResponse); + this.updateCatalogItems(followedResponse); + this.$scope.gui.isLoading = false; + }; + + let onError = ():void => { + console.info('Failed to load catalog CatalogViewModel::getArchiveCatalogItems'); + this.$scope.gui.isLoading = false; + }; + + this.ArchiveService.getArchiveCatalog().subscribe(onSuccess, onError); + } else { + let archiveCache = this.cacheService.get("archiveComponents"); + this.updateCatalogItems(archiveCache); } - return false; - }; + + } + + private updateCatalogItems = (items:Array<Component>):void => { + this.$scope.catalogFilterdItems = items; + this.$scope.isAllItemDisplay = this.$scope.numberOfItemToDisplay >= this.$scope.catalogFilterdItems.length; + this.$scope.categories = this.cacheService.get('serviceCategories').concat(this.cacheService.get('resourceCategories')); + } + + private componentShouldReload = ():boolean => { + let breadcrumbsValid: boolean = (this.$state.current.name === this.cacheService.get('breadcrumbsComponentsState') && this.cacheService.contains('breadcrumbsComponents')); + return !breadcrumbsValid || this.isDefaultFilter(); + } + + private isDefaultFilter = (): boolean => { + return angular.equals(this.defaultFilterParams, this.$scope.filterParams); + } + + private applyFilterParamsStatuses(filterParams: IFilterParams) { + this.$scope.checkboxesFilter.selectedStatuses = filterParams.statuses.reduce((acc, stKey:string) => { + const status = this.$scope.confStatus[stKey]; + if (status) { + acc.push(status.values); + } + return acc; + }, []); + } + + private applyFilterParamsOrder(filterParams: IFilterParams) { + this.$scope.sortBy = filterParams.order[0]; + this.$scope.reverse = filterParams.order[1]; + } + + private applyFilterParamsTerm(filterParams: IFilterParams) { + this.$scope.search = { + filterTerm: filterParams.term + }; + } + + private loadFilterParams() { + const params = this.$state.params; + this.$scope.filterParams = angular.copy(this.defaultFilterParams); + Object.keys(params).forEach((k) => { + if (!angular.isUndefined(params[k])) { + let newVal; + let filterKey = k.substr('filter.'.length); + switch (k) { + case 'filter.components': + case 'filter.categories': + newVal = _.uniq(params[k].split(',')); + newVal = this.cleanSubsFromList(newVal); + break; + case 'filter.statuses': + newVal = _.uniq(params[k].split(',')); + break; + case 'filter.order': + newVal = params[k].startsWith('-') ? [params[k].substr(1), true] : [params[k], false]; + break; + case 'filter.term': + newVal = params[k]; + break; + case 'filter.active': + newVal = (params[k] === "true" || params[k] === true); + break; + default: + // unknown filter key + filterKey = null; + } + if (filterKey) { + this.$scope.filterParams[filterKey] = newVal; + } + } + }); + // re-set filter params with valid values + this.applyFilterParamsToView(this.$scope.filterParams); + + } + + private changeFilterParams(changedFilterParams) { + const newParams = {}; + Object.keys(changedFilterParams).forEach((k) => { + let newVal; + switch (k) { + case 'components': + case 'categories': + case 'statuses': + newVal = changedFilterParams[k] && changedFilterParams[k].length ? changedFilterParams[k].join(',') : null; + break; + case 'order': + newVal = (changedFilterParams[k][1] ? '-' : '') + changedFilterParams[k][0]; + break; + case 'term': + newVal = changedFilterParams[k] ? changedFilterParams[k] : null; + break; + case 'active': + newVal = changedFilterParams[k]; + break; + default: + return; + } + this.$scope.filterParams[k] = changedFilterParams[k]; + newParams['filter.' + k] = newVal; + }); + this.$state.go('.', newParams, {location: 'replace', notify: false}).then(() => { + this.applyFilterParamsToView(this.$scope.filterParams); + }); + } } diff --git a/catalog-ui/src/app/view-models/catalog/catalog-view.html b/catalog-ui/src/app/view-models/catalog/catalog-view.html index 76f23573a1..0546db3196 100644 --- a/catalog-ui/src/app/view-models/catalog/catalog-view.html +++ b/catalog-ui/src/app/view-models/catalog/catalog-view.html @@ -7,10 +7,31 @@ <div class="w-sdc-main-container"> + <div + class="i-sdc-designer-leftbar-section-left-switch-header" + data-tests-id="catalog-selector-button" + data-ng-click="showCatalogSelector=!showCatalogSelector"> + <div class="i-sdc-designer-leftbar-section-left-switch-header-text"> + {{selectedCatalogItem.title}} + </div> + <div class="i-sdc-designer-leftbar-section-left-switch-header-icon sprite-new arrow-up-small"> </div> + + <div + class="sdc-catalog-selector-wrapper" + data-ng-show="showCatalogSelector"> + <div + class="sdc-catalog-selector-item" + data-ng-repeat="leftSwitchItem in catalogSelectorItems track by $index" + data-tests-id="catalog-selector-{{leftSwitchItem.value}}" + data-ng-click="selectLeftSwitchItem(leftSwitchItem)"> + <span>{{leftSwitchItem.title}}</span> + </div> + </div> + </div> + <!-- LEFT SIDE --> - <perfect-scrollbar scroll-y-margin-offset="0" class="sdc-catalog-body-container w-sdc-left-sidebar" include-padding="true"> + <perfect-scrollbar scroll-y-margin-offset="0" class="sdc-catalog-body-container w-sdc-left-sidebar i-sdc-designer-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" @@ -23,20 +44,20 @@ <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}}" + <ng1-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> + sdc-checked-change="gui.onComponentTypeClick(type, checked)" + text="{{type}}"></ng1-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}}" + <ng1-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> + sdc-checked-change="gui.onComponentSubTypesClick(subType, type, checked)" + text="{{subType}}"></ng1-checkbox> </li> </ul> @@ -59,33 +80,33 @@ <li class="i-sdc-designer-leftbar-section-content-ul-li" data-ng-repeat="category in categories | categoryTypeFilter:checkboxesFilter.selectedComponentTypes:checkboxesFilter.selectedResourceSubTypes | orderBy: category"> - <sdc-checkbox elem-id="checkbox-{{category.uniqueId | lowercase | clearWhiteSpaces}}" + <ng1-checkbox elem-id="checkbox-{{category.uniqueId | lowercase | clearWhiteSpaces}}" sdc-checklist-model="checkboxesFilter.selectedCategoriesModel" sdc-checklist-value="category.uniqueId" + sdc-checked-change="gui.onCategoryClick(category, checked)" data-tests-id="{{category.uniqueId}}" - data-ng-click="gui.onCategoryClick(category)" - text="{{category.name}}"></sdc-checkbox> + text="{{category.name}}"></ng1-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}}" + <ng1-checkbox elem-id="checkbox-{{subcategory.uniqueId | lowercase | clearWhiteSpaces}}" sdc-checklist-model="checkboxesFilter.selectedCategoriesModel" sdc-checklist-value="subcategory.uniqueId" + sdc-checked-change="gui.onCategoryClick(subcategory, checked)" data-tests-id="{{subcategory.uniqueId}}" - data-ng-click="gui.onSubcategoryClick($parent.category, subcategory)" - text="{{subcategory.name}}"></sdc-checkbox> + text="{{subcategory.name}}"></ng1-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}}" + <ng1-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> + sdc-checked-change="gui.onCategoryClick(grouping, checked)" + text="{{grouping.name}}"></ng1-checkbox> </li> </ul> @@ -112,15 +133,15 @@ <!--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"> + data-ng-repeat="(key, state) in confStatus"> - <sdc-checkbox elem-id="checkbox-{{key | lowercase | clearWhiteSpaces}}" + <ng1-checkbox elem-id="checkbox-{{key | lowercase | clearWhiteSpaces}}" sdc-checklist-model="checkboxesFilter.selectedStatuses" sdc-checklist-value="state.values" - text="{{state.name}}"></sdc-checkbox> + sdc-checked-change="gui.onStatusClick(key, state, checked)" + text="{{state.name}}"></ng1-checkbox> <div class="i-sdc-categories-list-item-icon"></div> - </label> </li> </ul> </div> @@ -134,66 +155,39 @@ <!-- HEADER --> <div> - <div class="w-sdc-dashboard-catalog-header"> - {{getNumOfElements((catalogFilterdItems| entityFilter:checkboxesFilter | filter:search).length)}} - </div> + <div class="w-sdc-dashboard-catalog-items-header" + ng-bind-html="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> + <span class="w-sdc-dashboard-catalog-header-order1" 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> + 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> + <div infinite-scroll-disabled='isAllItemDisplay' infinite-scroll="raiseNumberOfElementToDisplay()" infinite-scroll-container="'#catalog-main-scroll'" infinite-scroll-distance="'0.2'" infinite-scroll-parent> <div class='w-sdc-row-flex-items'> - - <!-- Tile new --> - <div data-ng-init="component.filterTerm = component.name + ' ' + component.description + ' ' + component.tags.toString() + ' ' + component.version" - class="sdc-tile sdc-tile-fix-width" - data-ng-repeat="component in catalogFilterdItems| entityFilter:checkboxesFilter | filter:search | orderBy:sortBy:reverse | limitTo:numberOfItemToDisplay" - > - - <div class='sdc-tile-header' data-ng-class="{'purple': component.isResource(), 'blue': !component.isResource()}"> - <div data-ng-if="component.isResource()" data-tests-id="asset-type">{{component.getComponentSubType()}}</div> - <div data-ng-if="component.isService()">S</div> - </div> - - <div class='sdc-tile-content' data-ng-click="gui.isLoading || goToComponent(component)"> - <div class='sdc-tile-content-icon centered'> - <div class="{{component.iconSprite}} {{component.icon}}" - data-ng-class="{'sprite-resource-icons': component.isResource(), 'sprite-services-icons': component.isService()}" - data-tests-id="{{component.name}}"></div> - </div> - <div class='sdc-tile-content-info'> - <div class="sdc-tile-info-line title" data-tests-id="{{component.name | resourceName}}" sdc-smart-tooltip>{{component.name | resourceName}}</div> - <div class="sdc-tile-info-line subtitle" data-tests-id="{{component.name}}Version"> - V {{component.version}} - </div> - </div> - </div> - <div class='sdc-tile-footer'> - <div class="sdc-tile-footer-content"> - <div class='sdc-tile-footer-text'>{{component.getStatus(sdcMenu)}}</div> - </div> - </div> - </div> <!-- Tile new --> - + <ng2-ui-tile data-ng-repeat="component in catalogFilterdItems| entityFilter:checkboxesFilter | filter:search | orderBy:sortBy:reverse | limitTo:numberOfItemToDisplay" + data-ng-init="component.filterTerm = component.name + ' ' + component.description + ' ' + component.tags.toString() + ' ' + component.version;" + [component]="component" (on-tile-click)="gui.isLoading || goToComponent(component)"></ng2-ui-tile> + <!-- Tile new --> + </div> - + </div> </perfect-scrollbar> </div> - <top-nav [top-lvl-selected-index]="1" [search-term]="search.filterTerm" (search-term-change)="search.filterTerm=$event" [version]="version"></top-nav> + <top-nav [top-lvl-selected-index]="1" [search-term]="search.filterTerm" (search-term-change)="gui.changeFilterTerm($event)" [version]="version"></top-nav> </div> diff --git a/catalog-ui/src/app/view-models/catalog/catalog.less b/catalog-ui/src/app/view-models/catalog/catalog.less index 1f473c9638..45556030e3 100644 --- a/catalog-ui/src/app/view-models/catalog/catalog.less +++ b/catalog-ui/src/app/view-models/catalog/catalog.less @@ -145,29 +145,29 @@ 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 { + .w-sdc-dashboard-catalog-items-header { .b_3; + color: @main_color_m; + font-family: OpenSans-Regular, sans-serif; + font-size: 14px; display: inline-block; - font-style: italic; - font-weight: bold; - padding-left: 10px; + font-style: normal; + margin-left: 11px; + b { + font-family: OpenSans-Bold, sans-serif; + color: @main_color_l; + font-weight: bold; + } + font-weight: normal; + /* padding-left: 10px; */ } - .w-sdc-dashboard-catalog-header-order { + .w-sdc-dashboard-catalog-header-order1 { .b_3; font-weight: 800; } @@ -207,8 +207,6 @@ } - - .w-sdc-dashboard-catalog-header-right{ float: right; display: inline-block; @@ -248,6 +246,39 @@ margin-left: 20px; } + /* added Michael */ + .i-sdc-designer-left-sidebar { + margin-top: 43px; + } + .i-sdc-designer-leftbar-section-left-switch-header { + text-transform: uppercase; + .l_14_m; + line-height: 40px; + width: 243px; + + font-family: OpenSans-Bold, sans-serif; + font-size: 14px; + + color: @main_color_a; + background-color: @tlv_color_t; + border: solid 1px fade(@main_color_t, 40%); + cursor: pointer; + opacity: 1; + z-index: 9999; + position: relative; + //box-shadow: 1px 0 2px #00000036; + } + .i-sdc-designer-leftbar-section-left-switch-header-text { + display: inline-block; + width: 180px; + margin-left: 20px; + } + .i-sdc-designer-leftbar-section-left-switch-header-icon { + display: inline-block; + vertical-align: middle; + } + + .seperator-left, .seperator-right { border-right: solid 1px @color_m; @@ -299,3 +330,33 @@ .hand; } } + +/* added Michael */ +.sdc-catalog-selector-wrapper { + position: absolute; + left: 0px; + top: 42px; + width: 241px; + height: auto; + cursor: pointer; + opacity: 1; + z-index: 1000; + box-shadow: 1px 2px 3px #b1b1b1; +} + +.sdc-catalog-selector-item { + text-transform: none; + line-height: 40px; + font-family: OpenSans-Bold, sans-serif; + font-size: 14px; + color: @main_color_l; + background-color: @main_color_p; + padding-left: 20px; +} + +.sdc-catalog-selector-item:hover { + color: @main_color_a; + background-color: @tlv_color_v; +} + + diff --git a/catalog-ui/src/app/view-models/dashboard/dashboard-view-model.ts b/catalog-ui/src/app/view-models/dashboard/dashboard-view-model.ts index 42628607c9..4d084045f7 100644 --- a/catalog-ui/src/app/view-models/dashboard/dashboard-view-model.ts +++ b/catalog-ui/src/app/view-models/dashboard/dashboard-view-model.ts @@ -21,13 +21,15 @@ 'use strict'; import {IConfigRoles, IAppConfigurtaion, IAppMenu, IUserProperties, Component} from "app/models"; import {EntityService, SharingService, CacheService} from "app/services"; -import {ComponentType, ResourceType, MenuHandler, ModalsHandler, ChangeLifecycleStateHandler, SEVERITY, ComponentFactory} from "app/utils"; +import {ComponentType, ResourceType, MenuHandler, ModalsHandler, ChangeLifecycleStateHandler, SEVERITY, ComponentFactory, CHANGE_COMPONENT_CSAR_VERSION_FLAG} from "app/utils"; import {IClientMessageModalModel} from "../modals/message-modal/message-client-modal/client-message-modal-view-model"; import {UserService} from "../../ng2/services/user.service"; + export interface IDashboardViewModelScope extends ng.IScope { isLoading:boolean; + numberOfItemToDisplay:number; components:Array<Component>; folders:FoldersMenu; roles:IConfigRoles; @@ -38,10 +40,11 @@ export interface IDashboardViewModelScope extends ng.IScope { showTutorial:boolean; isFirstTime:boolean; version:string; - checkboxesFilter:CheckboxesFilter; + filterParams:DashboardFilter; vfcmtType:string; - + changeFilterParams():void; + updateSearchTerm(newTerm:string):void; onImportVfc(file:any):void; onImportVf(file:any):void; openCreateModal(componentType:ComponentType, importedFile:any):void; @@ -52,11 +55,12 @@ export interface IDashboardViewModelScope extends ng.IScope { getCurrentFolderDistributed():Array<Component>; changeLifecycleState(entity:any, data:any):void; goToComponent(component:Component):void; + raiseNumberOfElementToDisplay():void; wizardDebugEdit:Function; notificationIconCallback:Function; } -interface CheckboxesFilter { +interface ICheckboxesFilter { // Statuses selectedStatuses:Array<string>; // distributed @@ -76,6 +80,35 @@ export interface IMenuItemProperties { states:Array<any>; } +export interface IQueryFilterParams { + 'filter.term': string; + 'filter.distributed': string; + 'filter.status': string +} + + +export class DashboardFilter { + searchTerm: string; + checkboxes: ICheckboxesFilter; + + constructor(params = {}) { + this.searchTerm = params['filter.term'] || ""; + this.checkboxes = { + selectedStatuses : params['filter.status']? params['filter.status'].split(',') : [], + distributed : params['filter.distributed']? params['filter.distributed'].split(',') : [] + }; + } + + public toParam = ():IQueryFilterParams => { + return { + 'filter.term': this.searchTerm, + 'filter.distributed': this.checkboxes && this.checkboxes.distributed.join(',') || null, + 'filter.status': this.checkboxes && this.checkboxes.selectedStatuses.join(',') || null + }; + } + +} + export class FoldersMenu { private _folders:Array<FoldersItemsMenu> = []; @@ -190,7 +223,7 @@ export class DashboardViewModel { private $http:ng.IHttpService, private sdcConfig:IAppConfigurtaion, private sdcMenu:IAppMenu, - private $state:any, + private $state:ng.ui.IStateService, private $stateParams:any, private userService:UserService, private sharingService:SharingService, @@ -202,7 +235,7 @@ export class DashboardViewModel { private MenuHandler:MenuHandler) { this.initScope(); this.initFolders(); - this.initEntities(true); + this.initEntities(); if (this.$stateParams) { @@ -237,6 +270,7 @@ export class DashboardViewModel { this.$scope.version = this.cacheService.get('version'); this.$scope.sharingService = this.sharingService; + this.$scope.numberOfItemToDisplay = 0; this.$scope.isLoading = false; this.$scope.sdcConfig = this.sdcConfig; this.$scope.sdcMenu = this.sdcMenu; @@ -245,21 +279,26 @@ export class DashboardViewModel { this.$scope.showTutorial = false; this.$scope.isFirstTime = false; this.$scope.vfcmtType = ResourceType.VFCMT; + this.$scope.filterParams = new DashboardFilter(this.$state.params); // Open onboarding modal this.$scope.notificationIconCallback = ():void => { - this.ModalsHandler.openOnboadrdingModal('Import').then(()=> { - // OK + this.ModalsHandler.openOnboadrdingModal('Import').then((result)=> { + //OK + 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 + }); }, ()=> { // ERROR }); }; - // Checkboxes filter init - this.$scope.checkboxesFilter = <CheckboxesFilter>{}; - this.$scope.checkboxesFilter.selectedStatuses = []; - this.$scope.checkboxesFilter.distributed = []; - this.$scope.onImportVf = (file:any):void => { if (file && file.filename) { // Check that the file has valid extension. @@ -367,6 +406,20 @@ export class DashboardViewModel { this.$state.go('workspace.general', {id: component.uniqueId, type: component.componentType.toLowerCase()}); }; + this.$scope.raiseNumberOfElementToDisplay = ():void => { + this.$scope.numberOfItemToDisplay = this.$scope.numberOfItemToDisplay + 35; + if (this.$scope.components) { + this.$scope.isAllItemDisplay = this.$scope.numberOfItemToDisplay >= this.$scope.components.length; + } + }; + + this.$scope.updateSearchTerm = (newTerm: string):void => { + this.$scope.filterParams.searchTerm = newTerm; + }; + + this.$scope.changeFilterParams = ():void => { + this.$state.go('.', this.$scope.filterParams.toParam(), {location: 'replace', notify: false}); + }; }; private _getTotalCounts(tmpFolder, self):number { @@ -393,16 +446,38 @@ export class DashboardViewModel { } } - private initEntities = (reload:boolean):void => { - this.$scope.isLoading = reload; - this.entityService.getAllComponents().then( - (components:Array<Component>) => { - this.components = components; - this.$scope.components = components; - this.$scope.isLoading = false; - }); + private initEntities = (forceReload?:boolean):void => { + + if(forceReload || this.componentShouldReload()){ + this.$scope.isLoading = true; + this.entityService.getAllComponents(true).then( + (components:Array<Component>) => { + this.cacheService.set('breadcrumbsComponentsState', this.$state.current.name); //dashboard + this.cacheService.set('breadcrumbsComponents', components); + this.components = components; + this.$scope.components = components; + this.$scope.isAllItemDisplay = this.$scope.numberOfItemToDisplay >= this.$scope.components.length; + this.$scope.isLoading = false; + }); + } else { + this.components = this.cacheService.get('breadcrumbsComponents'); + this.$scope.components = this.components; + this.$scope.isAllItemDisplay = this.$scope.numberOfItemToDisplay >= this.$scope.components.length; + + } + }; + private isDefaultFilter = (): boolean => { + let defaultFilter = new DashboardFilter(); + return angular.equals(defaultFilter, this.$scope.filterParams); + } + + private componentShouldReload = ():boolean => { + let breadcrumbsValid: boolean = (this.$state.current.name === this.cacheService.get('breadcrumbsComponentsState') && this.cacheService.contains('breadcrumbsComponents')); + return !breadcrumbsValid || this.isDefaultFilter(); + } + private getEntitiesByStateDist = (state:string, dist:string):Array<Component> => { let gObj:Array<Component>; if (this.components && (state || dist)) { diff --git a/catalog-ui/src/app/view-models/dashboard/dashboard-view.html b/catalog-ui/src/app/view-models/dashboard/dashboard-view.html index bddcbcd46c..8279232b13 100644 --- a/catalog-ui/src/app/view-models/dashboard/dashboard-view.html +++ b/catalog-ui/src/app/view-models/dashboard/dashboard-view.html @@ -8,74 +8,53 @@ <div class="w-sdc-main-container"> - <perfect-scrollbar include-padding="true" class="w-sdc-main-right-container"> - - <div class='w-sdc-row-flex-items'> - - <!-- ADD Component --> - <div ng-if="user.role === 'DESIGNER'" class="w-sdc-dashboard-card-new" - data-ng-mouseleave="displayActions = false" - data-ng-mouseover="displayActions = true" - data-ng-init="displayActions = false"> - <div class="w-sdc-dashboard-card-new-content" data-tests-id="AddButtonsArea"> - <div class="w-sdc-dashboard-card-new-content-plus" data-ng-show="!displayActions"></div> - <div class="sdc-dashboard-create-element-container" data-ng-show="displayActions"> - <button data-ng-if="roles[user.role].dashboard.showCreateNew" data-tests-id="createResourceButton" class="tlv-btn outline blue" data-ng-click="openCreateModal('RESOURCE')">Add VF</button> - <button data-ng-if="roles[user.role].dashboard.showCreateNew" data-tests-id="createCRButton" class="tlv-btn outline blue" data-ng-click="createCR()">Add CR</button> - <button data-ng-if="roles[user.role].dashboard.showCreateNew" data-tests-id="createPNFButton" class="tlv-btn outline blue" data-ng-click="createPNF()">Add PNF</button> - <button data-ng-if="roles[user.role].dashboard.showCreateNew" data-tests-id="createServiceButton" class="tlv-btn outline blue" data-ng-click="openCreateModal('SERVICE')">Add Service</button> - </div> - </div> - </div> - - <!-- Import Component --> - <div ng-if="user.role === 'DESIGNER'" class="w-sdc-dashboard-card-new" - data-ng-mouseleave="displayActions = false" - data-ng-mouseover="displayActions = true" - data-ng-init="displayActions = false"> - <div class="w-sdc-dashboard-card-new-content" data-tests-id="importButtonsArea" > - <div class="w-sdc-dashboard-card-import-content-plus" data-ng-show="!displayActions"></div> - <div class="sdc-dashboard-import-element-container" data-ng-show="displayActions"> - <div data-ng-if="roles[user.role].dashboard.showCreateNew" class="tlv-btn outline blue">Import VFC - <file-opener on-file-upload="onImportVfc(file)" data-tests-id="importVFCbutton" extensions="{{sdcConfig.toscaFileExtension}}" data-ng-click="displayActions=false"></file-opener> - </div> - <div data-ng-if="roles[user.role].dashboard.showCreateNew" class="tlv-btn outline blue" data-ng-click="notificationIconCallback()">Import VSP</div> - <div data-ng-if="roles[user.role].dashboard.showCreateNew" class="tlv-btn outline blue import-dcae">Import DCAE asset - <file-opener on-file-upload="onImportVf(file)" data-tests-id="importVFbutton" extensions="{{sdcConfig.csarFileExtension}}" data-ng-click="displayActions=false"></file-opener> + <perfect-scrollbar id="dashboard-main-scroll" include-padding="true" class="w-sdc-main-right-container"> + + <div infinite-scroll-disabled='isAllItemDisplay' infinite-scroll="raiseNumberOfElementToDisplay()" infinite-scroll-container="'#dashboard-main-scroll'" infinite-scroll-distance="'0.2'" infinite-scroll-parent> + + <div class='w-sdc-row-flex-items'> + + <!-- ADD Component --> + <div ng-if="user.role === 'DESIGNER'" class="w-sdc-dashboard-card-new" + data-ng-mouseleave="displayActions = false" + data-ng-mouseover="displayActions = true" + data-ng-init="displayActions = false"> + <div class="w-sdc-dashboard-card-new-content" data-tests-id="AddButtonsArea"> + <div class="w-sdc-dashboard-card-new-content-plus" data-ng-show="!displayActions"></div> + <div class="sdc-dashboard-create-element-container" data-ng-show="displayActions"> + <button data-ng-if="roles[user.role].dashboard.showCreateNew" data-tests-id="createResourceButton" class="tlv-btn outline blue" data-ng-click="openCreateModal('RESOURCE')">Add VF</button> + <button data-ng-if="roles[user.role].dashboard.showCreateNew" data-tests-id="createCRButton" class="tlv-btn outline blue" data-ng-click="createCR()">Add CR</button> + <button data-ng-if="roles[user.role].dashboard.showCreateNew" data-tests-id="createPNFButton" class="tlv-btn outline blue" data-ng-click="createPNF()">Add PNF</button> + <button data-ng-if="roles[user.role].dashboard.showCreateNew" data-tests-id="createServiceButton" class="tlv-btn outline blue" data-ng-click="openCreateModal('SERVICE')">Add Service</button> </div> </div> </div> - </div> - <!-- Tile new --> - <div class="sdc-tile sdc-tile-fix-width" data-ng-repeat="component in components | filter:{resourceType:('!'+vfcmtType)} | entityFilter:checkboxesFilter | filter:search"> - - <div class='sdc-tile-header' data-ng-class="{'purple': component.isResource(), 'blue': !component.isResource()}"> - <div data-ng-if="component.isResource()" data-tests-id="asset-type">{{component.getComponentSubType()}}</div> - <div data-ng-if="component.isService()">S</div> - </div> - - <div class='sdc-tile-content' data-tests-id="dashboard-Elements" data-ng-click="goToComponent(component)"> - <div class='sdc-tile-content-icon'> - <div class="{{component.iconSprite}} {{component.icon}}" - data-ng-class="{'sprite-resource-icons': component.isResource(), 'sprite-services-icons': component.isService()}" - data-tests-id="{{component.name}}"></div> - </div> - - <div class='sdc-tile-content-info'> - <div class="sdc-tile-info-line title" data-tests-id="{{component.name | resourceName}}" sdc-smart-tooltip>{{component.name | resourceName}}</div> - <div class="sdc-tile-info-line subtitle" data-tests-id="{{component.name}}Version">V {{component.version}}</div> + <!-- Import Component --> + <div ng-if="user.role === 'DESIGNER'" class="w-sdc-dashboard-card-new" + data-ng-mouseleave="displayActions = false" + data-ng-mouseover="displayActions = true" + data-ng-init="displayActions = false"> + <div class="w-sdc-dashboard-card-new-content" data-tests-id="importButtonsArea" > + <div class="w-sdc-dashboard-card-import-content-plus" data-ng-show="!displayActions"></div> + <div class="sdc-dashboard-import-element-container" data-ng-show="displayActions"> + <div data-ng-if="roles[user.role].dashboard.showCreateNew" class="tlv-btn outline blue">Import VFC + <file-opener on-file-upload="onImportVfc(file)" data-tests-id="importVFCbutton" extensions="{{sdcConfig.toscaFileExtension}}" data-ng-click="displayActions=false"></file-opener> + </div> + <div data-ng-if="roles[user.role].dashboard.showCreateNew" class="tlv-btn outline blue" data-ng-click="notificationIconCallback()">Import VSP</div> + <div data-ng-if="roles[user.role].dashboard.showCreateNew" class="tlv-btn outline blue import-dcae">Import DCAE asset + <file-opener on-file-upload="onImportVf(file)" data-tests-id="importVFbutton" extensions="{{sdcConfig.csarFileExtension}}" data-ng-click="displayActions=false"></file-opener> + </div> + </div> </div> </div> - <div class='sdc-tile-footer'> - <div class="sdc-tile-footer-content"> - <div class='sdc-tile-footer-text'>{{component.getStatus(sdcMenu)}}</div> - </div> - </div> + <!-- Tile new --> + <ng2-ui-tile data-ng-repeat="component in components | filter:{resourceType:('!'+vfcmtType)} | entityFilter:filterParams.checkboxes | filter:filterParams.searchTerm | limitTo:numberOfItemToDisplay" + [component]="component" (on-tile-click)="goToComponent(component)"></ng2-ui-tile> + <!-- Tile new --> </div> - <!-- Tile new --> </div> @@ -88,24 +67,26 @@ > <span data-ng-if="folder.isGroup()">{{folder.text}}</span> - <sdc-checkbox data-ng-if="!folder.isGroup() && !folder.dist" + <ng1-checkbox data-ng-if="!folder.isGroup() && !folder.dist" elem-id="checkbox-{{folder.text | lowercase | clearWhiteSpaces}}" - sdc-checklist-model="checkboxesFilter.selectedStatuses" + sdc-checklist-model="filterParams.checkboxes.selectedStatuses" sdc-checklist-value="folder.state" - text="{{folder.text}}"></sdc-checkbox> + sdc-checklist-change="changeFilterParams()" + text="{{folder.text}}"></ng1-checkbox> - <sdc-checkbox data-ng-if="!folder.isGroup() && folder.dist" + <ng1-checkbox data-ng-if="!folder.isGroup() && folder.dist" elem-id="checkbox-{{folder.text | lowercase | clearWhiteSpaces}}" - sdc-checklist-model="checkboxesFilter.distributed" + sdc-checklist-model="filterParams.checkboxes.distributed" sdc-checklist-value="folder.dist" - text="{{folder.text}}"></sdc-checkbox> + sdc-checklist-change="changeFilterParams()" + text="{{folder.text}}"></ng1-checkbox> <span class="i-sdc-left-sidebar-item-state-count">{{entitiesCount(folder)}}</span> </div> </div> </div> - <top-nav [top-lvl-selected-index]="0" [version]="version" [search-term]="search.filterTerm" (search-term-change)="search.filterTerm=$event" [notification-icon-callback]="notificationIconCallback"></top-nav> + <top-nav [top-lvl-selected-index]="0" [version]="version" [search-term]="filterParams.searchTerm" (search-term-change)="updateSearchTerm($event);changeFilterParams()" [notification-icon-callback]="notificationIconCallback"></top-nav> </div> <div data-ui-view=""></div> diff --git a/catalog-ui/src/app/view-models/forms/artifact-form/artifact-form-view.html b/catalog-ui/src/app/view-models/forms/artifact-form/artifact-form-view.html index 0984c6872d..59124a28d9 100644 --- a/catalog-ui/src/app/view-models/forms/artifact-form/artifact-form-view.html +++ b/catalog-ui/src/app/view-models/forms/artifact-form/artifact-form-view.html @@ -1,4 +1,4 @@ -<sdc-modal modal="modalInstanceArtifact" type="classic" class="sdc-add-artifact" buttons="footerButtons" header="{{getFormTitle()}}" show-close-button="true" get-close-modal-response="close" data-tests-id="sdc-add-artifact"> +<ng1-modal modal="modalInstanceArtifact" type="classic" class="sdc-add-artifact" buttons="footerButtons" header="{{getFormTitle()}}" show-close-button="true" get-close-modal-response="close" data-tests-id="sdc-add-artifact"> <loader data-display="isLoading"></loader> @@ -165,5 +165,5 @@ </form> </div> -</sdc-modal> +</ng1-modal> diff --git a/catalog-ui/src/app/view-models/forms/attribute-form/attribute-form-view.html b/catalog-ui/src/app/view-models/forms/attribute-form/attribute-form-view.html index daa7a90bf8..eada5c9269 100644 --- a/catalog-ui/src/app/view-models/forms/attribute-form/attribute-form-view.html +++ b/catalog-ui/src/app/view-models/forms/attribute-form/attribute-form-view.html @@ -1,4 +1,4 @@ -<sdc-modal modal="modalInstanceAttribute" type="classic" class="sdc-edit-attribute-container" buttons="footerButtons" header="{{isNew ? 'Add' : 'Update' }} Attribute" show-close-button="true"> +<ng1-modal modal="modalInstanceAttribute" type="classic" class="sdc-edit-attribute-container" buttons="footerButtons" header="{{isNew ? 'Add' : 'Update' }} Attribute" show-close-button="true"> <div class="sdc-edit-attribute-form-container" > <form novalidate class="w-sdc-form two-columns" name="forms.editForm" > @@ -149,4 +149,4 @@ </form> </div> -</sdc-modal> +</ng1-modal> diff --git a/catalog-ui/src/app/view-models/forms/env-parameters-form/env-parameters-form.html b/catalog-ui/src/app/view-models/forms/env-parameters-form/env-parameters-form.html index 5fd57f6b24..d211b4ea72 100644 --- a/catalog-ui/src/app/view-models/forms/env-parameters-form/env-parameters-form.html +++ b/catalog-ui/src/app/view-models/forms/env-parameters-form/env-parameters-form.html @@ -1,4 +1,4 @@ -<sdc-modal modal="envParametersModal" type="classic" class="sdc-env-form-container" buttons="buttons" header="{{artifactResource.artifactDisplayName}}" show-close-button="true"> +<ng1-modal modal="envParametersModal" type="classic" class="sdc-env-form-container" buttons="buttons" header="{{artifactResource.artifactDisplayName}}" show-close-button="true"> <div class="w-sdc-env-form-container"> <div class="w-sdc-env-search pull-left"> <input type="text" class="w-sdc-env-search-input" placeholder="Search" data-ng-model="searchText" data-tests-id="search-env-param-name"/> @@ -46,8 +46,7 @@ <div class="i-sdc-form-item" data-ng-class="{error:(forms.editForm[parameter.name].$dirty && forms.editForm[parameter.name].$invalid), required: (parameter.defaultValue)}"> <span class="required-symbol">*</span> <div class="input-parameter"> - <input class="i-sdc-form-input" data-ng-class="{error: (forms.editForm[parameter.name].$invalid), - 'default-value':(parameter.defaultValue && parameter.currentValue === parameter.defaultValue)}" + <input class="i-sdc-form-input" data-ng-class="{error: (forms.editForm[parameter.name].$invalid)}" data-ng-model-options="{ debounce: 200 }" data-ng-model="parameter.currentValue" value="{{parameter.currentValue}}" @@ -90,4 +89,4 @@ </div> </div> </div> -</sdc-modal> +</ng1-modal> diff --git a/catalog-ui/src/app/view-models/forms/env-parameters-form/env-parameters-form.less b/catalog-ui/src/app/view-models/forms/env-parameters-form/env-parameters-form.less index e797093271..d89ab37030 100644 --- a/catalog-ui/src/app/view-models/forms/env-parameters-form/env-parameters-form.less +++ b/catalog-ui/src/app/view-models/forms/env-parameters-form/env-parameters-form.less @@ -109,9 +109,6 @@ width: 100%; display: inline-flex; padding-right: 33px; - &.default-value{ - border-color: @func_color_h; - } } .action-button{ border-left: solid 1px @main_color_o; diff --git a/catalog-ui/src/app/view-models/forms/input-form/input-form-view.html b/catalog-ui/src/app/view-models/forms/input-form/input-form-view.html index 1bf6dc4ca9..34532d14dd 100644 --- a/catalog-ui/src/app/view-models/forms/input-form/input-form-view.html +++ b/catalog-ui/src/app/view-models/forms/input-form/input-form-view.html @@ -1,4 +1,4 @@ -<sdc-modal modal="modalInstanceInput" type="classic" class="sdc-edit-input-container" buttons="footerButtons" header="Update Input" show-close-button="true"> +<ng1-modal modal="modalInstanceInput" type="classic" class="sdc-edit-input-container" buttons="footerButtons" header="Update Input" show-close-button="true"> <div class="sdc-edit-input-form-container" > <form novalidate class="w-sdc-form two-columns" name="forms.editForm" > @@ -122,4 +122,4 @@ </form> </div> -</sdc-modal> +</ng1-modal> diff --git a/catalog-ui/src/app/view-models/forms/property-forms/base-property-form/property-form-base-view.html b/catalog-ui/src/app/view-models/forms/property-forms/base-property-form/property-form-base-view.html index 7cb05bf4ca..248f143eca 100644 --- a/catalog-ui/src/app/view-models/forms/property-forms/base-property-form/property-form-base-view.html +++ b/catalog-ui/src/app/view-models/forms/property-forms/base-property-form/property-form-base-view.html @@ -1,4 +1,4 @@ -<sdc-modal modal="modalPropertyFormBase" type="classic" class="sdc-edit-property-container" buttons="footerButtons" header="{{isNew ? 'Add' : 'Update' }} Property" show-close-button="true" data-tests-id="sdc-edit-property-container"> +<ng1-modal modal="modalPropertyFormBase" type="classic" class="sdc-edit-property-container" buttons="footerButtons" header="{{isNew ? 'Add' : 'Update' }} Property" show-close-button="true" data-tests-id="sdc-edit-property-container"> <loader data-display="isLoading" relative="false" size="medium"></loader> <div class="sdc-modal-top-bar" data-ng-if="!isNew"> <div class="sdc-modal-top-bar-buttons"> @@ -129,4 +129,4 @@ </perfect-scrollbar> </div> -</sdc-modal> +</ng1-modal> diff --git a/catalog-ui/src/app/view-models/forms/property-forms/component-property-form/property-form-view-model.ts b/catalog-ui/src/app/view-models/forms/property-forms/component-property-form/property-form-view-model.ts index 8ea2e8cf76..f5c057e41e 100644 --- a/catalog-ui/src/app/view-models/forms/property-forms/component-property-form/property-form-view-model.ts +++ b/catalog-ui/src/app/view-models/forms/property-forms/component-property-form/property-form-view-model.ts @@ -23,8 +23,9 @@ import * as _ from "lodash"; import { PROPERTY_TYPES, ModalsHandler, ValidationUtils, PROPERTY_VALUE_CONSTRAINTS, FormState, PROPERTY_DATA} from "app/utils"; import {DataTypesService} from "app/services"; -import {PropertyModel, DataTypesMap, Component} from "app/models"; +import {PropertyModel, DataTypesMap, Component, GroupInstance, PolicyInstance, PropertyBEModel} from "app/models"; import {ComponentInstance} from "../../../../models/componentsInstances/componentInstance"; +import { ComponentInstanceServiceNg2 } from "app/ng2/services/component-instance-services/component-instance.service"; export interface IEditPropertyModel { property:PropertyModel; @@ -86,7 +87,10 @@ export class PropertyFormViewModel { 'ModalsHandler', 'filteredProperties', '$timeout', - 'isPropertyValueOwner' + 'isPropertyValueOwner', + 'propertyOwnerType', + 'propertyOwnerId', + 'ComponentInstanceServiceNg2' ]; private formState:FormState; @@ -104,7 +108,10 @@ export class PropertyFormViewModel { private ModalsHandler:ModalsHandler, private filteredProperties:Array<PropertyModel>, private $timeout:ng.ITimeoutService, - private isPropertyValueOwner:boolean) { + private isPropertyValueOwner:boolean, + private propertyOwnerType:string, + private propertyOwnerId:string, + private ComponentInstanceServiceNg2: ComponentInstanceServiceNg2) { this.formState = angular.isDefined(property.name) ? FormState.UPDATE : FormState.CREATE; this.initScope(); @@ -194,15 +201,17 @@ export class PropertyFormViewModel { this.$scope.isLastProperty = this.$scope.currentPropertyIndex == (this.filteredProperties.length - 1); this.$scope.dataTypes = this.DataTypesService.getAllDataTypes(); this.$scope.isPropertyValueOwner = this.isPropertyValueOwner; + this.$scope.propertyOwnerType = this.propertyOwnerType; this.initEditPropertyModel(); //check if property of VnfConfiguration this.$scope.isVnfConfiguration = false; - if(angular.isArray(this.component.componentInstances)) { + if(this.propertyOwnerType == "component" && angular.isArray(this.component.componentInstances)) { + var componentPropertyOwner:ComponentInstance = this.component.componentInstances.find((ci:ComponentInstance) => { return ci.uniqueId === this.property.resourceInstanceUniqueId; }); - if (componentPropertyOwner.componentName === 'vnfConfiguration') { + if (componentPropertyOwner && componentPropertyOwner.componentName === 'vnfConfiguration') { this.$scope.isVnfConfiguration = true; } } @@ -252,21 +261,30 @@ export class PropertyFormViewModel { } }; - //in case we have uniqueId we call update method - if (this.$scope.isPropertyValueOwner) { - if (!this.$scope.editPropertyModel.property.simpleType && !this.$scope.isSimpleType(property.type)) { - let myValueString:string = JSON.stringify(this.$scope.myValue); - property.value = myValueString; - } - this.component.updateInstanceProperties(property.resourceInstanceUniqueId, [property]).then((propertiesFromBE) => onPropertySuccess(propertiesFromBE[0]), onPropertyFaild); + //Not clean, but doing this as a temporary fix until we update the property right panel modals + if(this.propertyOwnerType == "group"){ + this.ComponentInstanceServiceNg2.updateComponentGroupInstanceProperties(this.component, this.propertyOwnerId, [property]) + .subscribe((propertiesFromBE) => { onPropertySuccess(<PropertyModel>propertiesFromBE[0])}, error => onPropertyFaild); + } else if(this.propertyOwnerType == "policy"){ + this.ComponentInstanceServiceNg2.updateComponentPolicyInstanceProperties(this.component, this.propertyOwnerId, [property]) + .subscribe((propertiesFromBE) => { onPropertySuccess(<PropertyModel>propertiesFromBE[0])}, error => onPropertyFaild); } else { - if (!this.$scope.editPropertyModel.property.simpleType && !this.$scope.isSimpleType(property.type)) { - let myValueString:string = JSON.stringify(this.$scope.myValue); - property.defaultValue = myValueString; + //in case we have uniqueId we call update method + if (this.$scope.isPropertyValueOwner) { + if (!this.$scope.editPropertyModel.property.simpleType && !this.$scope.isSimpleType(property.type)) { + let myValueString:string = JSON.stringify(this.$scope.myValue); + property.value = myValueString; + } + this.component.updateInstanceProperties(property.resourceInstanceUniqueId, [property]).then((propertiesFromBE) => onPropertySuccess(propertiesFromBE[0]), onPropertyFaild); } else { - this.$scope.editPropertyModel.property.defaultValue = this.$scope.editPropertyModel.property.value; + if (!this.$scope.editPropertyModel.property.simpleType && !this.$scope.isSimpleType(property.type)) { + let myValueString:string = JSON.stringify(this.$scope.myValue); + property.defaultValue = myValueString; + } else { + this.$scope.editPropertyModel.property.defaultValue = this.$scope.editPropertyModel.property.value; + } + this.component.addOrUpdateProperty(property).then(onPropertySuccess, onPropertyFaild); } - this.component.addOrUpdateProperty(property).then(onPropertySuccess, onPropertyFaild); } }; diff --git a/catalog-ui/src/app/view-models/forms/property-forms/component-property-form/property-form-view.html b/catalog-ui/src/app/view-models/forms/property-forms/component-property-form/property-form-view.html index 743de298cd..37a265a098 100644 --- a/catalog-ui/src/app/view-models/forms/property-forms/component-property-form/property-form-view.html +++ b/catalog-ui/src/app/view-models/forms/property-forms/component-property-form/property-form-view.html @@ -1,8 +1,8 @@ -<sdc-modal modal="modalInstanceProperty" type="classic" class="sdc-edit-property-container" buttons="footerButtons" header="{{isNew ? 'Add' : 'Update' }} Property" show-close-button="true" data-tests-id="sdc-edit-property-container"> +<ng1-modal modal="modalInstanceProperty" type="classic" class="sdc-edit-property-container" buttons="footerButtons" header="{{isNew ? 'Add' : 'Update' }} Property" show-close-button="true" data-tests-id="sdc-edit-property-container"> <loader data-display="isLoading" relative="false" size="medium"></loader> <div class="sdc-modal-top-bar" data-ng-if="!isNew"> <div class="sdc-modal-top-bar-buttons"> - <span ng-click="delete(editPropertyModel.property)" data-ng-class="{'disabled' : isPropertyValueOwner || editPropertyModel.property.readonly}" class="sprite-new delete-btn" data-tests-id="delete_property" sdc-smart-tooltip="">Delete</span> + <span ng-click="delete(editPropertyModel.property)" data-ng-class="{'disabled' : isPropertyValueOwner || editPropertyModel.property.readonly || propertyOwnerType == 'group' || propertyOwnerType == 'policy'}" class="sprite-new delete-btn" data-tests-id="delete_property" sdc-smart-tooltip="">Delete</span> <span class="delimiter"></span> <span data-ng-click="getPrev()" data-ng-class="{'disabled' : !currentPropertyIndex }" class="sprite-new left-arrow" data-tests-id="get-prev" sdc-smart-tooltip="">Previous</span> <span data-ng-click="getNext()" data-ng-class="{'disabled' : isLastProperty }" class="sprite-new right-arrow" data-tests-id="get-next" sdc-smart-tooltip="">Next</span> @@ -198,4 +198,4 @@ </perfect-scrollbar> </div> -</sdc-modal> +</ng1-modal> diff --git a/catalog-ui/src/app/view-models/forms/property-forms/module-property-modal/module-property-model.ts b/catalog-ui/src/app/view-models/forms/property-forms/module-property-modal/module-property-model.ts index 510814b333..2437f4612c 100644 --- a/catalog-ui/src/app/view-models/forms/property-forms/module-property-modal/module-property-model.ts +++ b/catalog-ui/src/app/view-models/forms/property-forms/module-property-modal/module-property-model.ts @@ -71,7 +71,7 @@ export class ModulePropertyView extends PropertyFormBaseView { save(isNeedToCloseModal):ng.IPromise<boolean> { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<boolean>(); let onSuccess = (properties:Array<PropertyModel>):void => { deferred.resolve(true); diff --git a/catalog-ui/src/app/view-models/forms/property-forms/select-datatype-modal/select-datatype-modal-view-model.ts b/catalog-ui/src/app/view-models/forms/property-forms/select-datatype-modal/select-datatype-modal-view-model.ts index 8d5c30a6fe..ab4b033c0e 100644 --- a/catalog-ui/src/app/view-models/forms/property-forms/select-datatype-modal/select-datatype-modal-view-model.ts +++ b/catalog-ui/src/app/view-models/forms/property-forms/select-datatype-modal/select-datatype-modal-view-model.ts @@ -67,7 +67,7 @@ export class SelectDataTypeViewModel extends PropertyFormBaseView { //scope methods save(isNeedToCloseModal):ng.IPromise<boolean> { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<boolean>(); this.$scope.property.propertiesName = this.DataTypesService.selectedPropertiesName; this.$scope.property.input = this.DataTypesService.selectedInput; this.$scope.property.isAlreadySelected = true; diff --git a/catalog-ui/src/app/view-models/forms/resource-instance-name-form/resource-instance-name-view.html b/catalog-ui/src/app/view-models/forms/resource-instance-name-form/resource-instance-name-view.html index e04343adbd..969d1d91d5 100644 --- a/catalog-ui/src/app/view-models/forms/resource-instance-name-form/resource-instance-name-view.html +++ b/catalog-ui/src/app/view-models/forms/resource-instance-name-form/resource-instance-name-view.html @@ -1,4 +1,4 @@ -<sdc-modal modal="modalInstanceName" type="classic" class="w-sdc-modal-resource-instance-name modal-type-confirmation" buttons="footerButtons" header="Instance Name" show-close-button="true"> +<ng1-modal modal="modalInstanceName" type="classic" class="w-sdc-modal-resource-instance-name modal-type-confirmation" buttons="footerButtons" header="Instance Name" show-close-button="true"> <form novalidate class="w-sdc-form" name="forms.editNameForm"> <div class="i-sdc-form-item" data-ng-class="{error:(editNameForm.componentInstanceName.$dirty && editNameForm.resourceInstanceName.$invalid)}"> @@ -25,7 +25,7 @@ </div> </form> -</sdc-modal> +</ng1-modal> diff --git a/catalog-ui/src/app/view-models/modals/confirmation-modal/confirmation-modal-view.html b/catalog-ui/src/app/view-models/modals/confirmation-modal/confirmation-modal-view.html index 09c27f8cd3..e6b31d5a47 100644 --- a/catalog-ui/src/app/view-models/modals/confirmation-modal/confirmation-modal-view.html +++ b/catalog-ui/src/app/view-models/modals/confirmation-modal/confirmation-modal-view.html @@ -1,4 +1,4 @@ -<sdc-modal modal="modalInstanceConfirmation" type="classic" class="w-sdc-modal-confirmation modal-type-{{confirmationModalModel.type}}" header="{{confirmationModalModel.title}}" show-close-button="true"> +<ng1-modal modal="modalInstanceConfirmation" type="classic" class="w-sdc-modal-confirmation modal-type-{{confirmationModalModel.type}}" header="{{confirmationModalModel.title}}" show-close-button="true"> <form novalidate class="w-sdc-form" name="editForm"> <label class="i-sdc-form-label required w-sdc-modal-label" data-ng-bind-html="confirmationModalModel.message"></label> @@ -24,6 +24,6 @@ <div class="w-sdc-modal-footer classic"> <button class="tlv-btn {{okButtonColor}}" data-tests-id="OK" data-ng-click="ok()" data-ng-disabled="confirmationModalModel.showComment===true && (!comment.text || comment.text && comment.text.length===0)">OK</button> <button class="tlv-btn grey" data-ng-if="hideCancelButton===false" data-tests-id="Cancel" data-ng-click="cancel()" >Cancel</button> - <button class="tlv-btn blue add-property-add-another" data-ng-if="isNew" data-ng-click="saveAndAnother()" type="reset" data-ng-disabled="editForm.$invalid">Add Another</button> + <!--<button class="tlv-btn blue add-property-add-another" data-ng-if="isNew" data-ng-click="saveAndAnother()" type="reset" data-ng-disabled="editForm.$invalid">Add Another</button>--> </div> -</sdc-modal> +</ng1-modal> diff --git a/catalog-ui/src/app/view-models/modals/conformance-level-modal/conformance-level-modal-view.html b/catalog-ui/src/app/view-models/modals/conformance-level-modal/conformance-level-modal-view.html index 3577e4d77b..59a13bc72a 100644 --- a/catalog-ui/src/app/view-models/modals/conformance-level-modal/conformance-level-modal-view.html +++ b/catalog-ui/src/app/view-models/modals/conformance-level-modal/conformance-level-modal-view.html @@ -1,4 +1,4 @@ -<sdc-modal modal="modalInstance" +<ng1-modal modal="modalInstance" type="classic" class="w-sdc-modal modal-type-alert conformance-level-modal" header="Warning" @@ -19,4 +19,4 @@ </div> </perfect-scrollbar> -</sdc-modal> +</ng1-modal> diff --git a/catalog-ui/src/app/view-models/modals/email-modal/email-modal-view.html b/catalog-ui/src/app/view-models/modals/email-modal/email-modal-view.html index bf65428033..0354e62063 100644 --- a/catalog-ui/src/app/view-models/modals/email-modal/email-modal-view.html +++ b/catalog-ui/src/app/view-models/modals/email-modal/email-modal-view.html @@ -1,4 +1,4 @@ -<sdc-modal modal="modalInstanceEmail" type="classic" class="w-sdc-modal-email modal-type-standard" header="{{emailModalModel.title}}" show-close-button="true"> +<ng1-modal modal="modalInstanceEmail" type="classic" class="w-sdc-modal-email modal-type-standard" header="{{emailModalModel.title}}" show-close-button="true"> <loader data-display="isLoading"></loader> <form novalidate class="w-sdc-form" name="editForm"> @@ -74,4 +74,4 @@ <button class="tlv-btn blue" data-tests-id="OK" data-ng-click="submit()" data-ng-disabled="editForm.$invalid">OK</button> <button class="tlv-btn grey" data-tests-id="Cancel" data-ng-click="cancel()" >Cancel</button> </div> -</sdc-modal> +</ng1-modal> diff --git a/catalog-ui/src/app/view-models/modals/error-modal/error-403-view.html b/catalog-ui/src/app/view-models/modals/error-modal/error-403-view.html index 41b1c6df1d..08f3ef4952 100644 --- a/catalog-ui/src/app/view-models/modals/error-modal/error-403-view.html +++ b/catalog-ui/src/app/view-models/modals/error-modal/error-403-view.html @@ -1,4 +1,4 @@ <div class="sdc-error-403-container" > <div class="sdc-error-403-container-title" translate="GENERAL_ERROR_403_TITLE"></div> - <div class="w-sdc-error-403-text w-sdc-form" translate="GENERAL_ERROR_403_DESCRIPTION" translate-values="{{ mailtoJson }}"></div> + <div class="w-sdc-error-403-text w-sdc-form" translate="GENERAL_ERROR_403_DESCRIPTION" translate-values="{'mailto': mailto }"></div> </div> diff --git a/catalog-ui/src/app/view-models/modals/error-modal/error.less b/catalog-ui/src/app/view-models/modals/error-modal/error.less index 8297b5053d..1843ea34bc 100644 --- a/catalog-ui/src/app/view-models/modals/error-modal/error.less +++ b/catalog-ui/src/app/view-models/modals/error-modal/error.less @@ -1,10 +1,17 @@ .sdc-error-403-container { .bg_n; width: 700px; - height: 400px; margin: auto; margin-top: 196px; + padding: 40px; + box-shadow: #999 2px 2px 10px; + text-align: center; + .sdc-error-403-container-title { + font-size: 24px; + text-transform: uppercase; + } + .w-sdc-error-403-text { .q_11; margin-top: 20px; diff --git a/catalog-ui/src/app/view-models/modals/icons-modal/icons-modal-view.html b/catalog-ui/src/app/view-models/modals/icons-modal/icons-modal-view.html index 4b89701201..aa9230f9d9 100644 --- a/catalog-ui/src/app/view-models/modals/icons-modal/icons-modal-view.html +++ b/catalog-ui/src/app/view-models/modals/icons-modal/icons-modal-view.html @@ -1,4 +1,4 @@ -<sdc-modal modal="modalIcons" type="classic" class="w-sdc-modal-icons" buttons="footerButtons" header="Choose Icon" show-close-button="true"> +<ng1-modal modal="modalIcons" type="classic" class="w-sdc-modal-icons" buttons="footerButtons" header="Choose Icon" show-close-button="true"> <div class="suggested-icons-container"> <div class ="suggested-icon-wrapper" data-ng-class="{'selected': selectedIcon == iconSrc}" data-ng-repeat="iconSrc in icons track by $index"> @@ -15,4 +15,4 @@ <button class="tlv-btn blue" data-tests-id="OK" data-ng-click="updateIcon()">OK</button> <button class="tlv-btn grey" data-tests-id="Cancel" data-ng-click="cancel()" >Cancel</button> </div> -</sdc-modal> +</ng1-modal> diff --git a/catalog-ui/src/app/view-models/modals/message-modal/message-client-modal/client-message-modal-view.html b/catalog-ui/src/app/view-models/modals/message-modal/message-client-modal/client-message-modal-view.html index cfb0a35f69..421391e923 100644 --- a/catalog-ui/src/app/view-models/modals/message-modal/message-client-modal/client-message-modal-view.html +++ b/catalog-ui/src/app/view-models/modals/message-modal/message-client-modal/client-message-modal-view.html @@ -1,4 +1,4 @@ -<sdc-modal modal="modalInstanceError" +<ng1-modal modal="modalInstanceError" type="classic" class="w-sdc-modal modal-type-alert" header="{{messageModalModel.title}}" @@ -13,4 +13,4 @@ <!--<div class="w-sdc-modal-body-content" data-ng-bind-html="messageModalModel.message"></div>--> </perfect-scrollbar> -</sdc-modal> +</ng1-modal> diff --git a/catalog-ui/src/app/view-models/modals/message-modal/message-server-modal/server-message-modal-view-model.ts b/catalog-ui/src/app/view-models/modals/message-modal/message-server-modal/server-message-modal-view-model.ts index e3c6ad1c55..b92069fce2 100644 --- a/catalog-ui/src/app/view-models/modals/message-modal/message-server-modal/server-message-modal-view-model.ts +++ b/catalog-ui/src/app/view-models/modals/message-modal/message-server-modal/server-message-modal-view-model.ts @@ -24,6 +24,8 @@ import {IMessageModalModel, IMessageModalViewModelScope, MessageModalViewModel} export interface IServerMessageModalModel extends IMessageModalModel { status:string; messageId:string; + + } export interface IServerMessageModalViewModelScope extends IMessageModalViewModelScope { diff --git a/catalog-ui/src/app/view-models/modals/message-modal/message-server-modal/server-message-modal-view.html b/catalog-ui/src/app/view-models/modals/message-modal/message-server-modal/server-message-modal-view.html index 294dc76c4c..524551bcc8 100644 --- a/catalog-ui/src/app/view-models/modals/message-modal/message-server-modal/server-message-modal-view.html +++ b/catalog-ui/src/app/view-models/modals/message-modal/message-server-modal/server-message-modal-view.html @@ -1,4 +1,4 @@ -<sdc-modal modal="modalInstanceError" +<ng1-modal modal="modalInstanceError" type="classic" class="w-sdc-modal modal-type-error" header="{{messageModalModel.title}}" @@ -14,4 +14,4 @@ <div class="w-sdc-modal-body-content" data-ng-bind-html="messageModalModel.message" data-tests-id="message"></div> </perfect-scrollbar> -</sdc-modal> +</ng1-modal> 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 index 1cc3690e9f..46b258f0bd 100644 --- 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 @@ -19,7 +19,7 @@ */ 'use strict'; -import {ComponentType, CHANGE_COMPONENT_CSAR_VERSION_FLAG, SEVERITY, FileUtils, ModalsHandler, ComponentFactory} from "app/utils"; +import {ComponentType, 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"; @@ -63,6 +63,7 @@ export class OnboardingModalViewModel { 'Sdc.Services.OnboardingService', 'okButtonText', 'currentCsarUUID', + 'currentCsarVersion', 'Sdc.Services.CacheService', 'FileUtils', 'ComponentFactory', @@ -77,6 +78,7 @@ export class OnboardingModalViewModel { private onBoardingService:OnboardingService, private okButtonText:string, private currentCsarUUID:string, + private currentCsarVersion:string, private cacheService:CacheService, private fileUtils:FileUtils, private componentFactory:ComponentFactory, @@ -107,28 +109,27 @@ export class OnboardingModalViewModel { // 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.$uibModalInstance.close({ + componentCsar: this.$scope.selectedComponent, + type: ComponentType.RESOURCE.toLowerCase() }); }; 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, - componentCsar: this.$scope.selectedComponent, - type: this.$scope.componentFromServer.componentType.toLowerCase(), - disableButtons: true - }); + if(!this.currentCsarVersion || this.currentCsarVersion != (<Resource>this.$scope.selectedComponent).csarVersion) { + this.$uibModalInstance.close({ + componentCsar: this.$scope.selectedComponent, + previousComponent: this.$scope.componentFromServer, + type: this.$scope.componentFromServer.componentType.toLowerCase() + + }); + + } else { + this.$uibModalInstance.close(); + } }; this.$scope.downloadCsar = (packageId:string):void => { 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 index b078a4b1ef..a69d0a8f3c 100644 --- 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 @@ -1,4 +1,4 @@ -<sdc-modal modal="modalOnboarding" class="w-sdc-modal-onboarding w-sdc-classic-top-line-modal" buttons="footerButtons" header="Import VF" show-close-button="true"> +<ng1-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> @@ -141,4 +141,4 @@ </div><!-- End table-container-flex --> <div class="w-sdc-modal-footer classic"></div> -</sdc-modal> +</ng1-modal> diff --git a/catalog-ui/src/app/view-models/tabs/hierarchy/hierarchy-view-model.ts b/catalog-ui/src/app/view-models/tabs/hierarchy/hierarchy-view-model.ts index c438c7ace6..f752e3dba7 100644 --- a/catalog-ui/src/app/view-models/tabs/hierarchy/hierarchy-view-model.ts +++ b/catalog-ui/src/app/view-models/tabs/hierarchy/hierarchy-view-model.ts @@ -23,6 +23,10 @@ import {ModalsHandler} from "app/utils"; import {PropertyModel, DisplayModule, Component, ComponentInstance, Tab, Module} from "app/models"; import {ExpandCollapseListData} from "app/directives/utils/expand-collapse-list-header/expand-collapse-list-header"; +interface IComponentInstancesMap { + [key:string]: ComponentInstance +} + export interface IHierarchyScope extends ng.IScope { component:Component; selectedIndex:number; @@ -32,8 +36,9 @@ export interface IHierarchyScope extends ng.IScope { expandCollapseArtifactsList:ExpandCollapseListData; expandCollapsePropertiesList:ExpandCollapseListData; selectedInstanceId:string; + componentInstancesMap:IComponentInstancesMap; - onModuleSelected(moduleId:string, selectedIndex:number):void; + onModuleSelected(module:Module, selectedIndex:number, componentInstanceId?:string):void; onModuleNameChanged(module:DisplayModule):void; updateHeatName():void; loadInstanceModules(instance:ComponentInstance):ng.IPromise<boolean>; @@ -53,6 +58,7 @@ export class HierarchyViewModel { this.$scope.isLoading = false; this.$scope.expandCollapseArtifactsList = new ExpandCollapseListData(); this.$scope.expandCollapsePropertiesList = new ExpandCollapseListData(); + this.$scope.componentInstancesMap = <IComponentInstancesMap>{}; this.initScopeMethods(); } @@ -65,7 +71,7 @@ export class HierarchyViewModel { this.$scope.expandCollapsePropertiesList.orderByField = "name"; }; - this.$scope.onModuleSelected = (moduleId:string, selectedIndex:number, componentInstanceId?:string):void => { + this.$scope.onModuleSelected = (module:Module, selectedIndex:number, componentInstanceId?:string):void => { let onSuccess = (module:DisplayModule) => { console.log("Module Loaded: ", module); @@ -79,15 +85,25 @@ export class HierarchyViewModel { }; this.$scope.selectedIndex = selectedIndex; - if (!this.$scope.selectedModule || (this.$scope.selectedModule && this.$scope.selectedModule.uniqueId != moduleId)) { + if (!this.$scope.selectedModule || (this.$scope.selectedModule && this.$scope.selectedModule.uniqueId != module.uniqueId)) { this.$scope.isLoading = true; if (this.$scope.component.isService()) { this.$scope.selectedInstanceId = componentInstanceId; - this.$scope.component.getModuleInstanceForDisplay(componentInstanceId, moduleId).then(onSuccess, onFailed); + this.$scope.component.getModuleInstanceForDisplay(componentInstanceId, module.uniqueId).then(onSuccess, onFailed); } else { - this.$scope.component.getModuleForDisplay(moduleId).then(onSuccess, onFailed); + this.$scope.component.getModuleForDisplay(module.uniqueId).then(onSuccess, onFailed); } } + + const componentInstances: Array<ComponentInstance> = this.$scope.component.componentInstances || []; + (<string[]>_.values(module.members)).forEach((memberId) => { + if (!(memberId in this.$scope.componentInstancesMap)) { + const compInstance = componentInstances.find((c) => c.uniqueId === memberId); + if (compInstance) { + this.$scope.componentInstancesMap[compInstance.uniqueId] = compInstance; + } + } + }); }; this.$scope.updateHeatName = () => { diff --git a/catalog-ui/src/app/view-models/tabs/hierarchy/hierarchy-view.html b/catalog-ui/src/app/view-models/tabs/hierarchy/hierarchy-view.html index 3b7b5fc36a..7a3874ee08 100644 --- a/catalog-ui/src/app/view-models/tabs/hierarchy/hierarchy-view.html +++ b/catalog-ui/src/app/view-models/tabs/hierarchy/hierarchy-view.html @@ -11,8 +11,8 @@ <expand-collapse expanded-selector=".hierarchy-module-member-list.{{$index}}" class="general-tab-expand-collapse" is-close-on-init="true" data-tests-id="hierarchy-module-{{$index}}" - data-ng-repeat-start="module in component.groups"> - <div class="expand-collapse-title first-level" data-tests-id="hierarchy-module-{{$index}}-title" ng-class="{'selected': selectedIndex === $index}" data-ng-click="onModuleSelected(module.uniqueId, $index)"> + data-ng-repeat-start="module in component.modules"> + <div class="expand-collapse-title first-level" data-tests-id="hierarchy-module-{{$index}}-title" ng-class="{'selected': selectedIndex === $index}" data-ng-click="onModuleSelected(module, $index)"> <div class="expand-collapse-title-icon"></div> <span class="expand-collapse-title-text" data-ng-bind="module.name" tooltips tooltip-content="{{module.name}}"></span> @@ -21,8 +21,8 @@ </expand-collapse> <div data-ng-repeat-end="" class="hierarchy-module-member-list {{$index}}"> - <div ng-repeat="(memberName, value) in ::module.members track by $index"> - <div class="expand-collapse-sub-title" tooltips tooltip-content="{{memberName}}">{{memberName}}</div> + <div ng-repeat="memberId in ::module.members track by $index"> + <div class="expand-collapse-sub-title" tooltips tooltip-content="{{componentInstancesMap[memberId].name}}">{{componentInstancesMap[memberId].name}}</div> </div> </div> </perfect-scrollbar> @@ -48,7 +48,7 @@ class="general-tab-expand-collapse" is-close-on-init="true" data-tests-id="hierarchy-module-{{$index}}" data-ng-repeat-start="module in instance.groupInstances"> - <div class="expand-collapse-title second-level" data-tests-id="hierarchy-module-{{$index}}-title" ng-class="{'selected': selectedIndex === $index && selectedInstanceId === instance.uniqueId}" data-ng-click="onModuleSelected(module.uniqueId, $index, instance.uniqueId)"> + <div class="expand-collapse-title second-level" data-tests-id="hierarchy-module-{{$index}}-title" ng-class="{'selected': selectedIndex === $index && selectedInstanceId === instance.uniqueId}" data-ng-click="onModuleSelected(module, $index, instance.uniqueId)"> <div class="expand-collapse-title-icon"></div> <span class="expand-collapse-title-text" data-ng-bind="module.name" tooltips tooltip-content="{{module.name}}"></span> @@ -56,8 +56,8 @@ </expand-collapse> <div data-ng-repeat-end="" class="outer-index-{{$parent.$index}} hierarchy-module-member-list {{$index}}"> - <div ng-repeat="(memberName, value) in ::module.members track by $index"> - <div class="expand-collapse-sub-title" tooltips tooltip-content="{{memberName}}">{{memberName}}</div> + <div ng-repeat="memberId in ::module.members track by $index"> + <div class="expand-collapse-sub-title" tooltips tooltip-content="{{componentInstancesMap[memberId].name}}">{{componentInstancesMap[memberId].name}}</div> </div> </div> </div> diff --git a/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view-model.ts index 46c2d2edf9..a77377bac4 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view-model.ts @@ -19,22 +19,34 @@ */ 'use strict'; import * as _ from "lodash"; -import {Component, ComponentInstance, IAppMenu} from "app/models"; -import {SharingService, CacheService, EventListenerService, LeftPaletteLoaderService} from "app/services"; -import {ModalsHandler, GRAPH_EVENTS, ComponentFactory, ChangeLifecycleStateHandler, MenuHandler, EVENTS} from "app/utils"; -import {IWorkspaceViewModelScope} from "../../workspace-view-model"; -import {ComponentGenericResponse} from "app/ng2/services/responses/component-generic-response"; -import {Resource} from "app/models/components/resource"; -import {ResourceType,ComponentType} from "app/utils/constants"; -import {ComponentServiceFactoryNg2} from "app/ng2/services/component-services/component.service.factory"; -import {ServiceGenericResponse} from "app/ng2/services/responses/service-generic-response"; -import {Service} from "app/models/components/service"; +import { Component, ComponentInstance, IAppMenu, Requirement, Capability, ButtonModel } from "app/models"; +import { SharingService, CacheService, EventListenerService, LeftPaletteLoaderService } from "app/services"; +import { ModalsHandler, GRAPH_EVENTS, ComponentFactory, ChangeLifecycleStateHandler, MenuHandler, EVENTS, ComponentInstanceFactory } from "app/utils"; +import { IWorkspaceViewModelScope } from "../../workspace-view-model"; +import { ComponentGenericResponse } from "app/ng2/services/responses/component-generic-response"; +import { Resource } from "app/models/components/resource"; +import { ResourceType, ComponentType } from "app/utils/constants"; +import { ComponentServiceFactoryNg2 } from "app/ng2/services/component-services/component.service.factory"; +import { ServiceGenericResponse } from "app/ng2/services/responses/service-generic-response"; +import { Service } from "app/models/components/service"; +import { ZoneInstance } from "app/models/graph/zones/zone-instance"; +import { ComponentServiceNg2 } from "app/ng2/services/component-services/component.service"; +import { ModalService as ModalServiceSdcUI} from "sdc-ui/lib/angular/modals/modal.service" +import { IModalConfig, IModalButtonComponent } from "sdc-ui/lib/angular/modals/models/modal-config"; +import { ValueEditComponent } from "app/ng2/components/ui/forms/value-edit/value-edit.component"; +import { UnsavedChangesComponent } from "../../../../ng2/components/ui/forms/unsaved-changes/unsaved-changes.component"; +import { ModalButtonComponent } from "sdc-ui/lib/angular/components"; + export interface ICompositionViewModelScope extends IWorkspaceViewModelScope { currentComponent:Component; + + //Added for now, in the future need to remove and use only id and type to pass to tabs. selectedComponent: Component; + selectedZoneInstance: ZoneInstance; + componentInstanceNames: Array<string>; isLoading:boolean; graphApi:any; @@ -42,21 +54,24 @@ export interface ICompositionViewModelScope extends IWorkspaceViewModelScope { sdcMenu:IAppMenu; version:string; isViewOnly:boolean; + isCanvasTagging:boolean; isLoadingRightPanel:boolean; disabledTabs:boolean; openVersionChangeModal(pathsToDelete:string[]):ng.IPromise<any>; onComponentInstanceVersionChange(component:Component); isComponentInstanceSelected():boolean; - updateSelectedComponent():void + updateSelectedComponent():void; openUpdateModal(); deleteSelectedComponentInstance():void; onBackgroundClick():void; setSelectedInstance(componentInstance:ComponentInstance):void; + setSelectedZoneInstance(zoneInstance: ZoneInstance):void; + changeZoneInstanceName(newName:string):void; printScreen():void; isPNF():boolean; isConfiguration():boolean; preventMoveTab(state: boolean):void; - + ComponentServiceNg2:ComponentServiceNg2, cacheComponentsInstancesFullData:Component; } @@ -76,8 +91,11 @@ export class CompositionViewModel { 'ChangeLifecycleStateHandler', 'LeftPaletteLoaderService', 'ModalsHandler', + 'ModalServiceSdcUI', 'EventListenerService', - 'ComponentServiceFactoryNg2' + 'ComponentServiceFactoryNg2', + 'ComponentServiceNg2', + 'Notification' ]; constructor(private $scope:ICompositionViewModelScope, @@ -93,8 +111,12 @@ export class CompositionViewModel { private ChangeLifecycleStateHandler:ChangeLifecycleStateHandler, private LeftPaletteLoaderService:LeftPaletteLoaderService, private ModalsHandler:ModalsHandler, + private ModalServiceSdcUI: ModalServiceSdcUI, private eventListenerService:EventListenerService, - private ComponentServiceFactoryNg2: ComponentServiceFactoryNg2) { + private ComponentServiceFactoryNg2: ComponentServiceFactoryNg2, + private ComponentServiceNg2:ComponentServiceNg2, + private Notification:any + ) { this.$scope.setValidState(true); this.initScope(); @@ -104,16 +126,17 @@ export class CompositionViewModel { private initGraphData = ():void => { - if(!this.$scope.component.componentInstances || !this.$scope.component.componentInstancesRelations ) { + if(!this.hasCompositionGraphData(this.$scope.component)) { this.$scope.isLoading = true; let service = this.ComponentServiceFactoryNg2.getComponentService(this.$scope.component); service.getComponentCompositionData(this.$scope.component).subscribe((response:ComponentGenericResponse) => { if (this.$scope.component.isService()) { (<Service> this.$scope.component).forwardingPaths = (<ServiceGenericResponse>response).forwardingPaths; } - this.$scope.component.componentInstances = response.componentInstances; - this.$scope.component.componentInstancesRelations = response.componentInstancesRelations; - this.$scope.component.policies = response.policies; + this.$scope.component.componentInstances = response.componentInstances || []; + this.$scope.component.componentInstancesRelations = response.componentInstancesRelations || []; + this.$scope.component.policies = response.policies || []; + this.$scope.component.groupInstances = response.groupInstances || []; this.$scope.isLoading = false; this.initComponent(); this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_COMPOSITION_GRAPH_DATA_LOADED); @@ -124,25 +147,134 @@ export class CompositionViewModel { this.eventListenerService.unRegisterObserver(GRAPH_EVENTS.ON_COMPOSITION_GRAPH_DATA_LOADED); }; + private hasCompositionGraphData = (component:Component):boolean => { + return !!(component.componentInstances && component.componentInstancesRelations && component.policies && component.groupInstances); + }; private cacheComponentsInstancesFullData:Array<Component>; private initComponent = ():void => { this.$scope.currentComponent = this.$scope.component; this.$scope.selectedComponent = this.$scope.currentComponent; + this.$scope.selectedZoneInstance = null; this.updateUuidMap(); this.$scope.isViewOnly = this.$scope.isViewMode(); }; private registerGraphEvents = (scope:ICompositionViewModelScope):void => { this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_NODE_SELECTED, scope.setSelectedInstance); + this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_ZONE_INSTANCE_SELECTED, scope.setSelectedZoneInstance); this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_GRAPH_BACKGROUND_CLICKED, scope.onBackgroundClick); + this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_CANVAS_TAG_START, () => { + scope.isCanvasTagging = true; + this.eventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, true, this.showUnsavedChangesAlert); + }); + this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_CANVAS_TAG_END, () => { + scope.isCanvasTagging = false; + this.resetUnsavedChanges(); + }); + this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_ZONE_INSTANCE_NAME_CHANGED, scope.changeZoneInstanceName); + this.eventListenerService.registerObserverCallback(EVENTS.UPDATE_PANEL, this.removeSelectedZoneInstance); }; - private openUpdateComponentInstanceNameModal = ():void => { - this.ModalsHandler.openUpdateComponentInstanceNameModal(this.$scope.currentComponent).then(()=> { - this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_COMPONENT_INSTANCE_NAME_CHANGED, this.$scope.currentComponent.selectedInstance); + private showUnsavedChangesAlert = (afterSave?:Function):Promise<any> => { + let deferred = new Promise<any>((resolve, reject)=> { + const modal = this.ModalServiceSdcUI.openCustomModal( + { + title: "Unsaved Changes", + size: 'sm', + type: 'custom', + + buttons: [ + {id: 'cancelButton', text: 'Cancel', type: 'secondary', size: 'xsm', closeModal: true, callback: () => reject()}, + {id: 'discardButton', text: 'Discard', type: 'secondary', size: 'xsm', closeModal: true, callback: () => { this.resetUnsavedChanges(); resolve()}}, + {id: 'saveButton', text: 'Save', type: 'primary', size: 'xsm', closeModal: true, callback: () => { reject(); this.saveUnsavedChanges(afterSave); }} + ] as IModalButtonComponent[] + }, UnsavedChangesComponent, { isValidChangedData: true}); }); + + return deferred; + } + + private unRegisterGraphEvents = (scope: ICompositionViewModelScope):void => { + this.eventListenerService.unRegisterObserver(GRAPH_EVENTS.ON_NODE_SELECTED, scope.setSelectedInstance); + this.eventListenerService.unRegisterObserver(GRAPH_EVENTS.ON_ZONE_INSTANCE_SELECTED, scope.setSelectedZoneInstance); + this.eventListenerService.unRegisterObserver(GRAPH_EVENTS.ON_GRAPH_BACKGROUND_CLICKED, scope.onBackgroundClick); + this.eventListenerService.unRegisterObserver(GRAPH_EVENTS.ON_CANVAS_TAG_START); + this.eventListenerService.unRegisterObserver(GRAPH_EVENTS.ON_CANVAS_TAG_END); + this.eventListenerService.unRegisterObserver(GRAPH_EVENTS.ON_ZONE_INSTANCE_NAME_CHANGED, scope.changeZoneInstanceName); + this.eventListenerService.unRegisterObserver(EVENTS.UPDATE_PANEL, this.removeSelectedZoneInstance); + + }; + + private resetUnsavedChanges = () => { + this.eventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, false); + } + + private saveUnsavedChanges = (afterSaveFunction?:Function):void => { + this.$scope.selectedZoneInstance.forceSave.next(afterSaveFunction); + this.eventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, false); + } + + private openUpdateComponentInstanceNameModal = ():void => { + + let modalConfig:IModalConfig = { + title: "Edit Name", + size: "sm", + type: "custom", + testId: "renameInstanceModal", + buttons: [ + {id: 'saveButton', text: 'OK', size: 'xsm', callback: this.saveInstanceName, closeModal: false}, + {id: 'cancelButton', text: 'Cancel', size: 'sm', closeModal: true} + ] + }; + + this.ModalServiceSdcUI.openCustomModal(modalConfig, ValueEditComponent, {name: this.$scope.currentComponent.selectedInstance.name, validityChangedCallback: this.enableOrDisableSaveButton}); + + }; + + + private enableOrDisableSaveButton = (shouldEnable: boolean): void => { + let saveButton: ModalButtonComponent = this.ModalServiceSdcUI.getCurrentInstance().getButtonById('saveButton'); + saveButton.disabled = !shouldEnable; + } + + private saveInstanceName = () => { + let currentModal = this.ModalServiceSdcUI.getCurrentInstance(); + let nameFromModal:string = currentModal.innerModalContent.instance.name; + + if(nameFromModal != this.$scope.currentComponent.selectedInstance.name){ + currentModal.buttons[0].disabled = true; + let componentInstanceModel:ComponentInstance = ComponentInstanceFactory.createComponentInstance(this.$scope.currentComponent.selectedInstance); + componentInstanceModel.name = nameFromModal; + + let onFailed = (error) => { + currentModal.buttons[0].disabled = false; + }; + let onSuccess = (componentInstance:ComponentInstance) => { + + this.$scope.currentComponent.selectedInstance.name = componentInstance.name; + //update requirements and capabilities owner name + _.forEach(this.$scope.currentComponent.selectedInstance.requirements, (requirementsArray:Array<Requirement>) => { + _.forEach(requirementsArray, (requirement:Requirement):void => { + requirement.ownerName = componentInstance.name; + }); + }); + + _.forEach(this.$scope.currentComponent.selectedInstance.capabilities, (capabilitiesArray:Array<Capability>) => { + _.forEach(capabilitiesArray, (capability:Capability):void => { + capability.ownerName = componentInstance.name; + }); + }); + this.ModalServiceSdcUI.closeModal(); + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_COMPONENT_INSTANCE_NAME_CHANGED, this.$scope.currentComponent.selectedInstance); + }; + + this.$scope.currentComponent.updateComponentInstance(componentInstanceModel).then(onSuccess, onFailed); + } else { + this.ModalServiceSdcUI.closeModal(); + } + }; private removeSelectedComponentInstance = ():void => { @@ -151,6 +283,12 @@ export class CompositionViewModel { this.$scope.selectedComponent = this.$scope.currentComponent; }; + private removeSelectedZoneInstance = ():void => { + this.$scope.currentComponent.selectedInstance = null; + this.$scope.selectedZoneInstance = null; + this.$scope.selectedComponent = this.$scope.currentComponent; + } + private updateUuidMap = ():void => { /** * In case user press F5, the page is refreshed and this.sharingService.currentEntity will be undefined, @@ -165,6 +303,7 @@ export class CompositionViewModel { this.$scope.sdcMenu = this.sdcMenu; this.$scope.isLoading = false; this.$scope.isLoadingRightPanel = false; + this.$scope.isCanvasTagging = false; this.$scope.graphApi = {}; this.$scope.version = this.cacheService.get('version'); this.initComponent(); @@ -175,6 +314,21 @@ export class CompositionViewModel { return this.$scope.currentComponent && this.$scope.currentComponent.selectedInstance != undefined && this.$scope.currentComponent.selectedInstance != null; }; + this.$scope.$on('$destroy', () => { + this.unRegisterGraphEvents(this.$scope); + }) + + this.$scope.restoreComponent = ():void => { + this.ComponentServiceNg2.restoreComponent(this.$scope.selectedComponent.componentType, this.$scope.selectedComponent.uniqueId).subscribe(() => { + this.Notification.success({ + message: '<' + this.$scope.component.name + '> ' + this.$filter('translate')("ARCHIVE_SUCCESS_MESSAGE_TEXT"), + title: this.$filter('translate')("ARCHIVE_SUCCESS_MESSAGE_TITLE") + }); + this.$scope.selectedComponent.archived = false; + } + ) + }; + this.$scope.updateSelectedComponent = ():void => { if (this.$scope.currentComponent.selectedInstance) { let parentComponentUid = this.$scope.currentComponent.selectedInstance.componentUid @@ -215,15 +369,25 @@ export class CompositionViewModel { this.$log.debug('composition-view-model::onNodeSelected:: with id: ' + selectedComponent.uniqueId); this.$scope.currentComponent.setSelectedInstance(selectedComponent); + this.$scope.selectedZoneInstance = null; this.$scope.updateSelectedComponent(); + + + if (this.$state.current.name === 'workspace.composition.api') { this.$state.go('workspace.composition.details'); } }; + this.$scope.setSelectedZoneInstance = (zoneInstance: ZoneInstance): void => { + this.$scope.currentComponent.selectedInstance = null; + this.$scope.selectedZoneInstance = zoneInstance; + }; + this.$scope.onBackgroundClick = ():void => { this.$scope.currentComponent.selectedInstance = null; + this.$scope.selectedZoneInstance = null; this.$scope.selectedComponent = this.$scope.currentComponent; if (this.$state.current.name === 'workspace.composition.api') { @@ -238,6 +402,10 @@ export class CompositionViewModel { this.$scope.openUpdateModal = ():void => { this.openUpdateComponentInstanceNameModal(); }; + + this.$scope.changeZoneInstanceName = (newName:string):void => { + this.$scope.selectedZoneInstance.instanceData.name = newName; + }; this.$scope.deleteSelectedComponentInstance = ():void => { const {currentComponent} = this.$scope; @@ -258,8 +426,7 @@ export class CompositionViewModel { modalText += `<p>The following service paths will be erased: ${pathNames}</p>`; } } - - this.ModalsHandler.openAlertModal(title, modalText).then(this.removeSelectedComponentInstance); + this.ModalServiceSdcUI.openAlertModal(title, modalText, "OK", this.removeSelectedComponentInstance, "deleteInstanceModal"); }; this.$scope.openVersionChangeModal = (pathsToDelete:string[]):ng.IPromise<any> => { @@ -308,7 +475,7 @@ export class CompositionViewModel { this.$scope.disabledTabs = state; }; - this.eventListenerService.registerObserverCallback(EVENTS.ON_CHECKOUT, this.$scope.reload); + this.eventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE, this.$scope.reload); } } diff --git a/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view.html b/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view.html index fceb73b882..4cd33f3210 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view.html +++ b/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view.html @@ -2,7 +2,7 @@ <loader data-display="isLoading"></loader> <div class="w-sdc-designer-canvas" data-ng-class="{sidebaractive: displayDesignerRightSidebar}"> <palette current-component="currentComponent" - is-view-only="isViewOnly" + is-view-only="isViewOnly || isCanvasTagging" is-loading="isLoading"></palette> <ng2-palette-popup-panel></ng2-palette-popup-panel> @@ -19,86 +19,107 @@ <div class="w-sdc-designer-sidebar" data-ng-class="{'view-mode':isViewOnly}"> - <div class="w-sdc-designer-sidebar-head" data-tests-id="w-sdc-designer-sidebar-head"> - <div class="w-sdc-designer-sidebar-logo-ph"> - <div class="large {{selectedComponent.iconSprite}} {{selectedComponent.icon}}"> - <div ng-if="isComponentInstanceSelected()" - data-ng-class="{'non-certified':'CERTIFIED' !== selectedComponent.lifecycleState}" - tooltips tooltip-side="top" tooltip-content="Not certified"></div> + <div ng-if="!selectedZoneInstance"> + + <div class="w-sdc-designer-sidebar-head" data-tests-id="w-sdc-designer-sidebar-head"> + <div class="w-sdc-designer-sidebar-logo-ph"> + <div class=" large {{selectedComponent.iconSprite}} {{selectedComponent.icon}}" + ng-class="{'archive-component':selectedComponent.archived}"> + <div ng-if="isComponentInstanceSelected()" + data-ng-class="{'non-certified':'CERTIFIED' !== selectedComponent.lifecycleState}" + tooltips tooltip-side="top" tooltip-content="Not certified"></div> + </div> </div> - </div> - <div class="w-sdc-designer-sidebar-logo"> - <span class="w-sdc-designer-sidebar-logo-title" data-tests-id="selectedCompTitle" tooltips - tooltip-class="tooltip-custom break-word-tooltip" - tooltip-content="​{{isComponentInstanceSelected() ? currentComponent.selectedInstance.name : currentComponent.name | resourceName}}" - data-ng-bind="isComponentInstanceSelected() ? currentComponent.selectedInstance.name : currentComponent.name | resourceName"></span> + <div class="w-sdc-designer-sidebar-logo"> + <span class="w-sdc-designer-sidebar-logo-title" data-tests-id="selectedCompTitle" tooltips + tooltip-class="tooltip-custom break-word-tooltip" + tooltip-content="​{{isComponentInstanceSelected() ? currentComponent.selectedInstance.name : currentComponent.name | resourceName}}" + data-ng-bind="isComponentInstanceSelected() ? currentComponent.selectedInstance.name : currentComponent.name | resourceName"></span> + </div> + <div class="sprite e-sdc-small-icon-pencil w-sdc-designer-update-resource-icon" + data-tests-id="renameInstance" + data-ng-if="!isViewOnly && isComponentInstanceSelected() && !selectedComponent.archived" + data-ng-click="openUpdateModal()" id="editPencil"></div> + + <div class="sprite e-sdc-small-icon-delete w-sdc-designer-delete-resource-icon" + data-tests-id="deleteInstance" + data-ng-if="!isViewOnly && isComponentInstanceSelected() && !selectedComponent.archived" + data-ng-click="!isLoading && deleteSelectedComponentInstance()" title="Delete Resource Instance"></div> </div> - <div class="sprite e-sdc-small-icon-pencil w-sdc-designer-update-resource-icon" - data-ng-if="!isViewOnly && isComponentInstanceSelected()" - data-ng-click="openUpdateModal()" id="editPencil"></div> - <div class="sprite e-sdc-small-icon-delete w-sdc-designer-delete-resource-icon" - data-tests-id="e-sdc-small-icon-delete" - data-ng-if="!isViewOnly && isComponentInstanceSelected()" - data-ng-click="!isLoading && deleteSelectedComponentInstance()" title="Delete Resource Instance"></div> - </div> + <div class="w-sdc-designer-sidebar-tabs"> + <button class="i-sdc-designer-sidebar-tab" data-ui-sref-active="active" + data-ui-sref="workspace.composition.details" + tooltips tooltip-class="tooltip-custom tab-tooltip" tooltip-content="Information" + data-tests-id="information-tab" + data-ng-class="{'disabled': disabledTabs}"> + <div class="i-sdc-designer-sidebar-tab-icon sprite-new info"></div> + </button> + <!--<button class="i-sdc-designer-sidebar-tab" data-ui-sref-active="active"--> + <!--ui-sref="workspace.composition.structure"--> + <!--tooltips tooltip-class="tooltip-custom tab-tooltip" tooltip-content="Composition">--> + <!--<div class="i-sdc-designer-sidebar-tab-icon sprite-new structure"></div>--> + <!--</button>--> + <button class="i-sdc-designer-sidebar-tab" data-ui-sref-active="active" + data-ui-sref="workspace.composition.deployment" + tooltips tooltip-class="tooltip-custom tab-tooltip" tooltip-content="Deployment Artifacts" + data-tests-id="deployment-artifact-tab" + data-ng-if="!isPNF() && !isConfiguration() && !(isComponentInstanceSelected() && currentComponent.selectedInstance.isServiceProxy())" + data-ng-class="{'disabled': disabledTabs}"> + <div class="i-sdc-designer-sidebar-tab-icon sprite-new deployment-artifacts"></div> + </button> + <button tooltips tooltip-class="tooltip-custom tab-tooltip" + tooltip-content="{{selectedComponent.isResource() || (isComponentInstanceSelected() && currentComponent.selectedInstance.isServiceProxy()) ? 'Properties and Attributes': 'Inputs'}}" + class="i-sdc-designer-sidebar-tab" data-ui-sref-active="active" + data-ui-sref="workspace.composition.properties" + data-tests-id="properties-and-attributes-tab" + data-ng-class="{'disabled': disabledTabs}"> + <div class="i-sdc-designer-sidebar-tab-icon sprite-new" + ng-class="selectedComponent.isResource() || (isComponentInstanceSelected() && currentComponent.selectedInstance.isServiceProxy()) ? 'properties': 'inputs'"></div> + </button> + <button class="i-sdc-designer-sidebar-tab" data-ui-sref-active="active" + data-ui-sref="workspace.composition.artifacts" + data-ng-if="!isConfiguration() && !(isComponentInstanceSelected() && currentComponent.selectedInstance.isServiceProxy())" + tooltips tooltip-class="tooltip-custom tab-tooltip" tooltip-content="Information Artifacts" + data-ng-class="{'disabled': disabledTabs}"> + <div class="i-sdc-designer-sidebar-tab-icon sprite-new information-artifacts"></div> + </button> + <button data-ng-if="!selectedComponent.isService() || (isComponentInstanceSelected() && currentComponent.selectedInstance.isServiceProxy())" class="i-sdc-designer-sidebar-tab" + data-ui-sref-active="active" ui-sref="workspace.composition.relations" + tooltips tooltip-class="tooltip-custom tab-tooltip tooltip-rightside" + data-tests-id="requirements-and-capabilities" + tooltip-content="Requirements and Capabilities" + data-ng-class="{'disabled': disabledTabs}"> + <div class="i-sdc-designer-sidebar-tab-icon sprite-new relations"></div> + </button> + <button data-ng-if="selectedComponent.isService() && !(isComponentInstanceSelected() && currentComponent.selectedInstance.isServiceProxy())" class="i-sdc-designer-sidebar-tab" + data-ui-sref-active="active" ui-sref="workspace.composition.api" data-tests-id="tab-api" + tooltips tooltip-class="tooltip-custom tab-tooltip tooltip-rightside" tooltip-content="API" + data-ng-class="{'disabled': disabledTabs}"> + <div class="i-sdc-designer-sidebar-tab-icon sprite-new api"></div> + </button> - <div class="w-sdc-designer-sidebar-tabs"> - <button class="i-sdc-designer-sidebar-tab" data-ui-sref-active="active" - data-ui-sref="workspace.composition.details" - tooltips tooltip-class="tooltip-custom tab-tooltip" tooltip-content="Information" - data-tests-id="information-tab" - data-ng-class="{'disabled': disabledTabs}"> - <div class="i-sdc-designer-sidebar-tab-icon sprite-new info"></div> - </button> - <!--<button class="i-sdc-designer-sidebar-tab" data-ui-sref-active="active"--> - <!--ui-sref="workspace.composition.structure"--> - <!--tooltips tooltip-class="tooltip-custom tab-tooltip" tooltip-content="Composition">--> - <!--<div class="i-sdc-designer-sidebar-tab-icon sprite-new structure"></div>--> - <!--</button>--> - <button class="i-sdc-designer-sidebar-tab" data-ui-sref-active="active" - data-ui-sref="workspace.composition.deployment" - tooltips tooltip-class="tooltip-custom tab-tooltip" tooltip-content="Deployment Artifacts" - data-tests-id="deployment-artifact-tab" - data-ng-if="!isPNF() && !isConfiguration() && !(isComponentInstanceSelected() && currentComponent.selectedInstance.isServiceProxy())" - data-ng-class="{'disabled': disabledTabs}"> - <div class="i-sdc-designer-sidebar-tab-icon sprite-new deployment-artifacts"></div> - </button> - <button tooltips tooltip-class="tooltip-custom tab-tooltip" - tooltip-content="{{selectedComponent.isResource() || (isComponentInstanceSelected() && currentComponent.selectedInstance.isServiceProxy()) ? 'Properties and Attributes': 'Inputs'}}" - class="i-sdc-designer-sidebar-tab" data-ui-sref-active="active" - data-ui-sref="workspace.composition.properties" - data-tests-id="properties-and-attributes-tab" - data-ng-class="{'disabled': disabledTabs}"> - <div class="i-sdc-designer-sidebar-tab-icon sprite-new" - ng-class="selectedComponent.isResource() || (isComponentInstanceSelected() && currentComponent.selectedInstance.isServiceProxy()) ? 'properties': 'inputs'"></div> - </button> - <button class="i-sdc-designer-sidebar-tab" data-ui-sref-active="active" - data-ui-sref="workspace.composition.artifacts" - data-ng-if="!isConfiguration() && !(isComponentInstanceSelected() && currentComponent.selectedInstance.isServiceProxy())" - tooltips tooltip-class="tooltip-custom tab-tooltip" tooltip-content="Information Artifacts" - data-ng-class="{'disabled': disabledTabs}"> - <div class="i-sdc-designer-sidebar-tab-icon sprite-new information-artifacts"></div> - </button> - <button data-ng-if="!selectedComponent.isService() || (isComponentInstanceSelected() && currentComponent.selectedInstance.isServiceProxy())" class="i-sdc-designer-sidebar-tab" - data-ui-sref-active="active" ui-sref="workspace.composition.relations" - tooltips tooltip-class="tooltip-custom tab-tooltip tooltip-rightside" - data-tests-id="requirements-and-capabilities" - tooltip-content="Requirements and Capabilities" - data-ng-class="{'disabled': disabledTabs}"> - <div class="i-sdc-designer-sidebar-tab-icon sprite-new relations"></div> - </button> - <button data-ng-if="selectedComponent.isService() && !(isComponentInstanceSelected() && currentComponent.selectedInstance.isServiceProxy())" class="i-sdc-designer-sidebar-tab" - data-ui-sref-active="active" ui-sref="workspace.composition.api" data-tests-id="tab-api" - tooltips tooltip-class="tooltip-custom tab-tooltip tooltip-rightside" tooltip-content="API" - data-ng-class="{'disabled': disabledTabs}"> - <div class="i-sdc-designer-sidebar-tab-icon sprite-new api"></div> - </button> + </div> + <div data-ui-view="" class="w-sdc-designer-sidebar-tab-content-view"></div> </div> - <div data-ui-view="" class="w-sdc-designer-sidebar-tab-content-view"></div> + <!-- Solution for now to support policies and groups working with Angular 2 components --> + <!-- isCertified not relevant for group or policy --> + <!-- (selectedZoneInstanceType === ZoneInstanceType.GROUP || selectedZoneInstanceType === ZoneInstanceType.POLICY) --> + <div ng-if="selectedZoneInstance"> + + <ng2-composition-panel + [is-loading]="isLoading" + [is-view-only]="isViewOnly || isCanvasTagging" + [selected-zone-instance-name]="selectedZoneInstance.instanceData.name" + [selected-zone-instance-id]="selectedZoneInstance.instanceData.uniqueId" + [selected-zone-instance-type]="selectedZoneInstance.type" + [topology-template]="currentComponent" + > + </ng2-composition-panel> + </div> <loader data-display="isLoadingRightPanel" relative="true" size="medium"></loader> diff --git a/catalog-ui/src/app/view-models/workspace/tabs/composition/composition.less b/catalog-ui/src/app/view-models/workspace/tabs/composition/composition.less index f351450e6d..b9bb66cde7 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/composition/composition.less +++ b/catalog-ui/src/app/view-models/workspace/tabs/composition/composition.less @@ -107,7 +107,7 @@ position: fixed; right: -302px; width: 302px; - top: 102px; + top: 103px; transition: right 0.2s; z-index: 9; .box-shadow(-7px -3px 6px -8px @main_color_n); @@ -163,6 +163,13 @@ top: 10px; } + .w-sdc-designer-restore-button { + .hand; + position:absolute; + right: 20px; + top:10px; + width:65px; + } .w-sdc-designer-sidebar-tabs { .bg_c; } @@ -237,7 +244,7 @@ height: 32px; line-height: 32px; margin-top: 1px; - padding: 0 40px 0 20px; + padding: 0 10px 0 20px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -266,7 +273,7 @@ .sprite-new; .arrow-up; right: 16px; - top: 10px; + top: 13px; transition: .3s all; position: absolute; } @@ -664,8 +671,8 @@ align-items: center; .non-certified { position: relative; - left: 27px; - bottom: 6px; + left: -4px; + top: -4px; .sprite; .s-sdc-state-non-certified; display: block; @@ -682,8 +689,8 @@ .non-certified { position: relative; - left: 43px; - bottom: 3px; + left: 0px; + top: 0px; .sprite; .s-sdc-state-non-certified; display: block; @@ -841,6 +848,11 @@ flex-direction: column; align-items: flex-end; margin-right:10px; + pointer-events: none; + + & > * { + pointer-events: all; + } &.with-sidebar { right:320px; diff --git a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/details/details-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/details/details-view-model.ts index 6e3258f69b..e389395142 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/details/details-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/details/details-view-model.ts @@ -143,19 +143,23 @@ export class DetailsViewModel { this.$scope.currentComponent.changeComponentInstanceVersion(componentUid).then(onSuccess, onCancel); }; - this.serviceService.checkComponentInstanceVersionChange(service, componentUid).subscribe((pathsToDelete:string[]) => { - if (pathsToDelete && pathsToDelete.length) { - this.$scope.isLoading = false; - this.$scope.$parent.isLoading = false; - this.$scope.$parent.openVersionChangeModal(pathsToDelete).then(() => { - this.$scope.isLoading = true; - this.$scope.$parent.isLoading = true; + if (this.$scope.currentComponent.isService()) { + this.serviceService.checkComponentInstanceVersionChange(service, componentUid).subscribe((pathsToDelete:string[]) => { + if (pathsToDelete && pathsToDelete.length) { + this.$scope.isLoading = false; + this.$scope.$parent.isLoading = false; + this.$scope.$parent.openVersionChangeModal(pathsToDelete).then(() => { + this.$scope.isLoading = true; + this.$scope.$parent.isLoading = true; + onUpdate(); + }, onCancel); + } else { onUpdate(); - }, onCancel); - } else { - onUpdate(); - } - }, onCancel); + } + }, onCancel); + } else { + onUpdate(); + } }; } } diff --git a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/details/details-view.html b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/details/details-view.html index 033c4668f3..9468937610 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/details/details-view.html +++ b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/details/details-view.html @@ -26,9 +26,10 @@ data-ng-if="!isComponentInstanceSelected()" data-tests-id="rightTab_version" data-ng-bind="selectedComponent.version"></span> <ng-form name="editForm" data-ng-if="isComponentInstanceSelected()"> - <select data-ng-model="editResourceVersion.changeVersion" name="changeVersion" data-tests-id="changeVersion" data-ng-disabled="$parent.isViewOnly || selectedComponent.uniqueId != editResourceVersion.allVersions[editResourceVersion.changeVersion]" + <select data-ng-model="editResourceVersion.changeVersion" name="changeVersion" data-tests-id="changeVersion" + data-ng-disabled="$parent.isViewOnly || selectedComponent.uniqueId != editResourceVersion.allVersions[editResourceVersion.changeVersion] || selectedComponent.archived" class="i-sdc-designer-sidebar-section-content-item-value i-sdc-form-select" - data-ng-class="{'minor': (editResourceVersion.changeVersion)%1}" + data-ng-class="{'minor': (editResourceVersion.changeVersion)%1, 'disabled':selectedComponent.archived}" data-ng-change="changeResourceVersion()"> <option class="select-instance-version" data-ng-class="{'minor': key%1}" ng-repeat="(key, value) in editResourceVersion.allVersions">{{key}}</option> diff --git a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/properties-and-attributes/properties-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/properties-and-attributes/properties-view-model.ts index efd5cfd84d..e3ddecd9a5 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/properties-and-attributes/properties-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/properties-and-attributes/properties-view-model.ts @@ -139,9 +139,11 @@ export class ResourcePropertiesViewModel { (this.$scope.isPropertyOwner() ? this.$scope.properties[property.parentUniqueId] : this.$scope.properties[property.resourceInstanceUniqueId]) || [], - this.isPropertyValueOwner()).then((updatedProperty:PropertyModel) => { - let oldProp = _.find(this.$scope.properties[updatedProperty.resourceInstanceUniqueId], (prop:PropertyModel) => {return prop.uniqueId == updatedProperty.uniqueId;}); - oldProp.value = updatedProperty.value; + this.isPropertyValueOwner(), "component", property.resourceInstanceUniqueId).then((updatedProperty:PropertyModel) => { + if(updatedProperty){ + let oldProp = _.find(this.$scope.properties[updatedProperty.resourceInstanceUniqueId], (prop:PropertyModel) => {return prop.uniqueId == updatedProperty.uniqueId;}); + oldProp.value = updatedProperty.value; + } }); }; @@ -224,7 +226,9 @@ export class ResourcePropertiesViewModel { return this.$filter("resourceName")(this.$scope.currentComponent.name); default: - return this.$filter("resourceName")((_.find(this.$scope.currentComponent.componentInstances, {uniqueId: key})).name); + let componentInstance = _.find(this.$scope.currentComponent.componentInstances, {uniqueId: key}); + if(componentInstance) + return this.$filter("resourceName")(componentInstance.name); } }; diff --git a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/properties-and-attributes/properties.less b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/properties-and-attributes/properties.less index 41a90bff9d..ce5acc83e5 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/properties-and-attributes/properties.less +++ b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/properties-and-attributes/properties.less @@ -1,5 +1,6 @@ .w-sdc-designer-sidebar-tab-content.properties { .i-sdc-designer-sidebar-section-content-item-property-and-attribute-label{ + display:block; font-weight: bold; } .i-sdc-designer-sidebar-section-content-item-button.update{ diff --git a/catalog-ui/src/app/view-models/workspace/tabs/deployment/deployment-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/deployment/deployment-view-model.ts index feda7fe17f..9df377c5fc 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/deployment/deployment-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/deployment/deployment-view-model.ts @@ -108,7 +108,7 @@ export class DeploymentViewModel { }; private initRightTabs = ()=> { - if (this.$scope.currentComponent.groups) { + if (this.$scope.currentComponent.modules) { this.$templateCache.put("hierarchy-view.html", require('app/view-models/tabs/hierarchy/hierarchy-view.html')); let hierarchyTab = new Tab("hierarchy-view.html", 'Sdc.ViewModels.HierarchyViewModel', 'hierarchy', this.$scope.isViewMode(), this.$scope.currentComponent, 'hierarchy'); this.$scope.tabs.push(hierarchyTab) @@ -116,11 +116,11 @@ export class DeploymentViewModel { } private initGraphData = ():void => { - if(!this.$scope.component.componentInstances || !this.$scope.component.componentInstancesRelations || !this.$scope.component.groups) { + if(!this.$scope.component.componentInstances || !this.$scope.component.componentInstancesRelations || !this.$scope.component.modules) { this.ComponentServiceNg2.getDeploymentGraphData(this.$scope.component).subscribe((response:ComponentGenericResponse) => { this.$scope.component.componentInstances = response.componentInstances; this.$scope.component.componentInstancesRelations = response.componentInstancesRelations; - this.$scope.component.groups = response.groups; + this.$scope.component.modules = response.modules; this.$scope.isLoading = false; this.initComponent(); this.initRightTabs(); diff --git a/catalog-ui/src/app/view-models/workspace/tabs/deployment/deployment-view.html b/catalog-ui/src/app/view-models/workspace/tabs/deployment/deployment-view.html index f8b5f23a25..1065552e46 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/deployment/deployment-view.html +++ b/catalog-ui/src/app/view-models/workspace/tabs/deployment/deployment-view.html @@ -5,6 +5,6 @@ </div> <div class="w-sdc-deployment-right-bar"> - <sdc-tabs tabs="tabs" is-view-only="isViewOnly" selected-tab="selectedTab"></sdc-tabs> + <ng1-tabs tabs="tabs" is-view-only="isViewOnly" selected-tab="selectedTab"></ng1-tabs> </div> </div> diff --git a/catalog-ui/src/app/view-models/workspace/tabs/deployment/deployment.less b/catalog-ui/src/app/view-models/workspace/tabs/deployment/deployment.less index 4c548c7331..f51ff6220d 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/deployment/deployment.less +++ b/catalog-ui/src/app/view-models/workspace/tabs/deployment/deployment.less @@ -10,9 +10,11 @@ .w-sdc-deployment-canvas { .noselect; .bg_c; + position: relative; bottom: 0; width: 100%; height: 100%; + z-index: 0; .view-mode{ background-color: #f8f8f8; @@ -27,7 +29,6 @@ position: absolute; right: 0px; transition: right 0.2s; - z-index: 10000; top: @action_nav_height; } } diff --git a/catalog-ui/src/app/view-models/workspace/tabs/distribution/disribution-status-modal/disribution-status-modal-view.html b/catalog-ui/src/app/view-models/workspace/tabs/distribution/disribution-status-modal/disribution-status-modal-view.html index 3367193fc7..ff4bbd60c5 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/distribution/disribution-status-modal/disribution-status-modal-view.html +++ b/catalog-ui/src/app/view-models/workspace/tabs/distribution/disribution-status-modal/disribution-status-modal-view.html @@ -1,4 +1,4 @@ -<sdc-modal modal="modalDitributionStatus" type="classic" class="w-sdc-classic-top-line-modal" buttons="footerButtons" header="Distribution by Status" show-close-button="true"> +<ng1-modal modal="modalDitributionStatus" type="classic" class="w-sdc-classic-top-line-modal" buttons="footerButtons" header="Distribution by Status" show-close-button="true"> <div class="w-sdc-distribution-view"> <div class="w-sdc-distribution-view-header"> @@ -127,4 +127,4 @@ </div> -</sdc-modal> +</ng1-modal> diff --git a/catalog-ui/src/app/view-models/workspace/tabs/general/general-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/general/general-view-model.ts index b03d7c4d7c..68f789808a 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/general/general-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/general/general-view-model.ts @@ -21,11 +21,13 @@ 'use strict'; import * as _ from "lodash"; import {ModalsHandler, ValidationUtils, EVENTS, CHANGE_COMPONENT_CSAR_VERSION_FLAG, ComponentType, DEFAULT_ICON, - ResourceType, ComponentState} from "app/utils"; + ResourceType, ComponentState, instantiationType, ComponentFactory} from "app/utils"; import {CacheService, EventListenerService, ProgressService, OnboardingService} from "app/services"; -import {IAppConfigurtaion, IValidate, IMainCategory, Resource, ISubCategory,Service, ICsarComponent} from "app/models"; +import {IAppConfigurtaion, IValidate, IMainCategory, Resource, ISubCategory,Service, ICsarComponent, Component} from "app/models"; import {IWorkspaceViewModelScope} from "app/view-models/workspace/workspace-view-model"; import {Dictionary} from "lodash"; +import { PREVIOUS_CSAR_COMPONENT } from "../../../../utils/constants"; + export class Validation { componentNameValidationPattern:RegExp; @@ -62,8 +64,11 @@ export interface IGeneralScope extends IWorkspaceViewModelScope { importCsarProgressKey:string; browseFileLabel:string; componentCategories:componentCategories; + instantiationTypes:Array<instantiationType>; - onToscaFileChange():void; + save():Promise<any>; + revert():void; + onImportFileChange():void; validateField(field:any):boolean; validateName(isInit:boolean):void; calculateUnique(mainCategory:string, subCategory:string):string; // Build unique string from main and sub category @@ -74,6 +79,8 @@ export interface IGeneralScope extends IWorkspaceViewModelScope { openOnBoardingModal():void; initCategoreis():void; initEnvironmentContext():void; + initInstantiationTypes():void; + onInstantiationTypeChange():void; updateIcon():void; possibleToUpdateIcon():boolean; } @@ -101,7 +108,8 @@ export class GeneralViewModel { '$interval', '$filter', '$timeout', - 'Sdc.Services.OnboardingService' + 'Sdc.Services.OnboardingService', + 'ComponentFactory' ]; constructor(private $scope:IGeneralScope, @@ -124,7 +132,8 @@ export class GeneralViewModel { protected $interval:any, private $filter:ng.IFilterService, private $timeout:ng.ITimeoutService, - private onBoardingService:OnboardingService) { + private onBoardingService:OnboardingService, + private ComponentFactory:ComponentFactory) { this.initScopeValidation(); this.initScopeMethods(); @@ -146,51 +155,64 @@ export class GeneralViewModel { this.$scope.validation.projectCodeValidationPattern = this.ProjectCodeValidationPattern; }; - private initImportedToscaBrowseFile = ():void =>{ - // Init the decision if to show onboarding - this.$scope.isShowOnboardingSelectionBrowse = false; - if (this.$scope.component.isResource() && - this.$scope.isEditMode() && - (<Resource>this.$scope.component).resourceType == ResourceType.VF && - (<Resource>this.$scope.component).csarUUID) { - this.$scope.isShowOnboardingSelectionBrowse = true; - let onboardCsarFilesMap:Dictionary<Dictionary<string>> = this.cacheService.get('onboardCsarFilesMap'); - // The onboardCsarFilesMap in cache contains map of [packageId]:[vsp display name for brows] - // if the map is empty - Do request to BE - if(onboardCsarFilesMap) { - if (onboardCsarFilesMap[(<Resource>this.$scope.component).csarUUID]){ - this.$scope.importedToscaBrowseFileText = onboardCsarFilesMap[(<Resource>this.$scope.component).csarUUID][(<Resource>this.$scope.component).csarVersion]; - } - } - if(!onboardCsarFilesMap || !this.$scope.importedToscaBrowseFileText){ + private loadOnboardingFileCache = ():ng.IPromise<Dictionary<any>> =>{ - let onSuccess = (vsps:Array<ICsarComponent>): void =>{ - onboardCsarFilesMap = {}; - _.each(vsps, (vsp:ICsarComponent)=>{ - onboardCsarFilesMap[vsp.packageId] = onboardCsarFilesMap[vsp.packageId] || {}; - onboardCsarFilesMap[vsp.packageId][vsp.version] = vsp.vspName + " (" + vsp.version + ")"; - }); - this.cacheService.set('onboardCsarFilesMap', onboardCsarFilesMap); - this.$scope.importedToscaBrowseFileText = onboardCsarFilesMap[(<Resource>this.$scope.component).csarUUID][(<Resource>this.$scope.component).csarVersion]; - }; + let onboardCsarFilesMap:Dictionary<Dictionary<string>>; + let onSuccess = (vsps:Array<ICsarComponent>) =>{ + onboardCsarFilesMap = {}; + _.each(vsps, (vsp:ICsarComponent)=>{ + onboardCsarFilesMap[vsp.packageId] = onboardCsarFilesMap[vsp.packageId] || {}; + onboardCsarFilesMap[vsp.packageId][vsp.version] = vsp.vspName + " (" + vsp.version + ")"; + }); + this.cacheService.set('onboardCsarFilesMap', onboardCsarFilesMap); + return onboardCsarFilesMap; + }; + let onError = (): void =>{ + console.log("Error getting onboarding list"); + }; + return this.onBoardingService.getOnboardingVSPs().then(onSuccess, onError); + }; + + private setImportedFileText = ():void => { - let onError = (): void =>{ - console.log("Error getting onboarding list"); - }; + if(!this.$scope.isShowOnboardingSelectionBrowse) return; - this.onBoardingService.getOnboardingVSPs().then(onSuccess, onError); + //these variables makes it easier to read this logic + let csarUUID:string = (<Resource>this.$scope.component).csarUUID; + let csarVersion:string = (<Resource>this.$scope.component).csarVersion; + + let onboardCsarFilesMap:Dictionary<Dictionary<string>> = this.cacheService.get('onboardCsarFilesMap'); + let assignFileName = ():void => { + if(this.$scope.component.vspArchived){ + this.$scope.importedToscaBrowseFileText = 'VSP is archived'; + } else { + this.$scope.importedToscaBrowseFileText = onboardCsarFilesMap[csarUUID][csarVersion]; } } - }; - - private initScope = ():void => { - // Work around to change the csar version - if (this.cacheService.get(CHANGE_COMPONENT_CSAR_VERSION_FLAG)) { - (<Resource>this.$scope.component).csarVersion = this.cacheService.get(CHANGE_COMPONENT_CSAR_VERSION_FLAG); + + if(this.$scope.component.vspArchived || (onboardCsarFilesMap && onboardCsarFilesMap[csarUUID] && onboardCsarFilesMap[csarUUID][csarVersion])){ //check that the file name is already in cache + assignFileName(); + } else { + this.loadOnboardingFileCache().then((onboardingFiles) => { + onboardCsarFilesMap = onboardingFiles; + this.cacheService.set('onboardCsarFilesMap', onboardingFiles); + assignFileName(); + }, ()=> {}); } + + } + isCreateModeAvailable(verifyObj:string): boolean { + var isCheckout:boolean = ComponentState.NOT_CERTIFIED_CHECKOUT === this.$scope.component.lifecycleState; + return this.$scope.isCreateMode() || (isCheckout && !verifyObj) + } + + private initScope = ():void => { + + this.$scope.importCsarProgressKey = "importCsarProgressKey"; + this.$scope.browseFileLabel = this.$scope.component.isResource() && (<Resource>this.$scope.component).resourceType === ResourceType.VF ? "Upload file" : "Upload VFC"; this.$scope.progressService = this.progressService; this.$scope.componentCategories = new componentCategories(); @@ -216,9 +238,33 @@ export class GeneralViewModel { if (this.$scope.isEditMode() && resource.resourceType == ResourceType.VF && !resource.csarUUID) { this.$scope.isShowFileBrowse = true; } + } else if(this.$scope.component.isService()){ + // Init Instantiation types + this.$scope.initInstantiationTypes(); + } + + // Work around to change the csar version + if (this.cacheService.get(CHANGE_COMPONENT_CSAR_VERSION_FLAG)) { + //(<Resource>this.$scope.component).csarVersion = this.cacheService.get(CHANGE_COMPONENT_CSAR_VERSION_FLAG); + this.cacheService.remove(CHANGE_COMPONENT_CSAR_VERSION_FLAG); + this.$scope.updateUnsavedFileFlag(true); + + if (!this.$scope.isViewMode() && this.cacheService.get(PREVIOUS_CSAR_COMPONENT)) { //keep the old component in the cache until checkout, so we dont need to pass it around + this.$scope.setOriginComponent(this.cacheService.get(PREVIOUS_CSAR_COMPONENT)); + this.cacheService.remove(PREVIOUS_CSAR_COMPONENT); + } } - this.initImportedToscaBrowseFile(); + + // Init the decision if to show onboarding + if (this.$scope.component.isResource() && this.$scope.isEditMode() && + (<Resource>this.$scope.component).resourceType == ResourceType.VF && (<Resource>this.$scope.component).csarUUID) { + this.$scope.isShowOnboardingSelectionBrowse = true; + this.setImportedFileText(); + } else { + this.$scope.isShowOnboardingSelectionBrowse = false; + } + //init file extensions based on the file that was imported. if (this.$scope.component.isResource() && (<Resource>this.$scope.component).importedFile) { @@ -231,11 +277,14 @@ export class GeneralViewModel { (<Resource>this.$scope.component).importedFile.filetype = "yaml"; this.$scope.importedFileExtension = this.sdcConfig.toscaFileExtension; } + this.$scope.restoreFile = angular.copy((<Resource>this.$scope.originComponent).importedFile); //create backup } else if (this.$scope.isEditMode() && (<Resource>this.$scope.component).resourceType === ResourceType.VF) { this.$scope.importedFileExtension = this.sdcConfig.csarFileExtension; //(<Resource>this.$scope.component).importedFile.filetype="csar"; } + + this.$scope.setValidState(true); this.$scope.calculateUnique = (mainCategory:string, subCategory:string):string => { @@ -252,6 +301,12 @@ export class GeneralViewModel { this.$scope.originComponent.contactId = this.$scope.component.contactId; } + + this.$scope.$on('$destroy', () => { + this.EventListenerService.unRegisterObserver(EVENTS.ON_LIFECYCLE_CHANGE_WITH_SAVE); + this.EventListenerService.unRegisterObserver(EVENTS.ON_LIFECYCLE_CHANGE); + }); + }; // Convert category string MainCategory_#_SubCategory to Array with one item (like the server except) @@ -299,14 +354,28 @@ export class GeneralViewModel { } }; + this.$scope.initInstantiationTypes = ():void => { + if (this.$scope.componentType === ComponentType.SERVICE) { + this.$scope.instantiationTypes = new Array(); + this.$scope.instantiationTypes.push(instantiationType.A_LA_CARTE); + this.$scope.instantiationTypes.push(instantiationType.MACRO); + var instantiationTypeField:string =(<Service>this.$scope.component).instantiationType; + if (instantiationTypeField === ""){ + this.$scope.instantiationTypes.push(""); + } + else if (this.isCreateModeAvailable(instantiationTypeField)) { + (<Service>this.$scope.component).instantiationType = instantiationType.A_LA_CARTE; + + } + } + }; this.$scope.initEnvironmentContext = ():void => { if (this.$scope.componentType === ComponentType.SERVICE) { this.$scope.environmentContextObj = this.cacheService.get('UIConfiguration').environmentContext; var environmentContext:string =(<Service>this.$scope.component).environmentContext; - var isCheckout:boolean = ComponentState.NOT_CERTIFIED_CHECKOUT === this.$scope.component.lifecycleState; // In creation new service OR check outing old service without environmentContext parameter - set default value - if(this.$scope.isCreateMode() || (isCheckout && !environmentContext)){ + if(this.isCreateModeAvailable(environmentContext)){ (<Service>this.$scope.component).environmentContext = this.$scope.environmentContextObj.defaultValue; } } @@ -320,19 +389,33 @@ export class GeneralViewModel { }; this.$scope.openOnBoardingModal = ():void => { + if(this.$scope.component.vspArchived) return; let csarUUID = (<Resource>this.$scope.component).csarUUID; - this.ModalsHandler.openOnboadrdingModal('Update', csarUUID).then(()=> { - // OK - this.$scope.uploadFileChangedInGeneralTab(); - }, ()=> { - // ERROR - }); + let csarVersion = (<Resource>this.$scope.component).csarVersion; + this.ModalsHandler.openOnboadrdingModal('Update', csarUUID, csarVersion).then((result)=> { + + if(result){ + this.ComponentFactory.getComponentWithMetadataFromServer(result.type.toUpperCase(), result.previousComponent.uniqueId).then( + (component:Component)=> { + if (result.componentCsar && component.isResource()){ + this.cacheService.set(PREVIOUS_CSAR_COMPONENT, angular.copy(component)); + component = this.ComponentFactory.updateComponentFromCsar(result.componentCsar, <Resource>component); + } + + this.$scope.setComponent(component); + this.$scope.updateUnsavedFileFlag(true); + this.setImportedFileText(); + }, ()=> { + // ERROR + }); + } + }, () => {}); }; this.$scope.updateIcon = ():void => { this.ModalsHandler.openUpdateIconModal(this.$scope.component).then((isDirty:boolean)=> { - if(!this.$scope.isCreateMode()){ - this.$state.current.data.unsavedChanges = this.$state.current.data.unsavedChanges || isDirty; + if(isDirty && !this.$scope.isCreateMode()){ + this.setUnsavedChanges(true); } }, ()=> { // ERROR @@ -340,7 +423,7 @@ export class GeneralViewModel { }; this.$scope.possibleToUpdateIcon = ():boolean => { - if(this.$scope.componentCategories.selectedCategory && (!this.$scope.component.isResource() || this.$scope.component.vendorName)){ + if(this.$scope.componentCategories.selectedCategory && (!this.$scope.component.isResource() || this.$scope.component.vendorName) && !this.$scope.component.isAlreadyCertified()){ return true; }else{ return false; @@ -364,7 +447,6 @@ export class GeneralViewModel { return; } - //????????????????????????? let subtype:string = ComponentType.RESOURCE == this.$scope.componentType ? this.$scope.component.getComponentSubType() : undefined; let onFailed = (response) => { @@ -407,6 +489,55 @@ export class GeneralViewModel { } }; + + this.EventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE_WITH_SAVE, (nextState) => { + if (this.$state.current.data.unsavedChanges && this.$scope.isValidForm){ + this.$scope.save().then(() => { + this.$scope.handleChangeLifecycleState(nextState); + }, () => { + console.error("Save failed, unable to change lifecycle state to " + nextState); + }); + } else if(!this.$scope.isValidForm){ + console.error("Form is not valid"); + } else { + let newCsarVersion:string; + if(this.$scope.unsavedFile){ + newCsarVersion = (<Resource>this.$scope.component).csarVersion; + } + this.$scope.handleChangeLifecycleState(nextState, newCsarVersion); + } + }); + + + this.$scope.revert = ():void => { + //in state of import file leave the file in place + + this.$scope.setComponent(this.ComponentFactory.createComponent(this.$scope.originComponent)); + + if (this.$scope.component.isResource() && this.$scope.restoreFile) { + (<Resource>this.$scope.component).importedFile = angular.copy(this.$scope.restoreFile); + } + + this.setImportedFileText(); + this.$scope.updateBreadcrumbs(this.$scope.component); //update on workspace + + this.$scope.componentCategories.selectedCategory = this.$scope.originComponent.selectedCategory; + this.setUnsavedChanges(false); + this.$scope.updateUnsavedFileFlag(false); + this.$scope.editForm.$setPristine(); + }; + + this.$scope.onImportFileChange = () => { + + if( !this.$scope.restoreFile && this.$scope.editForm.fileElement.value && this.$scope.editForm.fileElement.value.filename || //if file started empty but we have added a new one + this.$scope.restoreFile && !angular.equals(this.$scope.restoreFile, this.$scope.editForm.fileElement.value)){ //or file was swapped for a new one + this.$scope.updateUnsavedFileFlag(true); + } else { + this.$scope.updateUnsavedFileFlag(false); + this.$scope.editForm.fileElement.$setPristine(); + } + }; + this.$scope.$watchCollection('component.name', (newData:any):void => { this.$scope.validateName(false); }); @@ -417,9 +548,10 @@ export class GeneralViewModel { }); this.$scope.$watch("editForm.$dirty", (newVal, oldVal) => { - if (newVal !== oldVal) { - this.$state.current.data.unsavedChanges = newVal && !this.$scope.isCreateMode(); + if (newVal && !this.$scope.isCreateMode()) { + this.setUnsavedChanges(true); } + }); this.$scope.onCategoryChange = ():void => { @@ -439,9 +571,12 @@ export class GeneralViewModel { this.$scope.component.icon = DEFAULT_ICON; } }; - this.EventListenerService.registerObserverCallback(EVENTS.ON_CHECKOUT, this.$scope.reload); - this.EventListenerService.registerObserverCallback(EVENTS.ON_REVERT, ()=>{ - this.$scope.componentCategories.selectedCategory = this.$scope.originComponent.selectedCategory; - }); + this.EventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE, this.$scope.reload); + + }; + + private setUnsavedChanges = (hasChanges:boolean):void => { + this.$state.current.data.unsavedChanges = hasChanges; }; + } diff --git a/catalog-ui/src/app/view-models/workspace/tabs/general/general-view.html b/catalog-ui/src/app/view-models/workspace/tabs/general/general-view.html index 36976c610e..28b033a64b 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/general/general-view.html +++ b/catalog-ui/src/app/view-models/workspace/tabs/general/general-view.html @@ -1,5 +1,14 @@ <div include-padding="true" class="sdc-workspace-general-step"> - + <div class="w-sdc-main-container-body-content-action-buttons"> + <div data-ng-if="unsavedFile && !isCreateMode() && !isViewMode()" class="unsaved-file-warning"> + <span class="sprite-new sdc-warning"></span> Click save to update to the new VSP + </div> + <button class="tlv-btn blue" data-ng-if="isDesigner()" data-ng-show="isGeneralView()" data-ng-class="{'disabled' : !isValidForm || isDisableMode() || isViewMode() || isCreateMode()}" + data-ng-click="save()" data-tests-id="create/save" tooltips tooltip-content="Save">Save</button> + <span data-ng-if="isDesigner()" data-ng-class="{'disabled' :isDisableMode() || isViewMode() || isCreateMode()}" ng-click="revert()" class="sprite-new revert-btn" data-tests-id="revert" + data-ng-show="isGeneralView()" tooltips tooltip-content="Revert"></span> + + </div> <form novalidate class="w-sdc-form" name="editForm" validation-on-load form-to-validate="editForm"> <div class="w-sdc-form-section-container"> @@ -9,10 +18,13 @@ <div class="w-sdc-form-column"> <div class="upper-general-fields"> <div class="selected-icon-container" data-ng-class="{'show-only-on-over':'defaulticon'!=component.icon && !isViewMode()}"> - <div class="selected-icon-inner-container"> + <div class="selected-icon-inner-container "> <div class="sprite-new update-component-icon" data-ng-click="updateIcon()" data-ng-if="!isViewMode() && possibleToUpdateIcon()"></div> <div class="i-sdc-form-item-suggested-icon large selected-icon {{component.iconSprite}} {{component.icon}}" - data-ng-class="{ 'disable': isViewMode() || !possibleToUpdateIcon() }" + data-ng-class="{ + 'disable': isViewMode() || !possibleToUpdateIcon(), + 'archive-component active-component-static': component.archived + }" ng-model="component.icon" tooltips tooltip-content='{{component.icon | translate}}' > @@ -27,7 +39,7 @@ data-ng-class="{'view-mode': isViewMode()}" name="componentName" data-ng-init="isCreateMode() && validateName(true)" - data-ng-maxlength="50" + data-ng-maxlength="50" data-ng-model="component.name" type="text" data-required @@ -53,7 +65,7 @@ <!--------------------- CATEGORIES --------------------> <div class="i-sdc-form-item" - data-ng-class="{'error': validateField(editForm.category)}"> + data-ng-class="{'error': validateField(editForm.category)}"> <loader data-display="!categories && !initCategoreis()" relative="true"></loader> <label class="i-sdc-form-label required">Category</label> <select class="i-sdc-form-select" @@ -132,14 +144,17 @@ <div class="w-sdc-form-column"> <!--------------------- IMPORT TOSCA FILE USING BROWSE (ALSO VFC) --------------------> <div class="i-sdc-form-item" ng-if="isShowFileBrowse"> + + <!-- // element-disabled="{{!isCreateMode()&&!(isEditMode()&&component.resourceType=='VF')&&component.vspArchived}} || {{isViewMode()}}" --> + <label class="i-sdc-form-label" data-ng-class="{'required':isCreateMode()}">{{browseFileLabel}}</label> <file-upload id="fileUploadElement" class="i-sdc-form-input" element-name="fileElement" - element-disabled="{{!isCreateMode()&&!(isEditMode()&&component.resourceType=='VF')}} || {{isViewMode()}}" + element-disabled="{{(!isCreateMode()&&!(isEditMode()&&component.resourceType=='VF'))|| isViewMode() || component.vspArchived}}" form-element="editForm" file-model="component.importedFile" - on-file-changed-in-directive="uploadFileChangedInGeneralTab" + on-file-changed-in-directive="onImportFileChange" extensions="{{importedFileExtension}}" default-text="'Browse to select file'" data-ng-class="{'error':!(isEditMode()&&component.resourceType=='VF') && (!editForm.fileElement.$valid || !component.importedFile.filename)}"></file-upload> @@ -147,16 +162,16 @@ <!--------------------- IMPORT TOSCA FILE USING ONBOARDING --------------------> <div class="i-sdc-form-item" ng-if="isShowOnboardingSelectionBrowse"> - <label class="i-sdc-form-label required">Select VSP</label> - <div class="i-sdc-form-file-upload i-sdc-form-input"> - <span class="i-sdc-form-file-name" data-tests-id="filename">{{(fileModel && fileModel.filename) || importedToscaBrowseFileText}}</span> - <div class="i-sdc-form-file-upload-x-btn" ng-click="cancel()" data-ng-show="fileModel.filename && fileModel.filename!=='' && elementDisabled!=='true'"></div> - <input type="button" name="fileElement"/> - <div class="file-upload-browse-btn" data-ng-click="openOnBoardingModal()" data-tests-id="browseButton">Browse</div> - </div> + <label class="i-sdc-form-label required">Select VSP</label> + <div class="i-sdc-form-file-upload i-sdc-form-input"> + <span class="i-sdc-form-file-name" data-ng-disabled="component.vspArchived" data-tests-id="filename">{{(fileModel && fileModel.filename) || importedToscaBrowseFileText }}</span> + <div class="i-sdc-form-file-upload-x-btn" ng-click="cancel()" data-ng-show="fileModel.filename && fileModel.filename!=='' && elementDisabled!=='true'"></div> + <input type="button" data-ng-disabled="component.vspArchived" name="fileElement" /> + <div class="file-upload-browse-btn" data-ng-click="openOnBoardingModal()" data-ng-disabled="!component.vspArchived" data-tests-id="browseButton">Browse</div> + </div> </div> - <div class="input-error-file-upload" data-ng-show="component.importedFile && (!editForm.fileElement.$valid || !component.importedFile.filename)"> + <div class="input-error-file-upload" data-ng-disabled="!component.archived" data-ng-show="component.importedFile && (!editForm.fileElement.$valid || !component.importedFile.filename)"> <!-- editForm.fileElement.$error.required <== Can not use this, because the browse is done from outside for the first time --> <span ng-show="!(isEditMode()&&component.resourceType=='VF')&&!component.importedFile.filename" translate="NEW_SERVICE_RESOURCE_ERROR_TOSCA_FILE_REQUIRED"></span><!-- Required --> <span ng-show="editForm.fileElement.$error.maxsize" translate="VALIDATION_ERROR_MAX_FILE_SIZE"></span> @@ -283,7 +298,7 @@ </div> <!--------------------- Resource Model Number --------------------> - <!--------------------- ECOMPGENERATEDNAMING --------------------> + <!--------------------- ECOMPGENERATEDNAMING --------------------> <div class="i-sdc-form-item" data-ng-class="{'error': validateField(editForm.ecompGeneratedNaming)}" @@ -307,7 +322,7 @@ <!--------------------- NAMING POLICY --------------------> <div ng-if="component.isService()" class="i-sdc-form-item" data-ng-class="{'error': validateField(editForm.namingPolicy)}"> - <label class="i-sdc-form-label">Naming policy</label> + <label class="i-sdc-form-label">Naming Policy</label> <input class="i-sdc-form-input" name="namingPolicy" data-ng-class="{'view-mode': isViewMode() || !component.ecompGeneratedNaming}" @@ -389,6 +404,21 @@ </div> <!--------------------- ENVIRONMENT CONTEXT ------------------> + <!--------------------- Instantiation Type --------------------> + <div class="i-sdc-form-item" data-ng-if="component.isService() && instantiationTypes"> + <label class="i-sdc-form-label">Instantiation Type</label> + <select class="i-sdc-form-select" + name="instantiationType" + data-ng-class="{'view-mode': isViewMode()}" + data-ng-disabled="component.isCsarComponent()" + data-ng-model="component.instantiationType" + data-tests-id="selectInstantiationType"> + <option ng-repeat="type in instantiationTypes">{{type}}</option> + + </select> + </div> + + <!--------------------- Instantiation Type --------------------> <div class="meta-data" data-ng-if="component.creationDate"> <div> diff --git a/catalog-ui/src/app/view-models/workspace/tabs/general/general.less b/catalog-ui/src/app/view-models/workspace/tabs/general/general.less index b9b59deb1b..b60e4b8de4 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/general/general.less +++ b/catalog-ui/src/app/view-models/workspace/tabs/general/general.less @@ -1,5 +1,12 @@ .sdc-workspace-general-step { display: flex; + flex-direction: column; + .w-sdc-main-container-body-content-action-buttons{ + display: flex; + justify-content: flex-end; + align-items: center; + margin-bottom: 10px; + } .w-sdc-form { padding: 0; flex-grow: 10; @@ -26,10 +33,15 @@ width: 100px; height: 28px; text-align: center; + border-left: solid 1px #cfcfcf; &.disabled { cursor: default; } + + &:hover:not(.disabled) { + background-color: #dbdee2; + } } } @@ -80,8 +92,7 @@ padding: 8px 0 2px 20px; text-align: left; background-color: @tlv_color_t; - position: absolute; - bottom: 0; + position: relative; width: 100%; .meta-data-item-value{ padding-bottom: 6px; @@ -97,19 +108,19 @@ display: flex; align-items: center; .selected-icon-inner-container{ - height: 64px; - width: 64px; + height: 60px; + width: 60px; margin: 0 auto; } .update-component-icon{ position: relative; float: right; cursor: pointer; + z-index: 1; } .selected-icon{ position: relative; top: -20px; - z-index: -1; &.disable{ position: inherit; } @@ -137,7 +148,22 @@ } + .unsaved-file-warning { + border: solid 1px #ffb81c; + padding: 5px 8px; + display: flex; + align-items: center; + color: #ffb81c; + margin-right: 10px; + border-radius: 2px; + .sdc-warning { + margin-right:4px; + } + } + .revert-btn { + margin-left: 10px; + } } diff --git a/catalog-ui/src/app/view-models/workspace/tabs/inputs/resource-input/resource-inputs-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/inputs/resource-input/resource-inputs-view-model.ts index 2a7cd3dd65..4b9d314a38 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/inputs/resource-input/resource-inputs-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/inputs/resource-input/resource-inputs-view-model.ts @@ -17,121 +17,121 @@ * limitations under the License. * ============LICENSE_END========================================================= */ - -'use strict'; -import * as _ from "lodash"; -import {IWorkspaceViewModelScope} from "app/view-models/workspace/workspace-view-model"; -import {ComponentInstance, InstancesInputsOrPropertiesMapData, Resource, PropertyModel, InputModel} from "app/models"; -import {ModalsHandler} from "app/utils"; - -export interface IInputsViewModelScope extends IWorkspaceViewModelScope { - InstanceInputsProperties:InstancesInputsOrPropertiesMapData; //this is tha map object that hold the selected inputs and the inputs we already used - vfInstancesList:Array<ComponentInstance>; - component:Resource; - - onArrowPressed():void; - getInputPropertiesForInstance(instanceId:string, instance:ComponentInstance):ng.IPromise<boolean> ; - loadInputPropertiesForInstance(instanceId:string, input:InputModel):ng.IPromise<boolean> ; - openEditValueModal(input:InputModel):void; - openEditPropertyModal(property:PropertyModel):void; -} - -export class ResourceInputsViewModel { - - static '$inject' = [ - '$scope', - '$q', - 'ModalsHandler' - ]; - - constructor(private $scope:IInputsViewModelScope, private $q:ng.IQService, private ModalsHandler:ModalsHandler) { - this.initScope(); - } - - private initScope = ():void => { - - this.$scope.InstanceInputsProperties = new InstancesInputsOrPropertiesMapData(); - this.$scope.vfInstancesList = this.$scope.component.componentInstances; - - // Need to cast all inputs to InputModel for the search to work - let tmpInputs:Array<InputModel> = new Array<InputModel>(); - _.each(this.$scope.component.inputs, (input):void => { - tmpInputs.push(new InputModel(input)); - }); - this.$scope.component.inputs = tmpInputs; - // This function is not supported for resource - //this.$scope.component.getComponentInputs(); - - /* - * When clicking on instance input in the left or right table, this function will load all properties of the selected input - */ - this.$scope.getInputPropertiesForInstance = (instanceId:string, instance:ComponentInstance):ng.IPromise<boolean> => { - let deferred = this.$q.defer(); - instance.properties = this.$scope.component.componentInstancesProperties[instanceId]; - deferred.resolve(true); - return deferred.promise; - }; - - /* - * When clicking on instance input in the left or right table, this function will load all properties of the selected input - */ - this.$scope.loadInputPropertiesForInstance = (instanceId:string, input:InputModel):ng.IPromise<boolean> => { - let deferred = this.$q.defer(); - - let onSuccess = (properties:Array<PropertyModel>) => { - input.properties = properties; - deferred.resolve(true); - }; - - let onError = () => { - deferred.resolve(false) - }; - - if (!input.properties) { - this.$scope.component.getComponentInstanceInputProperties(instanceId, input.uniqueId).then(onSuccess, onError); - } else { - deferred.resolve(true); - } - return deferred.promise; - }; - - /* - * When pressing the arrow, we create service inputs from the inputs selected - */ - this.$scope.onArrowPressed = ():void => { - let onSuccess = (inputsCreated:Array<InputModel>) => { - - //disabled all the inputs in the left table - _.forEach(this.$scope.InstanceInputsProperties, (properties:Array<PropertyModel>) => { - _.forEach(properties, (property:PropertyModel) => { - property.isAlreadySelected = true; - }); - }); - - // Adding color to the new inputs (right table) - _.forEach(inputsCreated, (input) => { - input.isNew = true; - }); - - // Removing color to the new inputs (right table) - setTimeout(() => { - _.forEach(inputsCreated, (input) => { - input.isNew = false; - }); - this.$scope.$apply(); - }, 3000); - }; - - this.$scope.component.createInputsFormInstances(this.$scope.InstanceInputsProperties).then(onSuccess); - }; - - this.$scope.openEditValueModal = (input:InputModel) => { - this.ModalsHandler.openEditInputValueModal(input); - }; - - this.$scope.openEditPropertyModal = (property:PropertyModel):void => { - this.ModalsHandler.openEditPropertyModal(property, this.$scope.component, this.$scope.component.componentInstancesProperties[property.resourceInstanceUniqueId], false).then(() => { - }); - } - } -} +/*********** DEPRECATED -- replaced by prop assignments */ +// 'use strict'; +// import * as _ from "lodash"; +// import {IWorkspaceViewModelScope} from "app/view-models/workspace/workspace-view-model"; +// import {ComponentInstance, InstancesInputsOrPropertiesMapData, Resource, PropertyModel, InputModel} from "app/models"; +// import {ModalsHandler} from "app/utils"; + +// export interface IInputsViewModelScope extends IWorkspaceViewModelScope { +// InstanceInputsProperties:InstancesInputsOrPropertiesMapData; //this is tha map object that hold the selected inputs and the inputs we already used +// vfInstancesList:Array<ComponentInstance>; +// component:Resource; + +// onArrowPressed():void; +// getInputPropertiesForInstance(instanceId:string, instance:ComponentInstance):ng.IPromise<boolean> ; +// loadInputPropertiesForInstance(instanceId:string, input:InputModel):ng.IPromise<boolean> ; +// openEditValueModal(input:InputModel):void; +// openEditPropertyModal(property:PropertyModel):void; +// } + +// export class ResourceInputsViewModel { + +// static '$inject' = [ +// '$scope', +// '$q', +// 'ModalsHandler' +// ]; + +// constructor(private $scope:IInputsViewModelScope, private $q:ng.IQService, private ModalsHandler:ModalsHandler) { +// this.initScope(); +// } + +// private initScope = ():void => { + +// this.$scope.InstanceInputsProperties = new InstancesInputsOrPropertiesMapData(); +// this.$scope.vfInstancesList = this.$scope.component.componentInstances; + +// // Need to cast all inputs to InputModel for the search to work +// let tmpInputs:Array<InputModel> = new Array<InputModel>(); +// _.each(this.$scope.component.inputs, (input):void => { +// tmpInputs.push(new InputModel(input)); +// }); +// this.$scope.component.inputs = tmpInputs; +// // This function is not supported for resource +// //this.$scope.component.getComponentInputs(); + +// /* +// * When clicking on instance input in the left or right table, this function will load all properties of the selected input +// */ +// this.$scope.getInputPropertiesForInstance = (instanceId:string, instance:ComponentInstance):ng.IPromise<boolean> => { +// let deferred = this.$q.defer<boolean>(); +// instance.properties = this.$scope.component.componentInstancesProperties[instanceId]; +// deferred.resolve(true); +// return deferred.promise; +// }; + +// /* +// * When clicking on instance input in the left or right table, this function will load all properties of the selected input +// */ +// this.$scope.loadInputPropertiesForInstance = (instanceId:string, input:InputModel):ng.IPromise<boolean> => { +// let deferred = this.$q.defer<boolean>(); + +// let onSuccess = (properties:Array<PropertyModel>) => { +// input.properties = properties; +// deferred.resolve(true); +// }; + +// let onError = () => { +// deferred.resolve(false) +// }; + +// if (!input.properties) { +// this.$scope.component.getComponentInstanceInputProperties(instanceId, input.uniqueId).then(onSuccess, onError); +// } else { +// deferred.resolve(true); +// } +// return deferred.promise; +// }; + +// /* +// * When pressing the arrow, we create service inputs from the inputs selected +// */ +// this.$scope.onArrowPressed = ():void => { +// let onSuccess = (inputsCreated:Array<InputModel>) => { + +// //disabled all the inputs in the left table +// _.forEach(this.$scope.InstanceInputsProperties, (properties:Array<PropertyModel>) => { +// _.forEach(properties, (property:PropertyModel) => { +// property.isAlreadySelected = true; +// }); +// }); + +// // Adding color to the new inputs (right table) +// _.forEach(inputsCreated, (input) => { +// input.isNew = true; +// }); + +// // Removing color to the new inputs (right table) +// setTimeout(() => { +// _.forEach(inputsCreated, (input) => { +// input.isNew = false; +// }); +// this.$scope.$apply(); +// }, 3000); +// }; + +// this.$scope.component.createInputsFormInstances(this.$scope.InstanceInputsProperties).then(onSuccess); +// }; + +// this.$scope.openEditValueModal = (input:InputModel) => { +// this.ModalsHandler.openEditInputValueModal(input); +// }; + +// this.$scope.openEditPropertyModal = (property:PropertyModel):void => { +// this.ModalsHandler.openEditPropertyModal(property, this.$scope.component, this.$scope.component.componentInstancesProperties[property.resourceInstanceUniqueId], false).then(() => { +// }); +// } +// } +// }
\ No newline at end of file diff --git a/catalog-ui/src/app/view-models/workspace/tabs/inputs/service-input/service-inputs-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/inputs/service-input/service-inputs-view-model.ts index bdbc0a4334..5e69f5bed6 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/inputs/service-input/service-inputs-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/inputs/service-input/service-inputs-view-model.ts @@ -17,382 +17,382 @@ * limitations under the License. * ============LICENSE_END========================================================= */ - -'use strict'; -import * as _ from "lodash"; -import {IWorkspaceViewModelScope} from "app/view-models/workspace/workspace-view-model"; -import {ComponentInstance, InstancesInputsOrPropertiesMapData, Service, IAppMenu, InputModel, PropertyModel, InputPropertyBase} from "app/models"; -import {DataTypesService} from "app/services"; -import {ModalsHandler, ResourceType} from "app/utils"; - - -interface IServiceInputsViewModelScope extends IWorkspaceViewModelScope { - - vfInstancesList:Array<ComponentInstance>; - instanceInputsMap:InstancesInputsOrPropertiesMapData; //this is tha map object that hold the selected inputs and the inputs we already used - instancePropertiesMap:InstancesInputsOrPropertiesMapData; - component:Service; - sdcMenu:IAppMenu; - isViewOnly:boolean; - isArrowDisabled:boolean; - onArrowPressed():void; - checkArrowState():void; - loadComponentInputs():void; - loadInstanceInputs(instance:ComponentInstance):ng.IPromise<boolean> ; - loadInstanceProperties(instance:ComponentInstance):ng.IPromise<boolean> ; - loadInputPropertiesForInstance(instanceId:string, input:InputModel):ng.IPromise<boolean> ; - loadInputInputs(input:InputModel):ng.IPromise<boolean>; - deleteInput(input:InputModel):void - openEditValueModal(input:InputModel):void; - openSelectPropertyDataTypeViewModel(instanceId:string, property:PropertyModel):void; - openEditPropertyDataTypeViewModel(property:PropertyModel):void; - dataTypesService:DataTypesService; -} - -export class ServiceInputsViewModel { - - static '$inject' = [ - '$scope', - '$q', - 'ModalsHandler', - 'Sdc.Services.DataTypesService' - ]; - - constructor(private $scope:IServiceInputsViewModelScope, - private $q:ng.IQService, - private ModalsHandler:ModalsHandler, - private DataTypesService:DataTypesService) { - this.initScope(); - this.$scope.isViewOnly = this.$scope.isViewMode(); - } - - - private getInputsOrPropertiesAlreadySelected = (instanceNormalizeName:string, arrayToFilter:Array<InputPropertyBase>):Array<any> => { - let alreadySelectedInput = []; - _.forEach(arrayToFilter, (inputOrProperty:InputPropertyBase) => { - let expectedServiceInputName = instanceNormalizeName + '_' + inputOrProperty.name; - let inputAlreadyInService = _.find(this.$scope.component.inputs, (serviceInput:InputModel) => { - //Checking if the input prefix is the instance name + '_' + property/input name (prefix because we don't need to check full name for complex dataType) - return serviceInput.name.substring(0, expectedServiceInputName.length) === expectedServiceInputName; - }); - if (inputAlreadyInService) { - inputOrProperty.isAlreadySelected = true; - alreadySelectedInput.push(inputOrProperty); - } else { - inputOrProperty.isAlreadySelected = false; - } - }); - return alreadySelectedInput; - }; - - - /* - * When loading the screen again, we need to disabled the inputs that already created on the service, - * we do that by comparing the service input name, to the instance name + '_' + the resource instance input name. - */ - private disableEnableSelectedInputsOrPropertiesOnInit = (instance:ComponentInstance):void => { - - if (instance.originType === ResourceType.VF) { - this.$scope.instanceInputsMap[instance.uniqueId] = this.getInputsOrPropertiesAlreadySelected(instance.normalizedName, instance.inputs); - } else { - this.$scope.instancePropertiesMap[instance.uniqueId] = this.getInputsOrPropertiesAlreadySelected(instance.normalizedName, instance.properties); - } - }; - - /* - * Enable Input/Property after delete - */ - private enableInputsAfterDelete = (propertiesOrInputsDeletes:Array<InputPropertyBase>):void => { - - _.forEach(propertiesOrInputsDeletes, (deletedInputInput:InputPropertyBase) => { //Enable all component instance inputs deleted - - let inputOrPropertyDeleted:InputPropertyBase = _.find(this.$scope.instanceInputsMap[deletedInputInput.componentInstanceId], (inputOrProperty:InputPropertyBase) => { - return inputOrProperty.uniqueId === deletedInputInput.uniqueId; - }); - inputOrPropertyDeleted.isAlreadySelected = false; - delete _.remove(this.$scope.instanceInputsMap[deletedInputInput.componentInstanceId], {uniqueId: inputOrPropertyDeleted.uniqueId})[0]; - }); - }; - - /* - * Enable Input/Property after delete - */ - private enablePropertiesAfterDelete = (propertiesOrInputsDeletes:Array<InputPropertyBase>):void => { - - _.forEach(propertiesOrInputsDeletes, (deletedInputInput:InputPropertyBase) => { //Enable all component instance inputs deleted - let componentInstance = _.find(this.$scope.vfInstancesList, (instance:ComponentInstance) => { - return instance.uniqueId === deletedInputInput.componentInstanceId; - }); - let inputOrPropertyDeleted:InputPropertyBase = _.find(this.$scope.instancePropertiesMap[deletedInputInput.componentInstanceId], (inputOrProperty:InputPropertyBase) => { - return inputOrProperty.uniqueId === deletedInputInput.uniqueId; - }); - - let expectedName = componentInstance.normalizedName + '_' + inputOrPropertyDeleted.name; - let isAnotherInputExist = _.find(this.$scope.component.inputs, (input:InputModel) => { - return input.name.substring(0, expectedName.length) === expectedName; - }); - if (!isAnotherInputExist) { - inputOrPropertyDeleted.isAlreadySelected = false; - delete _.remove(this.$scope.instancePropertiesMap[deletedInputInput.componentInstanceId], {uniqueId: inputOrPropertyDeleted.uniqueId})[0]; - } - }); - }; - - private initScope = ():void => { - - this.$scope.instanceInputsMap = new InstancesInputsOrPropertiesMapData(); - this.$scope.instancePropertiesMap = new InstancesInputsOrPropertiesMapData(); - this.$scope.isLoading = true; - this.$scope.isArrowDisabled = true; - // Why do we need this? we call this later. - //this.$scope.component.getComponentInputs(); - - let onSuccess = (componentInstances:Array<ComponentInstance>) => { - console.log("component instances loaded: ", componentInstances); - this.$scope.vfInstancesList = componentInstances; - this.$scope.isLoading = false; - }; - - //This function will get al component instance for the left table - in - // future the instances will be filter according to search text - this.$scope.component.getComponentInstancesFilteredByInputsAndProperties().then(onSuccess); - - // This function will get the service inputs for the right table - this.$scope.component.getComponentInputs(); - - /* - * When clicking on instance in the left table, this function will load all instance inputs - */ - this.$scope.loadInstanceInputs = (instance:ComponentInstance):ng.IPromise<boolean> => { - let deferred = this.$q.defer(); - - let onSuccess = (inputs:Array<InputModel>) => { - instance.inputs = inputs; - this.disableEnableSelectedInputsOrPropertiesOnInit(instance); - deferred.resolve(true); - }; - - let onError = () => { - deferred.resolve(false); - }; - - if (!instance.inputs) { - this.$scope.component.getComponentInstanceInputs(instance.uniqueId, instance.componentUid).then(onSuccess, onError); - //this.disableEnableSelectedInputs(instance); - } else { - deferred.resolve(true); - } - return deferred.promise; - }; - - - this.$scope.loadInstanceProperties = (instance:ComponentInstance):ng.IPromise<boolean> => { - let deferred = this.$q.defer(); - - let onSuccess = (properties:Array<PropertyModel>) => { - instance.properties = properties; - this.disableEnableSelectedInputsOrPropertiesOnInit(instance); - deferred.resolve(true); - }; - - let onError = () => { - deferred.resolve(false); - }; - - if (!instance.properties) { - this.$scope.component.getComponentInstanceProperties(instance.uniqueId).then(onSuccess, onError); - } else { - deferred.resolve(true); - } - return deferred.promise; - }; - - /* - * When clicking on instance input in the left or right table, this function will load all properties of the selected input - */ - this.$scope.loadInputPropertiesForInstance = (instanceId:string, input:InputModel):ng.IPromise<boolean> => { - let deferred = this.$q.defer(); - - let onSuccess = (properties:Array<PropertyModel>) => { - input.properties = properties; - deferred.resolve(true); - }; - - let onError = () => { - deferred.resolve(false) - }; - - if (!input.properties) { - this.$scope.component.getComponentInstanceInputProperties(instanceId, input.uniqueId).then(onSuccess, onError); - } else { - deferred.resolve(true); - } - return deferred.promise; - }; - - /* - * When clicking on input in the right table, this function will load all inputs of the selected input - */ - this.$scope.loadInputInputs = (input:InputModel):ng.IPromise<boolean> => { - let deferred = this.$q.defer(); - - let onSuccess = () => { - deferred.resolve(true); - }; - let onError = () => { - deferred.resolve(false); - }; - - if (!input.inputs) { // Caching, if exists do not get it. - this.$scope.component.getServiceInputInputsAndProperties(input.uniqueId).then(onSuccess, onError); - } else { - deferred.resolve(true); - } - return deferred.promise; - }; - - /* - * When pressing the arrow, we create service inputs from the inputs selected - */ - this.$scope.onArrowPressed = ():void => { - let onSuccess = (inputsCreated:Array<InputModel>) => { - - //disabled all the inputs in the left table - _.forEach(this.$scope.instanceInputsMap, (inputs:Array<InputModel>, instanceId:string) => { - _.forEach(inputs, (input:InputModel) => { - input.isAlreadySelected = true; - }); - }); - _.forEach(this.$scope.instancePropertiesMap, (properties:Array<PropertyModel>, instanceId:string) => { - _.forEach(properties, (property:PropertyModel) => { - property.isAlreadySelected = true; - }); - }); - this.addColorToItems(inputsCreated); - }; - - let onFailed = (error:any) => { - this.$scope.isArrowDisabled = false; - console.log("Error declaring input/property"); - }; - - this.$scope.isArrowDisabled = true; - this.$scope.component.createInputsFormInstances(this.$scope.instanceInputsMap, this.$scope.instancePropertiesMap).then(onSuccess, onFailed); - }; - - - /* Iterates through array of selected inputs and properties and returns true if there is at least one new selection on left */ - this.$scope.checkArrowState = ()=> { - - let newInputSelected:boolean = _.some(this.$scope.instanceInputsMap, (inputs:Array<InputModel>) => { - return _.some(inputs, (input:InputModel)=> { - return input.isAlreadySelected === false; - }); - }); - - let newPropSelected:boolean = _.some(this.$scope.instancePropertiesMap, (properties:Array<PropertyModel>) => { - return _.some(properties, (property:PropertyModel) => { - return property.isAlreadySelected === false; - }); - }); - - this.$scope.isArrowDisabled = !(newInputSelected || newPropSelected); - - }; - - this.$scope.deleteInput = (inputToDelete:InputModel):void => { - - let onDelete = ():void => { - - let onSuccess = (deletedInput:InputModel):void => { - if (deletedInput.inputs && deletedInput.inputs.length > 0) { // Enable input declared from input - this.enableInputsAfterDelete(deletedInput.inputs); - } - - if (deletedInput.properties && deletedInput.properties.length > 0) { // Enable properties - this.enablePropertiesAfterDelete(deletedInput.properties); - } - deletedInput.isDeleteDisabled = false; - this.$scope.checkArrowState(); - - }; - - let onFailed = (error:any):void => { - console.log("Error deleting input"); - inputToDelete.isDeleteDisabled = false; - }; - - inputToDelete.isDeleteDisabled = true; - this.addColorToItems([inputToDelete]); - this.$scope.component.deleteServiceInput(inputToDelete.uniqueId).then((deletedInput:InputModel):void => { - onSuccess(deletedInput); - }, onFailed); - }; - - // Get confirmation modal text from menu.json - let state = "deleteInput"; - let title:string = this.$scope.sdcMenu.alertMessages[state].title; - let message:string = this.$scope.sdcMenu.alertMessages[state].message.format([inputToDelete.name]); - - // Open confirmation modal - this.ModalsHandler.openAlertModal(title, message).then(onDelete); - }; - - this.$scope.openEditValueModal = (input:InputModel) => { - this.ModalsHandler.openEditInputValueModal(input); - }; - - this.$scope.openSelectPropertyDataTypeViewModel = (instanceId:string, property:PropertyModel) => { - //to open the select data type modal - let selectedInstance = _.find(this.$scope.vfInstancesList, {uniqueId: instanceId}); - this.DataTypesService.selectedInstance = selectedInstance; //set the selected instance on the service for compering the input name on the service & the complex property - this.DataTypesService.selectedComponentInputs = this.$scope.component.inputs; // set all the service inputs on the data type service - let filteredPropertiesMap = _.filter(this.$scope.instancePropertiesMap[instanceId], (instanceProperty)=> { - return instanceProperty.name == property.name; - });//get all properties under the specific property - this.DataTypesService.selectedPropertiesName = property.propertiesName; - - this.ModalsHandler.openSelectDataTypeModal(property, this.$scope.component, this.$scope.component.properties, filteredPropertiesMap).then((selectedProperty:PropertyModel)=> { - if (selectedProperty && selectedProperty.propertiesName) { - let propertyToUpdate:PropertyModel = _.find(selectedInstance.properties, {uniqueId: selectedProperty.uniqueId}); - let existingProperty:PropertyModel = (<PropertyModel>_.find(this.$scope.instancePropertiesMap[instanceId], {uniqueId: propertyToUpdate.uniqueId})); - - if (existingProperty) { - existingProperty.propertiesName = selectedProperty.propertiesName; - existingProperty.input = selectedProperty.input; - existingProperty.isAlreadySelected = false; - } else { - propertyToUpdate.propertiesName = selectedProperty.propertiesName; - propertyToUpdate.input = selectedProperty.input; - this.$scope.instancePropertiesMap[instanceId].push(propertyToUpdate); - - } - this.$scope.checkArrowState(); - - } - }); - }; - - - this.$scope.openEditPropertyDataTypeViewModel = (property:PropertyModel)=> { - this.ModalsHandler.openEditPropertyModal(property, this.$scope.component, this.$scope.component.properties, false).then(() => { - }); - } - }; - - private addColorToItems = (inputsCreated:Array<InputModel>):void => { - - // Adding color to the new inputs (right table) - _.forEach(inputsCreated, (input) => { - input.isNew = true; - }); - - // Removing color to the new inputs (right table) - setTimeout(() => { - _.forEach(inputsCreated, (input) => { - input.isNew = false; - }); - this.$scope.$apply(); - }, 3000); - }; -} +/***** DEPRECATED - replaced by prop assignments */ +// 'use strict'; +// import * as _ from "lodash"; +// import {IWorkspaceViewModelScope} from "app/view-models/workspace/workspace-view-model"; +// import {ComponentInstance, InstancesInputsOrPropertiesMapData, Service, IAppMenu, InputModel, PropertyModel, InputPropertyBase} from "app/models"; +// import {DataTypesService} from "app/services"; +// import {ModalsHandler, ResourceType} from "app/utils"; + + +// interface IServiceInputsViewModelScope extends IWorkspaceViewModelScope { + +// vfInstancesList:Array<ComponentInstance>; +// instanceInputsMap:InstancesInputsOrPropertiesMapData; //this is tha map object that hold the selected inputs and the inputs we already used +// instancePropertiesMap:InstancesInputsOrPropertiesMapData; +// component:Service; +// sdcMenu:IAppMenu; +// isViewOnly:boolean; +// isArrowDisabled:boolean; +// onArrowPressed():void; +// checkArrowState():void; +// loadComponentInputs():void; +// loadInstanceInputs(instance:ComponentInstance):ng.IPromise<boolean> ; +// loadInstanceProperties(instance:ComponentInstance):ng.IPromise<boolean> ; +// loadInputPropertiesForInstance(instanceId:string, input:InputModel):ng.IPromise<boolean> ; +// loadInputInputs(input:InputModel):ng.IPromise<boolean>; +// deleteInput(input:InputModel):void +// openEditValueModal(input:InputModel):void; +// openSelectPropertyDataTypeViewModel(instanceId:string, property:PropertyModel):void; +// openEditPropertyDataTypeViewModel(property:PropertyModel):void; +// dataTypesService:DataTypesService; +// } + +// export class ServiceInputsViewModel { + +// static '$inject' = [ +// '$scope', +// '$q', +// 'ModalsHandler', +// 'Sdc.Services.DataTypesService' +// ]; + +// constructor(private $scope:IServiceInputsViewModelScope, +// private $q:ng.IQService, +// private ModalsHandler:ModalsHandler, +// private DataTypesService:DataTypesService) { +// this.initScope(); +// this.$scope.isViewOnly = this.$scope.isViewMode(); +// } + + +// private getInputsOrPropertiesAlreadySelected = (instanceNormalizeName:string, arrayToFilter:Array<InputPropertyBase>):Array<any> => { +// let alreadySelectedInput = []; +// _.forEach(arrayToFilter, (inputOrProperty:InputPropertyBase) => { +// let expectedServiceInputName = instanceNormalizeName + '_' + inputOrProperty.name; +// let inputAlreadyInService = _.find(this.$scope.component.inputs, (serviceInput:InputModel) => { +// //Checking if the input prefix is the instance name + '_' + property/input name (prefix because we don't need to check full name for complex dataType) +// return serviceInput.name.substring(0, expectedServiceInputName.length) === expectedServiceInputName; +// }); +// if (inputAlreadyInService) { +// inputOrProperty.isAlreadySelected = true; +// alreadySelectedInput.push(inputOrProperty); +// } else { +// inputOrProperty.isAlreadySelected = false; +// } +// }); +// return alreadySelectedInput; +// }; + + +// /* +// * When loading the screen again, we need to disabled the inputs that already created on the service, +// * we do that by comparing the service input name, to the instance name + '_' + the resource instance input name. +// */ +// private disableEnableSelectedInputsOrPropertiesOnInit = (instance:ComponentInstance):void => { + +// if (instance.originType === ResourceType.VF) { +// this.$scope.instanceInputsMap[instance.uniqueId] = this.getInputsOrPropertiesAlreadySelected(instance.normalizedName, instance.inputs); +// } else { +// this.$scope.instancePropertiesMap[instance.uniqueId] = this.getInputsOrPropertiesAlreadySelected(instance.normalizedName, instance.properties); +// } +// }; + +// /* +// * Enable Input/Property after delete +// */ +// private enableInputsAfterDelete = (propertiesOrInputsDeletes:Array<InputPropertyBase>):void => { + +// _.forEach(propertiesOrInputsDeletes, (deletedInputInput:InputPropertyBase) => { //Enable all component instance inputs deleted + +// let inputOrPropertyDeleted:InputPropertyBase = _.find(this.$scope.instanceInputsMap[deletedInputInput.componentInstanceId], (inputOrProperty:InputPropertyBase) => { +// return inputOrProperty.uniqueId === deletedInputInput.uniqueId; +// }); +// inputOrPropertyDeleted.isAlreadySelected = false; +// delete _.remove(this.$scope.instanceInputsMap[deletedInputInput.componentInstanceId], {uniqueId: inputOrPropertyDeleted.uniqueId})[0]; +// }); +// }; + +// /* +// * Enable Input/Property after delete +// */ +// private enablePropertiesAfterDelete = (propertiesOrInputsDeletes:Array<InputPropertyBase>):void => { + +// _.forEach(propertiesOrInputsDeletes, (deletedInputInput:InputPropertyBase) => { //Enable all component instance inputs deleted +// let componentInstance = _.find(this.$scope.vfInstancesList, (instance:ComponentInstance) => { +// return instance.uniqueId === deletedInputInput.componentInstanceId; +// }); +// let inputOrPropertyDeleted:InputPropertyBase = _.find(this.$scope.instancePropertiesMap[deletedInputInput.componentInstanceId], (inputOrProperty:InputPropertyBase) => { +// return inputOrProperty.uniqueId === deletedInputInput.uniqueId; +// }); + +// let expectedName = componentInstance.normalizedName + '_' + inputOrPropertyDeleted.name; +// let isAnotherInputExist = _.find(this.$scope.component.inputs, (input:InputModel) => { +// return input.name.substring(0, expectedName.length) === expectedName; +// }); +// if (!isAnotherInputExist) { +// inputOrPropertyDeleted.isAlreadySelected = false; +// delete _.remove(this.$scope.instancePropertiesMap[deletedInputInput.componentInstanceId], {uniqueId: inputOrPropertyDeleted.uniqueId})[0]; +// } +// }); +// }; + +// private initScope = ():void => { + +// this.$scope.instanceInputsMap = new InstancesInputsOrPropertiesMapData(); +// this.$scope.instancePropertiesMap = new InstancesInputsOrPropertiesMapData(); +// this.$scope.isLoading = true; +// this.$scope.isArrowDisabled = true; +// // Why do we need this? we call this later. +// //this.$scope.component.getComponentInputs(); + +// let onSuccess = (componentInstances:Array<ComponentInstance>) => { +// console.log("component instances loaded: ", componentInstances); +// this.$scope.vfInstancesList = componentInstances; +// this.$scope.isLoading = false; +// }; + +// //This function will get al component instance for the left table - in +// // future the instances will be filter according to search text +// this.$scope.component.getComponentInstancesFilteredByInputsAndProperties().then(onSuccess); + +// // This function will get the service inputs for the right table +// this.$scope.component.getComponentInputs(); + +// /* +// * When clicking on instance in the left table, this function will load all instance inputs +// */ +// this.$scope.loadInstanceInputs = (instance:ComponentInstance):ng.IPromise<boolean> => { +// let deferred = this.$q.defer<boolean>(); + +// let onSuccess = (inputs:Array<InputModel>) => { +// instance.inputs = inputs; +// this.disableEnableSelectedInputsOrPropertiesOnInit(instance); +// deferred.resolve(true); +// }; + +// let onError = () => { +// deferred.resolve(false); +// }; + +// if (!instance.inputs) { +// this.$scope.component.getComponentInstanceInputs(instance.uniqueId, instance.componentUid).then(onSuccess, onError); +// //this.disableEnableSelectedInputs(instance); +// } else { +// deferred.resolve(true); +// } +// return deferred.promise; +// }; + + +// this.$scope.loadInstanceProperties = (instance:ComponentInstance):ng.IPromise<boolean> => { +// let deferred = this.$q.defer<boolean>(); + +// let onSuccess = (properties:Array<PropertyModel>) => { +// instance.properties = properties; +// this.disableEnableSelectedInputsOrPropertiesOnInit(instance); +// deferred.resolve(true); +// }; + +// let onError = () => { +// deferred.resolve(false); +// }; + +// if (!instance.properties) { +// this.$scope.component.getComponentInstanceProperties(instance.uniqueId).then(onSuccess, onError); +// } else { +// deferred.resolve(true); +// } +// return deferred.promise; +// }; + +// /* +// * When clicking on instance input in the left or right table, this function will load all properties of the selected input +// */ +// this.$scope.loadInputPropertiesForInstance = (instanceId:string, input:InputModel):ng.IPromise<boolean> => { +// let deferred = this.$q.defer<boolean>(); + +// let onSuccess = (properties:Array<PropertyModel>) => { +// input.properties = properties; +// deferred.resolve(true); +// }; + +// let onError = () => { +// deferred.resolve(false) +// }; + +// if (!input.properties) { +// this.$scope.component.getComponentInstanceInputProperties(instanceId, input.uniqueId).then(onSuccess, onError); +// } else { +// deferred.resolve(true); +// } +// return deferred.promise; +// }; + +// /* +// * When clicking on input in the right table, this function will load all inputs of the selected input +// */ +// this.$scope.loadInputInputs = (input:InputModel):ng.IPromise<boolean> => { +// let deferred = this.$q.defer<boolean>(); + +// let onSuccess = () => { +// deferred.resolve(true); +// }; +// let onError = () => { +// deferred.resolve(false); +// }; + +// if (!input.inputs) { // Caching, if exists do not get it. +// this.$scope.component.getServiceInputInputsAndProperties(input.uniqueId).then(onSuccess, onError); +// } else { +// deferred.resolve(true); +// } +// return deferred.promise; +// }; + +// /* +// * When pressing the arrow, we create service inputs from the inputs selected +// */ +// this.$scope.onArrowPressed = ():void => { +// let onSuccess = (inputsCreated:Array<InputModel>) => { + +// //disabled all the inputs in the left table +// _.forEach(this.$scope.instanceInputsMap, (inputs:Array<InputModel>, instanceId:string) => { +// _.forEach(inputs, (input:InputModel) => { +// input.isAlreadySelected = true; +// }); +// }); +// _.forEach(this.$scope.instancePropertiesMap, (properties:Array<PropertyModel>, instanceId:string) => { +// _.forEach(properties, (property:PropertyModel) => { +// property.isAlreadySelected = true; +// }); +// }); +// this.addColorToItems(inputsCreated); +// }; + +// let onFailed = (error:any) => { +// this.$scope.isArrowDisabled = false; +// console.log("Error declaring input/property"); +// }; + +// this.$scope.isArrowDisabled = true; +// this.$scope.component.createInputsFormInstances(this.$scope.instanceInputsMap, this.$scope.instancePropertiesMap).then(onSuccess, onFailed); +// }; + + +// /* Iterates through array of selected inputs and properties and returns true if there is at least one new selection on left */ +// this.$scope.checkArrowState = ()=> { + +// let newInputSelected:boolean = _.some(this.$scope.instanceInputsMap, (inputs:Array<InputModel>) => { +// return _.some(inputs, (input:InputModel)=> { +// return input.isAlreadySelected === false; +// }); +// }); + +// let newPropSelected:boolean = _.some(this.$scope.instancePropertiesMap, (properties:Array<PropertyModel>) => { +// return _.some(properties, (property:PropertyModel) => { +// return property.isAlreadySelected === false; +// }); +// }); + +// this.$scope.isArrowDisabled = !(newInputSelected || newPropSelected); + +// }; + +// this.$scope.deleteInput = (inputToDelete:InputModel):void => { + +// let onDelete = ():void => { + +// let onSuccess = (deletedInput:InputModel):void => { +// if (deletedInput.inputs && deletedInput.inputs.length > 0) { // Enable input declared from input +// this.enableInputsAfterDelete(deletedInput.inputs); +// } + +// if (deletedInput.properties && deletedInput.properties.length > 0) { // Enable properties +// this.enablePropertiesAfterDelete(deletedInput.properties); +// } +// deletedInput.isDeleteDisabled = false; +// this.$scope.checkArrowState(); + +// }; + +// let onFailed = (error:any):void => { +// console.log("Error deleting input"); +// inputToDelete.isDeleteDisabled = false; +// }; + +// inputToDelete.isDeleteDisabled = true; +// this.addColorToItems([inputToDelete]); +// this.$scope.component.deleteServiceInput(inputToDelete.uniqueId).then((deletedInput:InputModel):void => { +// onSuccess(deletedInput); +// }, onFailed); +// }; + +// // Get confirmation modal text from menu.json +// let state = "deleteInput"; +// let title:string = this.$scope.sdcMenu.alertMessages[state].title; +// let message:string = this.$scope.sdcMenu.alertMessages[state].message.format([inputToDelete.name]); + +// // Open confirmation modal +// this.ModalsHandler.openAlertModal(title, message).then(onDelete); +// }; + +// this.$scope.openEditValueModal = (input:InputModel) => { +// this.ModalsHandler.openEditInputValueModal(input); +// }; + +// this.$scope.openSelectPropertyDataTypeViewModel = (instanceId:string, property:PropertyModel) => { +// //to open the select data type modal +// let selectedInstance = _.find(this.$scope.vfInstancesList, {uniqueId: instanceId}); +// this.DataTypesService.selectedInstance = selectedInstance; //set the selected instance on the service for compering the input name on the service & the complex property +// this.DataTypesService.selectedComponentInputs = this.$scope.component.inputs; // set all the service inputs on the data type service +// let filteredPropertiesMap = _.filter(this.$scope.instancePropertiesMap[instanceId], (instanceProperty)=> { +// return instanceProperty.name == property.name; +// });//get all properties under the specific property +// this.DataTypesService.selectedPropertiesName = property.propertiesName; + +// this.ModalsHandler.openSelectDataTypeModal(property, this.$scope.component, this.$scope.component.properties, filteredPropertiesMap).then((selectedProperty:PropertyModel)=> { +// if (selectedProperty && selectedProperty.propertiesName) { +// let propertyToUpdate:PropertyModel = _.find(selectedInstance.properties, {uniqueId: selectedProperty.uniqueId}); +// let existingProperty:PropertyModel = (<PropertyModel>_.find(this.$scope.instancePropertiesMap[instanceId], {uniqueId: propertyToUpdate.uniqueId})); + +// if (existingProperty) { +// existingProperty.propertiesName = selectedProperty.propertiesName; +// existingProperty.input = selectedProperty.input; +// existingProperty.isAlreadySelected = false; +// } else { +// propertyToUpdate.propertiesName = selectedProperty.propertiesName; +// propertyToUpdate.input = selectedProperty.input; +// this.$scope.instancePropertiesMap[instanceId].push(propertyToUpdate); + +// } +// this.$scope.checkArrowState(); + +// } +// }); +// }; + + +// this.$scope.openEditPropertyDataTypeViewModel = (property:PropertyModel)=> { +// this.ModalsHandler.openEditPropertyModal(property, this.$scope.component, this.$scope.component.properties, false).then(() => { +// }); +// } +// }; + +// private addColorToItems = (inputsCreated:Array<InputModel>):void => { + +// // Adding color to the new inputs (right table) +// _.forEach(inputsCreated, (input) => { +// input.isNew = true; +// }); + +// // Removing color to the new inputs (right table) +// setTimeout(() => { +// _.forEach(inputsCreated, (input) => { +// input.isNew = false; +// }); +// this.$scope.$apply(); +// }, 3000); +// }; +// } diff --git a/catalog-ui/src/app/view-models/workspace/tabs/properties/properties-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/properties/properties-view-model.ts index 0360c9c805..b09662d7a2 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/properties/properties-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/properties/properties-view-model.ts @@ -71,7 +71,7 @@ export class PropertiesViewModel { } private openEditPropertyModal = (property:PropertyModel):void => { - this.ModalsHandler.openEditPropertyModal(property, this.$scope.component, this.$scope.filteredProperties, false).then((updatedProperty:PropertyModel) => { + this.ModalsHandler.openEditPropertyModal(property, this.$scope.component, this.$scope.filteredProperties, false, 'component', this.$scope.component.uniqueId).then((updatedProperty:PropertyModel) => { //property = updatedProperty; }); }; diff --git a/catalog-ui/src/app/view-models/workspace/tabs/req-and-capabilities/req-and-capabilities-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/req-and-capabilities/req-and-capabilities-view-model.ts index f63ab1ccbc..6eaae44eb2 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/req-and-capabilities/req-and-capabilities-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/req-and-capabilities/req-and-capabilities-view-model.ts @@ -93,7 +93,7 @@ export class ReqAndCapabilitiesViewModel { _.forEach(this.$scope.filteredProperties[indexInFilteredProperties], (prop:PropertyModel)=> { prop.readonly = true; }); - this.ModalsHandler.openEditPropertyModal(property, this.$scope.component, this.$scope.filteredProperties[indexInFilteredProperties], false).then(() => { + this.ModalsHandler.openEditPropertyModal(property, this.$scope.component, this.$scope.filteredProperties[indexInFilteredProperties], false, "component", this.$scope.component.uniqueId).then(() => { }); }; diff --git a/catalog-ui/src/app/view-models/workspace/workspace-view-model.ts b/catalog-ui/src/app/view-models/workspace/workspace-view-model.ts index 9abd7139b7..676a2d38d3 100644 --- a/catalog-ui/src/app/view-models/workspace/workspace-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/workspace-view-model.ts @@ -26,7 +26,7 @@ import * as _ from "lodash"; import {IUserProperties, IAppMenu, Resource, Component, Plugin, PluginsConfiguration, PluginDisplayOptions} from "app/models"; import { WorkspaceMode, ComponentFactory, ChangeLifecycleStateHandler, Role, ComponentState, MenuItemGroup, MenuHandler, - MenuItem, ModalsHandler, States, EVENTS, CHANGE_COMPONENT_CSAR_VERSION_FLAG, ResourceType + MenuItem, ModalsHandler, States, EVENTS, CHANGE_COMPONENT_CSAR_VERSION_FLAG, ResourceType, PREVIOUS_CSAR_COMPONENT } from "app/utils"; import { EventListenerService, @@ -36,8 +36,11 @@ import { LeftPaletteLoaderService } from "app/services"; import {FileUploadModel} from "../../directives/file-upload/file-upload"; +import {AutomatedUpgradeService} from "../../ng2/pages/automated-upgrade/automated-upgrade.service"; +import {ComponentServiceNg2} from "../../ng2/services/component-services/component.service"; import {EventBusService} from "../../ng2/services/event-bus.service"; import {PluginsService} from "../../ng2/services/plugins.service"; +import {IDependenciesServerResponse} from "../../ng2/services/responses/dependencies-server-response"; export interface IWorkspaceViewModelScope extends ng.IScope { @@ -70,23 +73,35 @@ export interface IWorkspaceViewModelScope extends ng.IScope { menuComponentTitle:string; progressService:ProgressService; progressMessage:string; + ComponentServiceNg2: ComponentServiceNg2; // leftPanelComponents:Array<Models.Components.Component>; //this is in order to load the left panel once, and not wait long time when moving to composition + unsavedChanges:boolean; + unsavedChangesCallback:Function; + unsavedFile:boolean; + + startProgress(message:string):void; + stopProgress():void; + updateBreadcrumbs(component:Component):void; + updateUnsavedFileFlag(isUnsaved:boolean):void; showChangeStateButton():boolean; getComponent():Component; setComponent(component:Component):void; + setOriginComponent(component:Component):void; onMenuItemPressed(state:string, params:any):ng.IPromise<boolean>; - save():ng.IPromise<boolean>; + create():void; + save():Promise<void>; setValidState(isValid:boolean):void; - revert():void; changeLifecycleState(state:string):void; - enabledTabs():void + handleChangeLifecycleState(state:string, newCsarVersion?:string):void; + disableMenuItems():void; + enableMenuItems():void; isDesigner():boolean; isViewMode():boolean; isEditMode():boolean; isCreateMode():boolean; isDisableMode():boolean; - showFullIcons():boolean; + isGeneralView():boolean; goToBreadcrumbHome():void; onVersionChanged(selectedId:string):void; getLatestVersion():void; @@ -120,6 +135,8 @@ export class WorkspaceViewModel { 'Notification', '$stateParams', 'Sdc.Services.ProgressService', + 'ComponentServiceNg2', + 'AutomatedUpgradeService', 'EventBusService', 'PluginsService' ]; @@ -141,8 +158,12 @@ export class WorkspaceViewModel { private Notification:any, private $stateParams:any, private progressService:ProgressService, + private ComponentServiceNg2:ComponentServiceNg2, + private AutomatedUpgradeService:AutomatedUpgradeService, private eventBusService:EventBusService, private pluginsService:PluginsService) { + + this.initScope(); this.initAfterScope(); @@ -170,22 +191,18 @@ export class WorkspaceViewModel { private initChangeLifecycleStateButtons = ():void => { let state = this.$scope.component.isService() && (Role.OPS == this.role || Role.GOVERNOR == this.role) ? this.$scope.component.distributionStatus : this.$scope.component.lifecycleState; - this.$scope.changeLifecycleStateButtons = this.sdcMenu.roles[this.role].changeLifecycleStateButtons[state]; - }; + this.$scope.changeLifecycleStateButtons = (this.sdcMenu.roles[this.role].changeLifecycleStateButtons[state] || [])[this.$scope.component.componentType.toUpperCase()]; - private isNeedSave = ():boolean => { - return this.$scope.isEditMode() && - this.$state.current.data && this.$state.current.data.unsavedChanges; }; private initLeftPalette = ():void => { - this.LeftPaletteLoaderService.loadLeftPanel(this.$scope.component); + //this.LeftPaletteLoaderService.loadLeftPanel(this.$scope.component); }; private initScope = ():void => { this.$scope.component = this.injectComponent; - this.initLeftPalette(); + //this.initLeftPalette(); this.$scope.menuComponentTitle = this.$scope.component.name; this.$scope.disabledButtons = false; this.$scope.originComponent = this.ComponentFactory.createComponent(this.$scope.component); @@ -202,7 +219,10 @@ export class WorkspaceViewModel { this.$scope.isComposition = (this.$state.current.name.indexOf(States.WORKSPACE_COMPOSITION) > -1); this.$scope.isDeployment = this.$state.current.name == States.WORKSPACE_DEPLOYMENT; this.$scope.progressService = this.progressService; - this.$scope.isActiveTopBar = true; + this.$scope.unsavedChanges = false; + + this.EventListenerService.registerObserverCallback(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, this.setWorkspaceButtonState); + //this.EventListenerService.registerObserverCallback(EVENTS.ON_UPDATE_VSP_FILE, this.updateVspFlag); this.$scope.getComponent = ():Component => { return this.$scope.component; @@ -218,19 +238,82 @@ export class WorkspaceViewModel { this.$scope.component = component; }; + this.$scope.setOriginComponent = (component:Component):void => { + this.$scope.originComponent = component; + } + this.$scope.uploadFileChangedInGeneralTab = ():void => { // In case user select browse file, and in update mode, need to disable submit for testing and checkin buttons. if (this.$scope.isEditMode() && this.$scope.component.isResource() && (<Resource>this.$scope.component).resourceType == ResourceType.VF) { - this.$scope.disabledButtons = true; + // NOTE: Commented out the disabling of the workspace buttons on CSAR updating due fix of a bug [417534] + // this.$scope.disabledButtons = true; } }; + this.$scope.archiveComponent = ():void => { + this.$scope.isLoading = true; + const typeComponent = this.$scope.component.componentType; + this.ComponentServiceNg2.archiveComponent(typeComponent, this.$scope.component.uniqueId).subscribe(()=>{ + this.$scope.isLoading = false; + if(this.$state.params.previousState){ + switch(this.$state.params.previousState){ + case 'catalog': + case 'dashboard': + this.$state.go(this.$state.params.previousState); + break; + default: + break; + } + } + this.$scope.component.archived = true; + this.deleteArchiveCache(); + + this.Notification.success({ + message: this.$scope.component.name + ' ' + this.$filter('translate')("ARCHIVE_SUCCESS_MESSAGE_TEXT"), + title: this.$filter('translate')("ARCHIVE_SUCCESS_MESSAGE_TITLE") + }); + }, (error) => { this.$scope.isLoading = false; }); + } + + this.$scope.restoreComponent = ():void => { + this.$scope.isLoading = true; + const typeComponent = this.$scope.component.componentType; + this.ComponentServiceNg2.restoreComponent(typeComponent, this.$scope.component.uniqueId).subscribe(()=>{ + this.$scope.isLoading = false; + this.Notification.success({ + message: this.$scope.component.name + ' ' + this.$filter('translate')("RESTORE_SUCCESS_MESSAGE_TEXT"), + title: this.$filter('translate')("RESTORE_SUCCESS_MESSAGE_TITLE") + }); + }); + this.$scope.component.archived = false; + this.deleteArchiveCache(); + } + + this.$scope.$on('$stateChangeStart', (event, toState, toParams, fromState, fromParams) => { + if(this.$scope.isEditMode()){ + if (fromParams.id == toParams.id && this.$state.current.data && this.$state.current.data.unsavedChanges) { + event.preventDefault(); + if(this.$scope.isValidForm){ + this.$scope.save().then(() => { + this.$scope.onMenuItemPressed(toState.name, toParams); + }, ()=> { + console.error("Save failed, unable to navigate to " + toState.name); + }) + } else { + console.error("Form is invalid, unable to navigate to " + toState.name); + } + } + } + + }); + this.$scope.$on('$stateChangeSuccess', (event, toState) => { this.$scope.updateSelectedMenuItem(this.$state.current.name); }); this.$scope.onMenuItemPressed = (state:string, params:any):ng.IPromise<boolean> => { - let deferred = this.$q.defer(); + + let deferred:ng.IDeferred<boolean> = this.$q.defer(); let goToState = ():void => { this.$state.go(state, Object.assign({ id: this.$scope.component.uniqueId, @@ -239,14 +322,8 @@ export class WorkspaceViewModel { }, params)); deferred.resolve(true); }; - if (this.isNeedSave()) { - if (this.$scope.isValidForm) { - this.$scope.save().then(goToState); - } else { - console.log('form is not valid'); - deferred.reject(false); - } - } else if (this.$scope.isEditMode() && //this is a workaround for amdocs - we need to get the artifact in order to avoid saving the vf when moving from their tabs + + if (this.$scope.isEditMode() && //this is a workaround for amdocs - we need to get the artifact in order to avoid saving the vf when moving from their tabs (this.$state.current.name === States.WORKSPACE_MANAGEMENT_WORKFLOW || this.$state.current.name === States.WORKSPACE_NETWORK_CALL_FLOW)) { let onGetSuccess = (component:Component) => { this.$scope.isLoading = false; @@ -271,7 +348,7 @@ export class WorkspaceViewModel { }; this.$scope.onVersionChanged = (selectedId:string):void => { - if (this.$state.current.data && this.$state.current.data.unsavedChanges) { + if (this.$scope.isGeneralView() && this.$state.current.data.unsavedChanges) { this.$scope.changeVersion.selectedVersion = _.find(this.$scope.versionsList, (versionObj)=> { return versionObj.versionId === this.$scope.component.uniqueId; }); @@ -298,37 +375,35 @@ export class WorkspaceViewModel { this.$scope.onVersionChanged(_.first(this.$scope.versionsList).versionId); }; - this.$scope.save = (state?:string):ng.IPromise<boolean> => { - this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_SAVE_BUTTON_CLICK); - - this.progressService.initCreateComponentProgress(this.$scope.component.uniqueId); + this.$scope.create = () => { + + this.$scope.startProgress("Creating Asset..."); + _.first(this.$scope.leftBarTabs.menuItems).isDisabled = true;//disabled click on general tab (DE246274) - let deferred = this.$q.defer(); - let modalInstance:ng.ui.bootstrap.IModalServiceInstance; + // In case we import CSAR. Notify user that import VF will take long time (the create is performed in the background). + if (this.$scope.component.isResource() && (<Resource>this.$scope.component).csarUUID) { + this.Notification.info({ + message: this.$filter('translate')("IMPORT_VF_MESSAGE_CREATE_TAKES_LONG_TIME_DESCRIPTION"), + title: this.$filter('translate')("IMPORT_VF_MESSAGE_CREATE_TAKES_LONG_TIME_TITLE") + }); + } let onFailed = () => { + this.$scope.stopProgress(); + this.$scope.isLoading = false; // stop the progress. _.first(this.$scope.leftBarTabs.menuItems).isDisabled = false;//enabled click on general tab (DE246274) this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_SAVE_BUTTON_ERROR); - this.progressService.deleteProgressValue(this.$scope.component.uniqueId); + let modalInstance:ng.ui.bootstrap.IModalServiceInstance; modalInstance && modalInstance.close(); // Close the modal in case it is opened. this.$scope.component.tags = _.without(this.$scope.component.tags, this.$scope.component.name);// for fix DE246217 - this.$scope.isCreateProgress = false; - this.$scope.isLoading = false; // stop the progress. this.$scope.setValidState(true); // Set the form valid (if sent form is valid, the error from server). - if (!this.$scope.isCreateMode()) { - this.$scope.component = this.ComponentFactory.createComponent(this.$scope.originComponent); // Set the component back to the original. - this.enableMenuItems(); // Enable the menu items (left tabs), so user can press on them. - this.$scope.disabledButtons = false; // Enable "submit for testing" & checking buttons. - } - - deferred.reject(false); }; let onSuccessCreate = (component:Component) => { + this.$scope.stopProgress(); this.showSuccessNotificationMessage(); - this.progressService.deleteProgressValue(this.$scope.component.uniqueId); // Update the components list for breadcrumbs this.components.unshift(component); @@ -337,99 +412,73 @@ export class WorkspaceViewModel { id: component.uniqueId, type: component.componentType.toLowerCase(), components: this.components - }, { inherit: false }); - - deferred.resolve(true); + }, {inherit: false}); }; - let onSuccessUpdate = (component:Component) => { - this.$scope.isCreateProgress = false; - this.$scope.disabledButtons = false; - this.showSuccessNotificationMessage(); - this.progressService.deleteProgressValue(this.$scope.component.uniqueId); + this.ComponentFactory.createComponentOnServer(this.$scope.component).then(onSuccessCreate, onFailed); - // Stop the circle loader. - this.$scope.isLoading = false; - - component.tags = _.reject(component.tags, (item)=> { - return item === component.name - }); - // Update the components list for breadcrumbs - const bcIdx = this.MenuHandler.findBreadcrumbComponentIndex(this.components, component); - if (bcIdx !== -1) { - this.components[bcIdx] = component; - this.initBreadcrumbs(); // re-calculate breadcrumbs - } + }; - // Update the component - this.$scope.component = component; - this.$scope.originComponent = this.ComponentFactory.createComponent(this.$scope.component); + this.$scope.save = ():Promise<void> => { + + this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_SAVE_BUTTON_CLICK); - // Enable left tags - this.$scope.enabledTabs(); + this.$scope.startProgress("Updating Asset..."); + this.$scope.disableMenuItems(); - if (this.$state.current.data) { - this.$state.current.data.unsavedChanges = false; + return new Promise<void>((resolve, reject) => { + let stopProgressAndEnableUI = () => { + this.$scope.disabledButtons = false; + this.$scope.isLoading = false; + this.$scope.enableMenuItems(); + this.$scope.stopProgress(); } - deferred.resolve(true); - }; - - if (this.$scope.isCreateMode()) { - this.$scope.progressMessage = "Creating Asset..."; - // CREATE MODE - this.$scope.isCreateProgress = true; + let onFailed = () => { + stopProgressAndEnableUI(); + this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_SAVE_BUTTON_ERROR); - _.first(this.$scope.leftBarTabs.menuItems).isDisabled = true;//disabled click on general tab (DE246274) + reject(); + }; - // Start creating the component - this.ComponentFactory.createComponentOnServer(this.$scope.component).then(onSuccessCreate, onFailed); + let onSuccessUpdate = (component:Component) => { + stopProgressAndEnableUI(); + this.showSuccessNotificationMessage(); - // In case we import CSAR. Notify user that import VF will take long time (the create is performed in the background). - if (this.$scope.component.isResource() && (<Resource>this.$scope.component).csarUUID) { - this.Notification.info({ - message: this.$filter('translate')("IMPORT_VF_MESSAGE_CREATE_TAKES_LONG_TIME_DESCRIPTION"), - title: this.$filter('translate')("IMPORT_VF_MESSAGE_CREATE_TAKES_LONG_TIME_TITLE") + component.tags = _.reject(component.tags, (item)=> { + return item === component.name }); - } - } else { - // UPDATE MODE - this.$scope.isCreateProgress = true; - this.$scope.progressMessage = "Updating Asset..."; - this.disableMenuItems(); + this.$scope.updateBreadcrumbs(component); + + //update the component + this.$scope.setComponent(component); + this.$scope.originComponent = this.ComponentFactory.createComponent(this.$scope.component); - // Work around to change the csar version - if (this.cacheService.get(CHANGE_COMPONENT_CSAR_VERSION_FLAG)) { - (<Resource>this.$scope.component).csarVersion = this.cacheService.get(CHANGE_COMPONENT_CSAR_VERSION_FLAG); - this.cacheService.remove(CHANGE_COMPONENT_CSAR_VERSION_FLAG); - } + if (this.cacheService.contains(CHANGE_COMPONENT_CSAR_VERSION_FLAG)) { + this.cacheService.remove(CHANGE_COMPONENT_CSAR_VERSION_FLAG); + } + if (this.cacheService.contains(PREVIOUS_CSAR_COMPONENT)){ + this.cacheService.remove(PREVIOUS_CSAR_COMPONENT); + } + + //clear edit flags + this.$state.current.data.unsavedChanges = false; + this.$scope.unsavedFile = false; + resolve(); + }; this.$scope.component.updateComponent().then(onSuccessUpdate, onFailed); - } - return deferred.promise; - }; + }); - this.$scope.revert = ():void => { - //in state of import file leave the file in place - if (this.$scope.component.isResource() && (<Resource>this.$scope.component).importedFile) { - let tempFile:FileUploadModel = (<Resource>this.$scope.component).importedFile; - this.$scope.component = this.ComponentFactory.createComponent(this.$scope.originComponent); - (<Resource>this.$scope.component).importedFile = tempFile; - } else { - this.$scope.component = this.ComponentFactory.createComponent(this.$scope.originComponent); - } - this.EventListenerService.notifyObservers(EVENTS.ON_REVERT); }; this.$scope.changeLifecycleState = (state:string):void => { - if (this.isNeedSave() && state !== 'deleteVersion') { - this.$scope.save().then(() => { - changeLifecycleState(state); - }) + if (this.$scope.isGeneralView() && state !== 'deleteVersion') { + this.EventListenerService.notifyObservers(EVENTS.ON_LIFECYCLE_CHANGE_WITH_SAVE, state); } else { - changeLifecycleState(state); + this.$scope.handleChangeLifecycleState(state); } }; @@ -440,7 +489,7 @@ export class WorkspaceViewModel { this.$state.go('dashboard'); }; - let changeLifecycleState = (state:string) => { + this.$scope.handleChangeLifecycleState = (state:string, newCsarVersion?:string) => { if ('monitor' === state) { this.$state.go('workspace.distribution'); return; @@ -466,9 +515,9 @@ export class WorkspaceViewModel { // only checkOut get the full component from server // this.$scope.component = component; // Work around to change the csar version - if (this.cacheService.get(CHANGE_COMPONENT_CSAR_VERSION_FLAG)) { - (<Resource>this.$scope.component).csarVersion = this.cacheService.get(CHANGE_COMPONENT_CSAR_VERSION_FLAG); - } + if(newCsarVersion) { + this.cacheService.set(CHANGE_COMPONENT_CSAR_VERSION_FLAG, newCsarVersion); + } //when checking out a minor version uuid remains const bcIdx = _.findIndex(this.components, (item) => { @@ -480,20 +529,17 @@ export class WorkspaceViewModel { //when checking out a major(certified) version this.components.unshift(component); } - // this.$state.go(this.$state.current.name, { - // id: component.uniqueId, - // type: component.componentType.toLowerCase(), - // components: this.components - // }); this.$scope.mode = this.initViewMode(); this.initChangeLifecycleStateButtons(); this.initVersionObject(); this.$scope.isLoading = false; this.EventListenerService.notifyObservers(EVENTS.ON_CHECKOUT, component); + this.Notification.success({ message: this.$filter('translate')("CHECKOUT_SUCCESS_MESSAGE_TEXT"), title: this.$filter('translate')("CHECKOUT_SUCCESS_MESSAGE_TITLE") }); + }); break; case 'lifecycleState/CHECKIN': @@ -528,11 +574,9 @@ export class WorkspaceViewModel { }); break; case 'lifecycleState/certify': - defaultActionAfterChangeLifecycleState(); - this.Notification.success({ - message: this.$filter('translate')("ACCEPT_TESTING_SUCCESS_MESSAGE_TEXT"), - title: this.$filter('translate')("ACCEPT_TESTING_SUCCESS_MESSAGE_TITLE") - }); + + this.$scope.handleCertification(component); + break; //DE203504 Bug Fix Start case 'lifecycleState/startCertification': @@ -588,11 +632,7 @@ export class WorkspaceViewModel { this.ChangeLifecycleStateHandler.changeLifecycleState(this.$scope.component, data, this.$scope, onSuccess); }; - this.$scope.enabledTabs = ():void => { - this.$scope.leftBarTabs.menuItems.forEach((item:MenuItem) => { - item.isDisabled = false; - }); - }; + this.$scope.isViewMode = ():boolean => { return this.$scope.mode === WorkspaceMode.VIEW; @@ -606,7 +646,7 @@ export class WorkspaceViewModel { return this.$scope.mode === WorkspaceMode.VIEW && this.$scope.component.lifecycleState === ComponentState.NOT_CERTIFIED_CHECKIN; }; - this.$scope.showFullIcons = ():boolean => { + this.$scope.isGeneralView = ():boolean => { //we show revert and save icons only in general view return this.$state.current.name === States.WORKSPACE_GENERAL; }; @@ -697,15 +737,96 @@ export class WorkspaceViewModel { }; this.$scope.reload = (component:Component):void => { - this.$state.go(this.$state.current.name,{id:component.uniqueId},{reload:true}); + this.$state.go(this.$state.current.name, {id: component.uniqueId}, {reload: true}); }; - this.$scope.$on('setWorkspaceTopBarActive', (event:ng.IAngularEvent, isActive:boolean) => { - this.$scope.isActiveTopBar = isActive; + this.$scope.$on('$destroy', () => { + this.EventListenerService.unRegisterObserver(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES); }); + + this.$scope.openAutomatedUpgradeModal = ():void => { + this.$scope.isLoading = true; + this.ComponentServiceNg2.getDependencies(this.$scope.component.componentType, this.$scope.component.uniqueId).subscribe((response:Array<IDependenciesServerResponse>)=> { + this.$scope.isLoading = false; + this.AutomatedUpgradeService.openAutomatedUpgradeModal(response, this.$scope.component, false); + }); + } + + this.$scope.handleCertification = (certifyComponent): void => { + if (this.$scope.component.getComponentSubType() === ResourceType.VF) { + this.ComponentServiceNg2.getDependencies(this.$scope.component.componentType, this.$scope.component.uniqueId).subscribe((response:Array<IDependenciesServerResponse>) => { + this.$scope.isLoading = false; + + let isUpgradeNeeded = _.filter(response, (componentToUpgrade:IDependenciesServerResponse) => { + return componentToUpgrade.dependencies && componentToUpgrade.dependencies.length > 0; + }); + if(isUpgradeNeeded.length === 0) { + this.onSuccessWithoutUpgradeNeeded(); + return; + } + this.refreshDataAfterChangeLifecycleState(certifyComponent); + this.AutomatedUpgradeService.openAutomatedUpgradeModal(response, this.$scope.component, true); + }); + } else { + this.onSuccessWithoutUpgradeNeeded(); + } + } + + this.$scope.disableMenuItems = () => { + this.$scope.leftBarTabs.menuItems.forEach((item:MenuItem) => { + item.isDisabled = (States.WORKSPACE_GENERAL != item.state); + }); + } + + this.$scope.enableMenuItems = () => { + this.$scope.leftBarTabs.menuItems.forEach((item:MenuItem) => { + item.isDisabled = false; + }); + } + + + this.$scope.startProgress = (message:string):void => { + this.progressService.initCreateComponentProgress(this.$scope.component.uniqueId); + this.$scope.isCreateProgress = true; + this.$scope.progressMessage = message; + }; + + this.$scope.stopProgress = ():void => { + this.$scope.isCreateProgress = false; + this.progressService.deleteProgressValue(this.$scope.component.uniqueId); + } + + this.$scope.updateBreadcrumbs = (component:Component):void => { + // Update the components list for breadcrumbs + const bcIdx = this.MenuHandler.findBreadcrumbComponentIndex(this.components, component); + if (bcIdx !== -1) { + this.components[bcIdx] = component; + this.initBreadcrumbs(); // re-calculate breadcrumbs + } + } + + this.$scope.updateUnsavedFileFlag = (isUnsaved:boolean) => { + this.$scope.unsavedFile = isUnsaved; + } }; + private onSuccessWithoutUpgradeNeeded = ():void => { + this.$scope.isLoading = false; + this.Notification.success({ + message: this.$filter('translate')("ACCEPT_TESTING_SUCCESS_MESSAGE_TEXT"), + title: this.$filter('translate')("ACCEPT_TESTING_SUCCESS_MESSAGE_TITLE") + }); + this.$state.go('dashboard'); + } + private refreshDataAfterChangeLifecycleState = (component:Component):void => { + this.$scope.isLoading = false; + this.$scope.mode = this.initViewMode(); + this.initChangeLifecycleStateButtons(); + this.initVersionObject(); + this.EventListenerService.notifyObservers(EVENTS.ON_LIFECYCLE_CHANGE, component); + } + private initAfterScope = ():void => { // In case user select csar from the onboarding modal, need to disable checkout and submit for testing. if (this.$state.params['disableButtons'] === true) { @@ -743,6 +864,10 @@ export class WorkspaceViewModel { return tempMenuItems; }; + private deleteArchiveCache = () => { + this.cacheService.remove("archiveComponents"); //delete the cache to ensure the archive is reloaded from server + }; + private initBreadcrumbs = () => { this.components = this.cacheService.get('breadcrumbsComponents'); let breadcrumbsComponentsLvl = this.MenuHandler.generateBreadcrumbsModelFromComponents(this.components, this.$scope.component); @@ -787,32 +912,16 @@ export class WorkspaceViewModel { } menuItem.callback = () => this.$scope[menuItem.action](menuItem.state, menuItem.params); menuItem.isDisabled = (inCreateMode && States.WORKSPACE_GENERAL != menuItem.state) || - (States.WORKSPACE_DEPLOYMENT === menuItem.state && this.$scope.component.groups && this.$scope.component.groups.length === 0 && this.$scope.component.isResource()); + (States.WORKSPACE_DEPLOYMENT === menuItem.state && this.$scope.component.modules && this.$scope.component.modules.length === 0 && this.$scope.component.isResource()); return menuItem; }); if (this.cacheService.get('breadcrumbsComponents')) { this.initBreadcrumbs(); - } else { - let onSuccess = (components:Array<Component>) => { - this.cacheService.set('breadcrumbsComponents', components); - this.initBreadcrumbs(); - }; - this.EntityService.getCatalog().then(onSuccess); //getAllComponents() doesnt return components from catalog } } - private disableMenuItems() { - this.$scope.leftBarTabs.menuItems.forEach((item:MenuItem) => { - item.isDisabled = (States.WORKSPACE_GENERAL != item.state); - }); - } - private enableMenuItems() { - this.$scope.leftBarTabs.menuItems.forEach((item:MenuItem) => { - item.isDisabled = false; - }); - } private showSuccessNotificationMessage = ():void => { this.Notification.success({ @@ -821,4 +930,9 @@ export class WorkspaceViewModel { }); }; + private setWorkspaceButtonState = (newState:boolean, callback?:Function) => { + this.$scope.unsavedChanges = newState; + this.$scope.unsavedChangesCallback = callback; + } + } diff --git a/catalog-ui/src/app/view-models/workspace/workspace-view.html b/catalog-ui/src/app/view-models/workspace/workspace-view.html index 1452754024..f6fed6a41d 100644 --- a/catalog-ui/src/app/view-models/workspace/workspace-view.html +++ b/catalog-ui/src/app/view-models/workspace/workspace-view.html @@ -17,9 +17,9 @@ <div class="version-container"> <span data-ng-if="!isCreateMode() && !component.isLatestVersion()" class="not-latest"></span> - <select class="version-selector" data-ng-if="!isCreateMode()" data-tests-id="versionHeader" data-ng-model="changeVersion.selectedVersion" data-ng-class="{'disabled': !isActiveTopBar}" - ng-options="'V'+version.versionNumber for version in versionsList" data-ng-change="onVersionChanged(changeVersion.selectedVersion.versionId)"> - </select> + <select class="version-selector" data-ng-if="!isCreateMode()" data-tests-id="versionHeader" data-ng-model="changeVersion.selectedVersion" data-ng-class="{'disabled': unsavedChanges}" + ng-options="'V'+version.versionNumber for version in versionsList" data-ng-change="onVersionChanged(changeVersion.selectedVersion.versionId)"> + </select> </div> <div class="lifecycle-state"> @@ -27,6 +27,9 @@ <span class="lifecycle-state-text" data-tests-id="formlifecyclestate">{{getStatus()}}</span> </div> + <div class="archive-state-label" ng-if="component.archived"> + <div class="sprite-new archive-label" ></div> + </div> <div class="progress-container" > <top-progress class="general-view-top-progress" progress-value="progressService.getProgressValue(component.uniqueId)" progress-message="progressMessage"></top-progress> @@ -34,47 +37,64 @@ <div class="sdc-workspace-top-bar-buttons"> - <span ng-if="!isCreateMode() && !component.isLatestVersion() && !showChangeStateButton()" [disabled]="!isActiveTopBar">Switch to the <a ng-click="getLatestVersion()">latest version</a></span> + <span ng-if="!isCreateMode() && !component.isLatestVersion() && !showChangeStateButton()" [disabled]="unsavedChanges">Switch to the <a ng-click="getLatestVersion()">latest version</a></span> - <button ng-if="isDesigner() && !isCreateMode()" - data-ng-class="{'disabled' :!isValidForm || isDisableMode() || isViewMode() || !isActiveTopBar}" - ng-click="save()" + <button ng-if="isDesigner() && !isCreateMode() && component.lifecycleState === 'CERTIFIED' && (component.isService() || component.getComponentSubType() === 'VF')" + ng-click="openAutomatedUpgradeModal()" class="tlv-btn blue" - data-tests-id="create/save" - data-ng-show="showFullIcons()" - sdc-smart-tooltip="">Update</button> + data-ng-class="{'disabled' : component.archived}" + data-tests-id="open-upgrade-vsp-popup" + sdc-smart-tooltip="" prevent-double-click>{{component.isResource() ? 'Upgrade Services' : 'Update Services'}}</button> + <button ng-repeat="(key,button) in changeLifecycleStateButtons" ng-click="changeLifecycleState(key)" ng-if="showChangeStateButton() && key != 'deleteVersion'" - data-ng-disabled="isCreateMode() || button.disabled || disabledButtons || !isValidForm || !isActiveTopBar" + data-ng-disabled="isCreateMode() || button.disabled || disabledButtons || !isValidForm || unsavedChanges || component.archived" class="change-lifecycle-state-btn tlv-btn" ng-class="$first ? 'outline green' : 'grey'" - data-tests-id="{{button.text | testsId}}"> + data-tests-id="{{button.text | testsId}}" prevent-double-click> {{button.text}} + </button> - <button ng-if="!isViewMode() && isCreateMode()" data-ng-disabled="!isValidForm || isDisableMode() || isLoading || !isActiveTopBar" ng-click="save()" class="tlv-btn outline green" data-tests-id="create/save">Create</button> - <span data-ng-if="isDesigner() && !isCreateMode() && component.lifecycleState === 'NOT_CERTIFIED_CHECKOUT'" sdc-smart-tooltip="" - data-ng-class="{'disabled' : !isValidForm || isDisableMode() || isViewMode() || !isActiveTopBar}" ng-click="changeLifecycleState('deleteVersion')" - class="sprite-new delete-btn" data-tests-id="delete_version" sdc-smart-tooltip="">Delete</span> + <button ng-if="!isCreateMode() && component.archived" + data-ng-class="{'disabled' :!isDesigner() || !component.isLatestVersion()}" + ng-click="restoreComponent()" + class="tlv-btn blue" + data-tests-id="restore-component-button" + prevent-double-click>Restore</button> + + <button ng-if="!isViewMode() && isCreateMode()" data-ng-disabled="!isValidForm || isDisableMode() || isLoading || unsavedChanges" ng-click="create()" class="tlv-btn outline green" data-tests-id="create/save">Create</button> + + <span data-ng-if="isDesigner() && !isCreateMode() && component.lifecycleState === 'NOT_CERTIFIED_CHECKOUT' && !component.archived" sdc-smart-tooltip="" + data-ng-class="{'disabled' : !isValidForm || isDisableMode() || isViewMode() || unsavedChanges}" ng-click="changeLifecycleState('deleteVersion')" + class="sprite-new delete-btn" data-tests-id="delete_version" sdc-smart-tooltip="Delete" prevent-double-click>Delete</span> + + <span data-ng-click = "archiveComponent()" + ng-model-options="{ debounce: 300 }" + data-ng-class="{'disabled' : !component.isLatestVersion()}" + data-ng-if = "isDesigner() && component.lifecycleState !== 'NOT_CERTIFIED_CHECKOUT' && !isCreateMode() && !component.archived" + data-tests-id="archive-component-button" + class="sprite-new archive-btn" sdc-smart-tooltip="Archive" prevent-double-click>Archive</span> + - <span data-ng-if="isDesigner()" data-ng-class="{'disabled' :isDisableMode() || isViewMode() || !isActiveTopBar}" ng-click="revert()" class="sprite-new revert-btn" data-tests-id="revert" - data-ng-show="showFullIcons()" sdc-smart-tooltip="">Revert</span> <span class="delimiter"></span> - <span class="sprite-new x-btn" data-ng-click="goToBreadcrumbHome()" sdc-smart-tooltip="">Close</span> + <span class="sprite-new x-btn" data-ng-click="goToBreadcrumbHome()" data-ng-class="{'disabled' : unsavedChanges}" sdc-smart-tooltip="">Close</span> </div> </div> <div class="w-sdc-main-container-body-content-wrapper"> - <div class="tab-title" data-ng-if="!isComposition && !isDeployment && !isPlugins"> - {{getTabTitle()}} + <div class="w-sdc-main-container-body-content-header"> + <div class="tab-title" data-ng-if="!isComposition && !isDeployment && !isPlugins"> + {{getTabTitle()}} + </div> </div> <div class="w-sdc-main-container-body-content" data-ng-class="{'third-party':thirdParty}" data-ui-view></div> </div> </div> </div> - <top-nav [hide-search]="true" [menu-model]="breadcrumbsModel" [version]="version"></top-nav> + <top-nav [hide-search]="true" [menu-model]="breadcrumbsModel" [version]="version" [unsaved-changes]="unsavedChanges" [unsaved-changes-callback]="unsavedChangesCallback"></top-nav> </div> diff --git a/catalog-ui/src/app/view-models/workspace/workspace.less b/catalog-ui/src/app/view-models/workspace/workspace.less index 0cc30ece20..b9956c655b 100644 --- a/catalog-ui/src/app/view-models/workspace/workspace.less +++ b/catalog-ui/src/app/view-models/workspace/workspace.less @@ -128,7 +128,7 @@ .delimiter { height: 32px; width: 1px; - background-color: #959595; + background-color: @main_color_o; display: inline-block; vertical-align: middle; margin-right: 20px; @@ -136,6 +136,16 @@ } + .archive-state-label { + padding: 7px 0 0 10px; + margin: 2px 0 7px 10px; + border-left: 1px solid @main_color_o; + line-height: 15px; + font-family: @font-opensans-bold; + color: @main_color_m; + font-size:12px; + } + .lifecycle-state { padding: 7px 0 0 10px; margin: 2px 0 7px 10px; @@ -191,7 +201,26 @@ } .w-sdc-main-container-body-content-wrapper { overflow: auto; - height: calc(~'100% - @{action_nav_height}') + height: calc(~'100% - @{action_nav_height}'); + .w-sdc-main-container-body-content-header { + display: flex; + .tab-title { + flex-grow: 1; + } + .w-sdc-main-container-body-content-action-buttons { + margin:72px 100px 0 0; + > * { + display: inline-block; + vertical-align: middle; + } + .revert-btn { + text-indent: 100%; + } + .save-btn { + text-indent: 100%; + } + } + } } } } |