diff options
Diffstat (limited to 'catalog-ui/src')
303 files changed, 8443 insertions, 2836 deletions
diff --git a/catalog-ui/src/app/app.ts b/catalog-ui/src/app/app.ts index 723f244dc6..67cf66529c 100644 --- a/catalog-ui/src/app/app.ts +++ b/catalog-ui/src/app/app.ts @@ -30,6 +30,7 @@ import './modules/utils.ts'; import './modules/directive-module.ts'; import './modules/service-module'; import './modules/view-model-module.ts'; +import {SdcUiComponentsNg1Module} from 'sdc-ui/lib/angular'; import { DataTypesService, @@ -45,14 +46,13 @@ import { import { UserService } from "./ng2/services/user.service"; import {forwardRef} from '@angular/core'; import {UpgradeAdapter} from '@angular/upgrade'; -import {CHANGE_COMPONENT_CSAR_VERSION_FLAG, States} from "./utils"; +import {CHANGE_COMPONENT_CSAR_VERSION_FLAG, States, PREVIOUS_CSAR_COMPONENT} from "./utils"; import {IAppConfigurtaion, IAppMenu, IMainCategory, Resource, IHostedApplication} from "./models"; import {ComponentFactory} from "./utils/component-factory"; import {ModalsHandler} from "./utils/modals-handler"; import {downgradeComponent} from "@angular/upgrade/static"; import {AppModule} from './ng2/app.module'; -import {PropertiesAssignmentComponent} from "./ng2/pages/properties-assignment/properties-assignment.page.component"; import {Component} from "./models/components/component"; import {ComponentServiceNg2} from "./ng2/services/component-services/component.service"; import {ComponentMetadata} from "./models/component-metadata"; @@ -100,6 +100,7 @@ let dependentModules:Array<string> = [ 'angular-clipboard', 'angularResizable', 'infinite-scroll', + SdcUiComponentsNg1Module.name, viewModelsModuleName, directivesModuleName, servicesModuleName, @@ -185,7 +186,7 @@ ng1appModule.config([ $stateProvider.state( 'dashboard', { - url: '/dashboard?show&folder', + url: '/dashboard?show&folder&filter.term&filter.status&filter.distributed', templateUrl: "./view-models/dashboard/dashboard-view.html", controller: viewModelsModuleName + '.DashboardViewModel', } @@ -200,25 +201,60 @@ ng1appModule.config([ ); let componentsParam:Array<any> = ['$stateParams', 'Sdc.Services.EntityService', 'Sdc.Services.CacheService', ($stateParams:any, EntityService:EntityService, cacheService:CacheService) => { - if (cacheService.get('breadcrumbsComponents')) { - return cacheService.get('breadcrumbsComponents'); + if (cacheService.get('breadcrumbsComponentsState') === $stateParams.previousState) { + const breadcrumbsComponents = cacheService.get('breadcrumbsComponents'); + if (breadcrumbsComponents) { + return breadcrumbsComponents; + } } else { - return EntityService.getCatalog(); + let breadcrumbsComponentsPromise; + if ($stateParams.previousState === 'dashboard') { + breadcrumbsComponentsPromise = EntityService.getAllComponents(true); + } else if ($stateParams.previousState === 'catalog') { + breadcrumbsComponentsPromise = EntityService.getCatalog(); + } else { + cacheService.remove('breadcrumbsComponentsState'); + cacheService.remove('breadcrumbsComponents'); + return []; + } + breadcrumbsComponentsPromise.then((components) => { + cacheService.set('breadcrumbsComponentsState', $stateParams.previousState); + cacheService.set('breadcrumbsComponents', components); + }); + return breadcrumbsComponentsPromise; } }]; + const oldWorkspaceController:Array<any> = ['$location', ($location:ng.ILocationService) => { + // redirect old /workspace/* urls to /catalog/workspace/* url + const newUrl = '/catalog' + $location.url(); + console.log('old workspace path - redirecting to:', newUrl); + $location.url(newUrl); + }]; + + $stateProvider.state( + 'workspace-old', { + url: '/workspace/:id/:type/*workspaceInnerPath', + controller: oldWorkspaceController + } + ); + $stateProvider.state( 'workspace', { - url: '/workspace/:id/:type/', + url: '/:previousState/workspace/:id/:type/', params: {'importedFile': null, 'componentCsar': null, 'resourceType': null, 'disableButtons': null}, templateUrl: './view-models/workspace/workspace-view.html', controller: viewModelsModuleName + '.WorkspaceViewModel', resolve: { - injectComponent: ['$stateParams', 'ComponentFactory', 'ComponentServiceNg2', function ($stateParams, ComponentFactory:ComponentFactory, ComponentServiceNg2:ComponentServiceNg2) { - if ($stateParams.id) { + injectComponent: ['$stateParams', 'ComponentFactory', 'Sdc.Services.CacheService', 'ComponentServiceNg2', function ($stateParams, ComponentFactory:ComponentFactory, cacheService:CacheService, ComponentServiceNg2:ComponentServiceNg2) { + + if ($stateParams.id && $stateParams.id.length) { //need to check length in case ID is an empty string return ComponentFactory.getComponentWithMetadataFromServer($stateParams.type.toUpperCase(), $stateParams.id).then( (component:Component)=> { - if ($stateParams.componentCsar){ + if ($stateParams.componentCsar && component.isResource()){ + if((<Resource>component).csarVersion != $stateParams.componentCsar.csarVersion) { + cacheService.set(PREVIOUS_CSAR_COMPONENT, angular.copy(component)); + } component = ComponentFactory.updateComponentFromCsar($stateParams.componentCsar, <Resource>component); } return component; @@ -258,7 +294,6 @@ ng1appModule.config([ parent: 'workspace', controller: viewModelsModuleName + '.ActivityLogViewModel', templateUrl: './view-models/workspace/tabs/activity-log/activity-log.html', - data: {unsavedChanges: false} } ); @@ -569,7 +604,7 @@ ng1appModule.config([ $stateProvider.state( 'catalog', { - url: '/catalog', + url: '/catalog?filter.components&filter.resourceSubTypes&filter.categories&filter.statuses&filter.order&filter.term&filter.active', templateUrl: './view-models/catalog/catalog-view.html', controller: viewModelsModuleName + '.CatalogViewModel', resolve: { @@ -619,6 +654,7 @@ ng1appModule.value('TagValidationPattern', /^[\s\w_.-]{1,50}$/); ng1appModule.value('VendorReleaseValidationPattern', /^[\x20-\x21\x23-\x29\x2B-\x2E\x30-\x39\x3B\x3D\x40-\x5B\x5D-\x7B\x7D-\xFF]{1,25}$/); ng1appModule.value('VendorNameValidationPattern', /^[\x20-\x21\x23-\x29\x2B-\x2E\x30-\x39\x3B\x3D\x40-\x5B\x5D-\x7B\x7D-\xFF]{1,60}$/); ng1appModule.value('VendorModelNumberValidationPattern', /^[\x20-\x21\x23-\x29\x2B-\x2E\x30-\x39\x3B\x3D\x40-\x5B\x5D-\x7B\x7D-\xFF]{1,65}$/); +ng1appModule.value('ServiceTypeAndRoleValidationPattern', /^[\x20-\x21\x23-\x29\x2B-\x2E\x30-\x39\x3B\x3D\x40-\x5B\x5D-\x7B\x7D-\xFF]{1,256}$/); ng1appModule.value('ContactIdValidationPattern', /^[\s\w-]{1,50}$/); ng1appModule.value('UserIdValidationPattern', /^[\s\w-]{1,50}$/); ng1appModule.value('ProjectCodeValidationPattern', /^[\s\w-]{5,50}$/); @@ -672,6 +708,7 @@ ng1appModule.run([ AngularJSBridge, $templateCache:ng.ITemplateCacheService):void => { $templateCache.put('notification-custom-template.html', require('./view-models/shared/notification-custom-template.html')); + $templateCache.put('notification-custom-template.html', require('./view-models/shared/notification-custom-template.html')); //handle cache data - version let initAsdcVersion:Function = ():void => { @@ -846,6 +883,9 @@ ng1appModule.run([ if (cacheService.contains(CHANGE_COMPONENT_CSAR_VERSION_FLAG)) { cacheService.remove(CHANGE_COMPONENT_CSAR_VERSION_FLAG); } + if (cacheService.contains(PREVIOUS_CSAR_COMPONENT)){ + cacheService.remove(PREVIOUS_CSAR_COMPONENT); + } } //set body class diff --git a/catalog-ui/src/app/directives/elements/checkbox/checkbox.html b/catalog-ui/src/app/directives/elements/checkbox/checkbox.html index 1e25408188..e52f810360 100644 --- a/catalog-ui/src/app/directives/elements/checkbox/checkbox.html +++ b/catalog-ui/src/app/directives/elements/checkbox/checkbox.html @@ -5,6 +5,7 @@ type="checkbox" checked="" ng-disabled="disabled" + ng-change="sdcCheckedChange({checked})" checklist-model="sdcChecklistModel" checklist-value="sdcChecklistValue" checklist-change="sdcChecklistChange()" diff --git a/catalog-ui/src/app/directives/elements/checkbox/checkbox.ts b/catalog-ui/src/app/directives/elements/checkbox/checkbox.ts index 43a05e77d4..9b752eaf98 100644 --- a/catalog-ui/src/app/directives/elements/checkbox/checkbox.ts +++ b/catalog-ui/src/app/directives/elements/checkbox/checkbox.ts @@ -25,6 +25,8 @@ export interface ICheckboxElementScope extends ng.IScope { text:string; sdcChecklistModel:any; sdcChecklistValue:string; + sdcChecklistChange:Function; + sdcCheckedChange:Function; disabled:boolean; } @@ -41,9 +43,10 @@ export class CheckboxElementDirective implements ng.IDirective { elemId: '@', text: '@', disabled: '=', - sdcChecklistModel: '=', - sdcChecklistValue: '=', - sdcChecklistChange: '&' + sdcChecklistModel: '=?', + sdcChecklistValue: '=?', + sdcChecklistChange: '&?', + sdcCheckedChange: '&?' }; template = ():string => { diff --git a/catalog-ui/src/app/directives/file-upload/file-upload.ts b/catalog-ui/src/app/directives/file-upload/file-upload.ts index 4902741927..7d6667cbcc 100644 --- a/catalog-ui/src/app/directives/file-upload/file-upload.ts +++ b/catalog-ui/src/app/directives/file-upload/file-upload.ts @@ -94,13 +94,13 @@ export class FileUploadDirective implements ng.IDirective { }; scope.onFileChange = ():void => { + if (scope.myFileModel || scope.fileModel) { + scope.fileModel = scope.myFileModel; + scope.formElement[scope.elementName].value = scope.myFileModel; + } if (scope.onFileChangedInDirective) { scope.onFileChangedInDirective(); } - if (scope.myFileModel) { - scope.fileModel = scope.myFileModel; - scope.formElement[scope.elementName].$setValidity('required', true); - } }; scope.setEmptyError = (element):void => { @@ -136,9 +136,10 @@ export class FileUploadDirective implements ng.IDirective { }; scope.cancel = ():void => { - scope.fileModel.filename = ''; + scope.myFileModel = new FileUploadModel(); scope.formElement[scope.elementName].$pristine; scope.formElement[scope.elementName].$setValidity('required', false); + scope.onFileChange(); } }; diff --git a/catalog-ui/src/app/directives/graphs-v2/common/style/component-instances-nodes-style.ts b/catalog-ui/src/app/directives/graphs-v2/common/style/component-instances-nodes-style.ts index 596dcecc13..194845c238 100644 --- a/catalog-ui/src/app/directives/graphs-v2/common/style/component-instances-nodes-style.ts +++ b/catalog-ui/src/app/directives/graphs-v2/common/style/component-instances-nodes-style.ts @@ -22,6 +22,7 @@ import { GraphColors, GraphUIObjects} from "app/utils/constants"; import constant = require("lodash/constant"); import {ImagesUrl} from "app/utils/constants"; import {AngularJSBridge} from "app/services/angular-js-bridge-service"; +import { CanvasHandleTypes } from "app/utils"; /** * Created by obarda on 12/18/2016. */ @@ -102,8 +103,10 @@ export class ComponentInstanceNodesStyle { 'background-image': 'data(img)', 'background-width': GraphUIObjects.SMALL_RESOURCE_WIDTH, 'background-height': GraphUIObjects.SMALL_RESOURCE_WIDTH, - 'width': GraphUIObjects.SMALL_RESOURCE_WIDTH, - 'height': GraphUIObjects.SMALL_RESOURCE_WIDTH, + 'width': GraphUIObjects.SMALL_RESOURCE_WIDTH + GraphUIObjects.HANDLE_SIZE, + 'height': GraphUIObjects.SMALL_RESOURCE_WIDTH + GraphUIObjects.HANDLE_SIZE/2, + 'background-position-x': GraphUIObjects.HANDLE_SIZE / 2, + 'background-position-y': GraphUIObjects.HANDLE_SIZE / 2, 'text-valign': 'bottom', 'text-halign': 'center', 'background-opacity': 0, @@ -120,8 +123,10 @@ export class ComponentInstanceNodesStyle { 'background-image': 'data(img)', 'background-width': GraphUIObjects.SMALL_RESOURCE_WIDTH, 'background-height': GraphUIObjects.SMALL_RESOURCE_WIDTH, - 'width': GraphUIObjects.SMALL_RESOURCE_WIDTH, - 'height': GraphUIObjects.SMALL_RESOURCE_WIDTH, + 'background-position-x': GraphUIObjects.HANDLE_SIZE / 2, + 'background-position-y': GraphUIObjects.HANDLE_SIZE / 2, + 'width': GraphUIObjects.SMALL_RESOURCE_WIDTH + GraphUIObjects.HANDLE_SIZE, + 'height': GraphUIObjects.SMALL_RESOURCE_WIDTH + GraphUIObjects.HANDLE_SIZE / 2, 'text-valign': 'bottom', 'text-halign': 'center', 'background-opacity': 0, @@ -167,6 +172,16 @@ export class ComponentInstanceNodesStyle { } }, { + selector: '.archived', + css: { + 'shape': 'rectangle', + 'background-image': (ele:Cy.Collection) => { + return ele.data().setArchivedImageBgStyle(ele, GraphUIObjects.NODE_OVERLAP_MIN_SIZE); //Change name to setArchivedImageBgStyle ?? + }, + "border-width": 0 + } + }, + { selector: '.vl-link', css: { 'width': 3, @@ -222,7 +237,7 @@ export class ComponentInstanceNodesStyle { css: { 'shape': 'rectangle', 'background-image': (ele:Cy.Collection) => { - return ele.data().initUncertifiedImage(ele, GraphUIObjects.NODE_OVERLAP_MIN_SIZE) + return ele.data().setUncertifiedImageBgStyle(ele, GraphUIObjects.NODE_OVERLAP_MIN_SIZE);//Change name to setUncertifiedImageBgStyle?? }, "border-width": 0 } @@ -256,8 +271,10 @@ export class ComponentInstanceNodesStyle { 'background-image': 'data(img)', 'background-width': GraphUIObjects.SMALL_RESOURCE_WIDTH, 'background-height': GraphUIObjects.SMALL_RESOURCE_WIDTH, - 'width': GraphUIObjects.SMALL_RESOURCE_WIDTH, - 'height': GraphUIObjects.SMALL_RESOURCE_WIDTH, + 'background-position-x': GraphUIObjects.HANDLE_SIZE / 2, + 'background-position-y': GraphUIObjects.HANDLE_SIZE / 2, + 'width': GraphUIObjects.SMALL_RESOURCE_WIDTH + GraphUIObjects.HANDLE_SIZE, + 'height': GraphUIObjects.SMALL_RESOURCE_WIDTH + GraphUIObjects.HANDLE_SIZE/2, 'text-valign': 'bottom', 'text-halign': 'center', 'background-opacity': 0, @@ -268,52 +285,57 @@ export class ComponentInstanceNodesStyle { ] } - public static getBasicNodeHanlde = () => { + public static getAddEdgeHandle = () => { return { - positionX: "right", - positionY: "top", - offsetX: 15, - offsetY: -20, - color: "#27a337", - type: "default", + single: false, - nodeTypeNames: ["basic-node"], + type: CanvasHandleTypes.ADD_EDGE, imageUrl: AngularJSBridge.getAngularConfig().imagesPath + ImagesUrl.CANVAS_PLUS_ICON, + lineColor: '#27a337', lineWidth: 2, lineStyle: 'dashed' } } - public static getBasicSmallNodeHandle = () => { + public static getTagHandle = () => { return { - positionX: "right", - positionY: "top", - offsetX: 3, - offsetY: -25, - color: "#27a337", - type: "default", single: false, - nodeTypeNames: ["basic-small-node"], - imageUrl: AngularJSBridge.getAngularConfig().imagesPath + ImagesUrl.CANVAS_PLUS_ICON, - lineWidth: 2, - lineStyle: 'dashed' - } + type: CanvasHandleTypes.TAG_AVAILABLE, + imageUrl: AngularJSBridge.getAngularConfig().imagesPath + ImagesUrl.CANVAS_TAG_ICON, + } } - public static getUcpeCpNodeHandle = () => { + public static getTaggedPolicyHandle = () => { return { - positionX: "center", - positionY: "center", - offsetX: -8, - offsetY: -10, - color: "#27a337", - type: "default", single: false, - nodeTypeNames: ["ucpe-cp-node"], - imageUrl: AngularJSBridge.getAngularConfig().imagesPath + ImagesUrl.CANVAS_PLUS_ICON, - lineWidth: 2, - lineStyle: 'dashed' - } + type: CanvasHandleTypes.TAGGED_POLICY, + imageUrl: AngularJSBridge.getAngularConfig().imagesPath + ImagesUrl.CANVAS_POLICY_TAGGED_ICON, + } } + + public static getTaggedGroupHandle = () => { + return { + single: false, + type: CanvasHandleTypes.TAGGED_GROUP, + imageUrl: AngularJSBridge.getAngularConfig().imagesPath + ImagesUrl.CANVAS_GROUP_TAGGED_ICON, + } + } + + + // public static getUcpeCpNodeHandle = () => { + // return { + // positionX: "center", + // positionY: "center", + // offsetX: -8, + // offsetY: -10, + // color: "#27a337", + // type: "default", + // single: false, + // nodeTypeNames: ["ucpe-cp-node"], + // imageUrl: AngularJSBridge.getAngularConfig().imagesPath + ImagesUrl.CANVAS_PLUS_ICON, + // lineWidth: 2, + // lineStyle: 'dashed' + // } + // } } diff --git a/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.directive.ts b/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.directive.ts index 2144ecfbfa..e40792dc7e 100644 --- a/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.directive.ts +++ b/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.directive.ts @@ -24,10 +24,7 @@ import { LinkMenu, ComponentInstance, LeftPaletteComponent, - Capability, - Requirement, Relationship, - PropertyModel, Component, Service, ConnectRelationModel, @@ -35,8 +32,7 @@ import { CompositionCiNodeVl, ModalModel, ButtonModel, - NodesFactory/*, - AssetPopoverObj*/, + NodesFactory, Point } from "app/models"; import {ComponentInstanceFactory, ComponentFactory, GRAPH_EVENTS, GraphColors} from "app/utils"; @@ -52,7 +48,6 @@ import {CytoscapeEdgeEditation} from 'third-party/cytoscape.js-edge-editation/Cy import {ComponentServiceNg2} from "../../../ng2/services/component-services/component.service"; import {ComponentGenericResponse} from "../../../ng2/services/responses/component-generic-response"; import {ModalService} from "../../../ng2/services/modal.service"; - import {ConnectionWizardService} from "../../../ng2/pages/connection-wizard/connection-wizard.service"; import {StepModel} from "../../../models/wizard-step"; import {FromNodeStepComponent} from "app/ng2/pages/connection-wizard/from-node-step/from-node-step.component"; @@ -63,31 +58,40 @@ import {ConnectionPropertiesViewComponent} from "../../../ng2/pages/connection-w import {ComponentInstanceServiceNg2} from "../../../ng2/services/component-instance-services/component-instance.service"; import {EVENTS} from "../../../utils/constants"; import {PropertyBEModel} from "../../../models/properties-inputs/property-be-model"; -import {ComponentType} from "app/utils"; import {ForwardingPath} from "app/models/forwarding-path"; import {ServicePathGraphUtils} from "./utils/composition-graph-service-path-utils"; import {CompositionCiServicePathLink} from "app/models/graph/graph-links/composition-graph-links/composition-ci-service-path-link"; -import { ZoneConfig, ZoneInstanceConfig, ZoneInstanceMode } from "app/models/graph/zones/zone-child"; -import { PoliciesService } from "app/ng2/services/policies.service"; -import { PaletteAnimationComponent } from "app/ng2/components/ui/palette-animation/palette-animation.component"; -import { CompositionGraphZoneUtils } from "./utils/composition-graph-zone-utils"; -import {LeftPaletteMetadataTypes} from "../../../models/components/displayComponent"; +import { + ZoneInstance, ZoneInstanceMode, ZoneInstanceType, + ZoneInstanceAssignmentType +} from "app/models/graph/zones/zone-instance"; + +import {Zone} from "app/models/graph/zones/zone"; +import {CompositionGraphZoneUtils} from "./utils/composition-graph-zone-utils"; +import {UIZoneInstanceObject} from "../../../models/ui-models/ui-zone-instance-object"; +import {GroupInstance} from "../../../models/graph/zones/group-instance"; +import {PolicyInstance} from "../../../models/graph/zones/policy-instance"; export interface ICompositionGraphScope extends ng.IScope { component:Component; - isLoading: boolean; - isViewOnly: boolean; - withSidebar: boolean; + isLoading:boolean; + isViewOnly:boolean; + withSidebar:boolean; //zones newZoneInstance; zoneTagMode:string; - activeZoneInstance:ZoneInstanceConfig; - zones:any; - zoneInstanceModeChanged(newMode:ZoneInstanceMode, instance:ZoneInstanceConfig, zoneId:string); + activeZoneInstance:ZoneInstance; + zones:Array<Zone>; + zoneMinimizeToggle(zoneType:ZoneInstanceType):void; + zoneInstanceTagged(taggedInstance:ZoneInstance):void; + zoneInstanceModeChanged(newMode:ZoneInstanceMode, instance:ZoneInstance, zoneId:ZoneInstanceType); + unsetActiveZoneInstance():void; clickOutsideZoneInstance():void; + zoneAssignmentSaveStart():void; + zoneAssignmentSaveComplete(success:boolean):void; // Link menu - create link menu relationMenuDirectiveObj:ConnectRelationModel; @@ -98,7 +102,7 @@ export interface ICompositionGraphScope extends ng.IScope { //modify link menu - for now only delete menu relationMenuTimeout:ng.IPromise<any>; linkMenuObject:LinkMenu; - isOnDrag: boolean; + isOnDrag:boolean; //left palette functions callbacks dropCallback(event:JQueryEventObject, ui:any):void; @@ -111,24 +115,24 @@ export interface ICompositionGraphScope extends ng.IScope { hideRelationMenu(); //search,zoom in/out/all - componentInstanceNames: Array<string>; //id, name - zoom(zoomIn: boolean): void; - zoomAll(nodes?:Cy.CollectionNodes): void; - getAutoCompleteValues(searchTerm: string):void; - highlightSearchMatches(searchTerm: string): void; + componentInstanceNames:Array<string>; //id, name + zoom(zoomIn:boolean):void; + zoomAllWithoutSidebar():void; + getAutoCompleteValues(searchTerm:string):void; + highlightSearchMatches(searchTerm:string):void; canvasMenuProps:any; - createOrUpdateServicePath(data: any):void; + createOrUpdateServicePath(data:any):void; deletePathsOnCy():void; - drawPathOnCy(data: ForwardingPath):void; - selectedPathId: string; + drawPathOnCy(data:ForwardingPath):void; + selectedPathId:string; /*//asset popover menu - assetPopoverObj:AssetPopoverObj; - assetPopoverOpen:boolean; - hideAssetPopover():void; - deleteNode(nodeId:string):void;*/ + assetPopoverObj:AssetPopoverObj; + assetPopoverOpen:boolean; + hideAssetPopover():void; + deleteNode(nodeId:string):void;*/ } export class CompositionGraph implements ng.IDirective { @@ -153,12 +157,11 @@ export class CompositionGraph implements ng.IDirective { private matchCapabilitiesRequirementsUtils:MatchCapabilitiesRequirementsUtils, private CompositionGraphPaletteUtils:CompositionGraphPaletteUtils, private compositionGraphZoneUtils:CompositionGraphZoneUtils, - private ComponentServiceNg2: ComponentServiceNg2, - private ModalServiceNg2: ModalService, - private ConnectionWizardServiceNg2: ConnectionWizardService, - private ComponentInstanceServiceNg2: ComponentInstanceServiceNg2, - private servicePathGraphUtils: ServicePathGraphUtils, - private policiesService:PoliciesService) { + private ComponentServiceNg2:ComponentServiceNg2, + private ModalServiceNg2:ModalService, + private ConnectionWizardServiceNg2:ConnectionWizardService, + private ComponentInstanceServiceNg2:ComponentInstanceServiceNg2, + private servicePathGraphUtils:ServicePathGraphUtils) { } @@ -173,14 +176,15 @@ export class CompositionGraph implements ng.IDirective { link = (scope:ICompositionGraphScope, el:JQuery) => { this.loadGraph(scope, el); - if(scope.component.componentInstances && scope.component.componentInstancesRelations) { - this.loadGraphData(scope); - } else { - //when we don't have the data we register to on graph load event + if (!scope.component.groupInstances || !scope.component.policies) { this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_COMPOSITION_GRAPH_DATA_LOADED, () => { this.loadGraphData(scope); }); + } else { + this.loadGraphData(scope); } + + scope.$on('$destroy', () => { this._cy.destroy(); _.forEach(GRAPH_EVENTS, (event) => { @@ -196,7 +200,10 @@ export class CompositionGraph implements ng.IDirective { this.initGraphNodes(scope.component.componentInstances, scope.isViewOnly); this.commonGraphUtils.initGraphLinks(this._cy, scope.component.componentInstancesRelations, scope.component.getRelationRequirementCapability.bind(scope.component)); this.commonGraphUtils.initUcpeChildren(this._cy); - this.compositionGraphZoneUtils.initPolicyInstances(scope.zones.policy, scope.component.policies); + this.compositionGraphZoneUtils.initZoneInstances(scope.zones, scope.component); + setTimeout(() => {//Need settimeout so that angular canvas changes will take effect before resize & center + this.GeneralGraphUtils.zoomAllWithMax(this._cy, 1); + }); } private loadGraph = (scope:ICompositionGraphScope, el:JQuery) => { @@ -207,7 +214,6 @@ export class CompositionGraph implements ng.IDirective { this.registerCytoscapeGraphEvents(scope); this.registerCustomEvents(scope, el); this.initViewMode(scope.isViewOnly); - }; private initGraph(graphEl:JQuery, isViewOnly:boolean) { @@ -234,16 +240,26 @@ export class CompositionGraph implements ng.IDirective { this._cy.off('drag'); this._cy.off('handlemouseout'); this._cy.off('handlemouseover'); + this._cy.off('canvasredraw'); + this._cy.off('handletagclick') this._cy.edges().unselectify(); } }; private registerCustomEvents(scope:ICompositionGraphScope, el:JQuery) { + this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_GROUP_INSTANCE_UPDATE, (groupInstance:GroupInstance) => { + this.compositionGraphZoneUtils.findAndUpdateZoneInstanceData(scope.zones, groupInstance); + this.GeneralGraphUtils.showGroupUpdateSuccess(); + }); + + this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_POLICY_INSTANCE_UPDATE, (policyInstance: PolicyInstance) => { + this.compositionGraphZoneUtils.findAndUpdateZoneInstanceData(scope.zones, policyInstance); + this.GeneralGraphUtils.showPolicyUpdateSuccess(); + }); + this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_PALETTE_COMPONENT_HOVER_IN, (leftPaletteComponent:LeftPaletteComponent) => { - if(scope.isOnDrag || - leftPaletteComponent.categoryType === LeftPaletteMetadataTypes.Group || - leftPaletteComponent.categoryType === LeftPaletteMetadataTypes.Policy) { + if (scope.isOnDrag) { return; } @@ -264,47 +280,33 @@ export class CompositionGraph implements ng.IDirective { //----------------------- ORIT TO FIX------------------------// - this.ComponentServiceNg2.getCapabilitiesAndRequirements(leftPaletteComponent.componentType, leftPaletteComponent.uniqueId).subscribe((response: ComponentGenericResponse) => { + this.ComponentServiceNg2.getCapabilitiesAndRequirements(leftPaletteComponent.componentType, leftPaletteComponent.uniqueId).subscribe((response:ComponentGenericResponse) => { - let component = this.ComponentFactory.createEmptyComponent(leftPaletteComponent.componentType); - component.uniqueId = component.uniqueId; - component.capabilities = response.capabilities; - component.requirements = response.requirements; - this.GeneralGraphUtils.componentRequirementsAndCapabilitiesCaching.setValue(leftPaletteComponent.uniqueId, component); - let filteredNodesData = this.matchCapabilitiesRequirementsUtils.findMatchingNodes(component, nodesData, nodesLinks); - this.matchCapabilitiesRequirementsUtils.fadeNonMachingComponents(filteredNodesData, nodesData, this._cy); - this.matchCapabilitiesRequirementsUtils.highlightMatchingComponents(filteredNodesData, this._cy) - }); + let component = this.ComponentFactory.createEmptyComponent(leftPaletteComponent.componentType); + component.uniqueId = component.uniqueId; + component.capabilities = response.capabilities; + component.requirements = response.requirements; + this.GeneralGraphUtils.componentRequirementsAndCapabilitiesCaching.setValue(leftPaletteComponent.uniqueId, component); + }); }); - this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_ADD_COMPONENT_INSTANCE_ZONE_START, (component:Component, paletteComponent:LeftPaletteComponent, startPosition:Point) => { - this.LoaderService.showLoader('composition-graph'); - - let zoneType:string = LeftPaletteMetadataTypes[paletteComponent.categoryType].toLowerCase(); - scope.zones[zoneType].showZone = true; - if(scope.minifyZone) scope.minifyZone = false; + this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_ADD_ZONE_INSTANCE_FROM_PALETTE, (component:Component, paletteComponent:LeftPaletteComponent, startPosition:Point) => { - this.policiesService.createPolicyInstance(component.componentType, component.uniqueId, paletteComponent.type).subscribe((newInstance)=>{ + let zoneType:ZoneInstanceType = this.compositionGraphZoneUtils.getZoneTypeForPaletteComponent(paletteComponent.categoryType); + this.compositionGraphZoneUtils.showZone(scope.zones[zoneType]); + this.LoaderService.showLoader('composition-graph'); + this.compositionGraphZoneUtils.createZoneInstanceFromLeftPalette(zoneType, component, paletteComponent.type).subscribe((zoneInstance:ZoneInstance) => { this.LoaderService.hideLoader('composition-graph'); - scope.newZoneInstance = newInstance; - this.compositionGraphZoneUtils.showAnimationToZone(startPosition, zoneType); - }, (error) => { + this.compositionGraphZoneUtils.addInstanceToZone(scope.zones[zoneInstance.type], zoneInstance, true); + this.compositionGraphZoneUtils.createPaletteToZoneAnimation(startPosition, zoneType, zoneInstance); + }, (error)=> { this.LoaderService.hideLoader('composition-graph'); }); }); - this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_FINISH_ANIMATION_ZONE, () => { - if(scope.newZoneInstance){ - this.compositionGraphZoneUtils.addInstanceToZone(scope.zones['policy'], scope.newZoneInstance); - } - }) - - this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_ZONE_SIZE_CHANGE, () => { - scope.minifyZone = true; - }) - this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_PALETTE_COMPONENT_HOVER_OUT, () => { + this._cy.emit('hidehandles'); this.matchCapabilitiesRequirementsUtils.resetFadedNodes(this._cy); }); @@ -334,13 +336,34 @@ export class CompositionGraph implements ng.IDirective { this.NodesGraphUtils.deleteNode(this._cy, scope.component, nodeToDelete); }); - this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_DELETE_MULTIPLE_COMPONENTS, () => { + this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_DELETE_ZONE_INSTANCE, (deletedInstance:UIZoneInstanceObject) => { - this._cy.$('node:selected').each((i:number, node:Cy.CollectionNodes) => { - this.NodesGraphUtils.deleteNode(this._cy, scope.component, node); - }); + if(deletedInstance.type === ZoneInstanceType.POLICY){ + scope.component.policies = scope.component.policies.filter(policy => policy.uniqueId !== deletedInstance.uniqueId); + } else if (deletedInstance.type === ZoneInstanceType.GROUP) { + scope.component.groupInstances = scope.component.groupInstances.filter(group => group.uniqueId !== deletedInstance.uniqueId); + } + //remove it from zones + scope.zones[deletedInstance.type].removeInstance(deletedInstance.uniqueId); + if (deletedInstance.type === ZoneInstanceType.GROUP && !_.isEmpty(scope.zones[ZoneInstanceType.POLICY])) { + this.compositionGraphZoneUtils.updateTargetsOrMembersOnCanvasDelete(deletedInstance.uniqueId, [scope.zones[ZoneInstanceType.POLICY]], ZoneInstanceAssignmentType.GROUPS); + } + this.eventListenerService.notifyObservers(EVENTS.UPDATE_PANEL); + }); + this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_DELETE_COMPONENT_INSTANCE_SUCCESS, (componentInstanceId:string)=> { + if (!_.isEmpty(scope.zones)) { + this.compositionGraphZoneUtils.updateTargetsOrMembersOnCanvasDelete(componentInstanceId, scope.zones, ZoneInstanceAssignmentType.COMPONENT_INSTANCES); + } }); + // not in use; commenting out + // this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_DELETE_MULTIPLE_COMPONENTS, () => { + + // this._cy.$('node:selected').each((i:number, node:Cy.CollectionNodes) => { + // this.NodesGraphUtils.deleteNode(this._cy, scope.component, node); + // }); + + // }); this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_DELETE_EDGE, (releaseLoading:boolean, linksToDelete:Cy.CollectionEdges) => { this.CompositionGraphLinkUtils.deleteLink(this._cy, scope.component, releaseLoading, linksToDelete); @@ -375,8 +398,9 @@ export class CompositionGraph implements ng.IDirective { this.loadGraphData(scope); }); - scope.zoom = (zoomIn: boolean):void => { - let currentZoom: number = this._cy.zoom(); + + scope.zoom = (zoomIn:boolean):void => { + let currentZoom:number = this._cy.zoom(); if (zoomIn) { this.GeneralGraphUtils.zoomGraphTo(this._cy, currentZoom + .1); } else { @@ -384,37 +408,32 @@ export class CompositionGraph implements ng.IDirective { } } - //Zooms to fit all of the nodes in the collection passed in. If no nodes are passed in, will zoom to fit all nodes on graph - scope.zoomAll = (nodes?:Cy.CollectionNodes) => { - if (!nodes || !nodes.length) { - nodes = this._cy.nodes(); - } - + + scope.zoomAllWithoutSidebar = () => { scope.withSidebar = false; - this._cy.animate({ - fit: { eles: nodes, padding: 20 }, - center: { eles: nodes } - }, { duration: 400 }); + setTimeout(() => { //wait for sidebar changes to take effect before zooming + this.GeneralGraphUtils.zoomAll(this._cy); + }); }; - scope.getAutoCompleteValues = (searchTerm: string) => { + scope.getAutoCompleteValues = (searchTerm:string) => { if (searchTerm.length > 1) { //US requirement: only display search results after 2nd letter typed. - let nodes: Cy.CollectionNodes = this.NodesGraphUtils.getMatchingNodesByName(this._cy, searchTerm); + let nodes:Cy.CollectionNodes = this.NodesGraphUtils.getMatchingNodesByName(this._cy, searchTerm); scope.componentInstanceNames = _.map(nodes, node => node.data('name')); } else { scope.componentInstanceNames = []; } }; - scope.highlightSearchMatches = (searchTerm: string) => { + scope.highlightSearchMatches = (searchTerm:string) => { this.NodesGraphUtils.highlightMatchingNodesByName(this._cy, searchTerm); - let matchingNodes: Cy.CollectionNodes = this.NodesGraphUtils.getMatchingNodesByName(this._cy, searchTerm); - scope.zoomAll(matchingNodes); + let matchingNodes:Cy.CollectionNodes = this.NodesGraphUtils.getMatchingNodesByName(this._cy, searchTerm); + this.GeneralGraphUtils.zoomAll(this._cy, matchingNodes); }; scope.saveChangedCapabilityProperties = ():Promise<PropertyBEModel[]> => { return new Promise<PropertyBEModel[]>((resolve) => { - const capabilityPropertiesBE: PropertyBEModel[] = this.ConnectionWizardServiceNg2.changedCapabilityProperties.map((prop) => { + const capabilityPropertiesBE:PropertyBEModel[] = this.ConnectionWizardServiceNg2.changedCapabilityProperties.map((prop) => { prop.value = prop.getJSONValue(); const propBE = new PropertyBEModel(prop); propBE.parentUniqueId = this.ConnectionWizardServiceNg2.selectedMatch.relationship.relation.capabilityOwnerId; @@ -464,7 +483,7 @@ export class CompositionGraph implements ng.IDirective { scope.deletePathsOnCy = () => { this.servicePathGraphUtils.deletePathsFromGraph(this._cy, <Service> scope.component); }; - scope.drawPathOnCy = (data: ForwardingPath) => { + scope.drawPathOnCy = (data:ForwardingPath) => { this.servicePathGraphUtils.drawPath(this._cy, data, <Service> scope.component); }; @@ -486,10 +505,14 @@ export class CompositionGraph implements ng.IDirective { this.ConnectionWizardServiceNg2.selectedMatch.relationship = relationship; const title = `Connection Properties`; - const saveButton: ButtonModel = new ButtonModel('Save', 'blue', () => { - scope.saveChangedCapabilityProperties().then(() => { this.ModalServiceNg2.closeCurrentModal(); }) + const saveButton:ButtonModel = new ButtonModel('Save', 'blue', () => { + scope.saveChangedCapabilityProperties().then(() => { + this.ModalServiceNg2.closeCurrentModal(); + }) + }); + const cancelButton:ButtonModel = new ButtonModel('Cancel', 'white', () => { + this.ModalServiceNg2.closeCurrentModal(); }); - const cancelButton: ButtonModel = new ButtonModel('Cancel', 'white', () => { this.ModalServiceNg2.closeCurrentModal(); }); const modal = new ModalModel('xl', title, '', [saveButton, cancelButton]); const modalInstance = this.ModalServiceNg2.createCustomModal(modal); this.ModalServiceNg2.addDynamicContentToModal(modalInstance, ConnectionPropertiesViewComponent); @@ -500,7 +523,8 @@ export class CompositionGraph implements ng.IDirective { this.ComponentInstanceServiceNg2.getInstanceCapabilityProperties(scope.component, linkData.target, capability) .subscribe(() => { resolve(); - }, (error) => {}); + }, (error) => { + }); } else { resolve(); } @@ -508,7 +532,8 @@ export class CompositionGraph implements ng.IDirective { this.ModalServiceNg2.addDynamicContentToModal(modalInstance, ConnectionPropertiesViewComponent); }) - }, (error) => {}); + }, (error) => { + }); }; scope.deleteRelation = (link:Cy.CollectionEdges) => { @@ -523,20 +548,20 @@ export class CompositionGraph implements ng.IDirective { }; /* - scope.hideAssetPopover = ():void => { - - this.commonGraphUtils.safeApply(scope, () => { - scope.assetPopoverOpen = false; - scope.assetPopoverObj = null; - }); - }; - - scope.deleteNode = (nodeId:string):void => { - if (!scope.isViewOnly) { - this.NodesGraphUtils.confirmDeleteNode(nodeId, this._cy, scope.component); - //scope.hideAssetPopover(); - } - };*/ + scope.hideAssetPopover = ():void => { + + this.commonGraphUtils.safeApply(scope, () => { + scope.assetPopoverOpen = false; + scope.assetPopoverObj = null; + }); + }; + + scope.deleteNode = (nodeId:string):void => { + if (!scope.isViewOnly) { + this.NodesGraphUtils.confirmDeleteNode(nodeId, this._cy, scope.component); + //scope.hideAssetPopover(); + } + };*/ } private registerCytoscapeGraphEvents(scope:ICompositionGraphScope) { @@ -599,22 +624,30 @@ export class CompositionGraph implements ng.IDirective { } }); - /* this._cy.on('mouseover', 'node', (event:Cy.EventObject) => { - if (!this._cy.scratch('_edge_editation_highlights')) { - this.commonGraphUtils.safeApply(scope, () => { - this.showNodePopoverMenu(scope, event.cyTarget[0]); - }); - } - }); + /* this._cy.on('mouseover', 'node', (event:Cy.EventObject) => { + if (!this._cy.scratch('_edge_editation_highlights')) { + this.commonGraphUtils.safeApply(scope, () => { + this.showNodePopoverMenu(scope, event.cyTarget[0]); + }); + } + }); + + this._cy.on('mouseout', 'node', (event:Cy.EventObject) => { + scope.hideAssetPopover(); + });*/ + - this._cy.on('mouseout', 'node', (event:Cy.EventObject) => { - scope.hideAssetPopover(); - });*/ this._cy.on('handlemouseover', (event, payload) => { if (payload.node.grabbed() || this._cy.scratch('_edge_editation_highlights') === true) { //no need to add opacity while we are dragging and hovering othe nodes- or if opacity was already calculated for these nodes return; } + + if (scope.zoneTagMode) { + scope.zoneTagMode = scope.zones[scope.activeZoneInstance.type].getHoverTagModeId(); + return; + } + let nodesData = this.NodesGraphUtils.getAllNodesData(this._cy.nodes()); let nodesLinks = this.GeneralGraphUtils.getAllCompositionCiLinks(this._cy); @@ -622,12 +655,16 @@ export class CompositionGraph implements ng.IDirective { let filteredNodesData = this.matchCapabilitiesRequirementsUtils.findMatchingNodes(payload.node.data().componentInstance, linkableNodes, nodesLinks); this.matchCapabilitiesRequirementsUtils.highlightMatchingComponents(filteredNodesData, this._cy); this.matchCapabilitiesRequirementsUtils.fadeNonMachingComponents(filteredNodesData, nodesData, this._cy, payload.node.data()); - + this._cy.scratch()._edge_editation_highlights = true; /*scope.hideAssetPopover();*/ }); this._cy.on('handlemouseout', () => { + if (scope.zoneTagMode) { + scope.zoneTagMode = scope.zones[scope.activeZoneInstance.type].getTagModeId(); + return; + } if (this._cy.scratch('_edge_editation_highlights') === true) { this._cy.removeScratch('_edge_editation_highlights'); this._cy.emit('hidehandles'); @@ -638,15 +675,20 @@ export class CompositionGraph implements ng.IDirective { this._cy.on('tapend', (event:Cy.EventObject) => { scope.isOnDrag = false; + if (scope.zoneTagMode) { + return; + } if (event.cyTarget === this._cy) { //On Background clicked if (this._cy.$('node:selected').length === 0) { //if the background click but not dragged + if (scope.activeZoneInstance) { + scope.unsetActiveZoneInstance(); + } this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_GRAPH_BACKGROUND_CLICKED); } scope.hideRelationMenu(); } else if (event.cyTarget.isEdge()) { //On Edge clicked - if (scope.isViewOnly) return; this.CompositionGraphLinkUtils.handleLinkClick(this._cy, event); if (event.cyTarget.data().type === CompositionCiServicePathLink.LINK_TYPE) { return; @@ -655,6 +697,7 @@ export class CompositionGraph implements ng.IDirective { } else { //On Node clicked + this._cy.nodes(':grabbed').style({'overlay-opacity': 0}); let isUcpe:boolean = event.cyTarget.data().isUcpe; @@ -668,6 +711,9 @@ export class CompositionGraph implements ng.IDirective { this.NodesGraphUtils.onNodesPositionChanged(this._cy, scope.component, nodesMoved); } else { this.$log.debug('composition-graph::onNodeSelectedEvent:: fired'); + if (scope.activeZoneInstance) { + scope.unsetActiveZoneInstance(); + } scope.$apply(() => { this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_NODE_SELECTED, event.cyTarget.data().componentInstance); //open node popover menu @@ -684,8 +730,21 @@ export class CompositionGraph implements ng.IDirective { }); this._cy.on('boxselect', 'node', (event:Cy.EventObject) => { + scope.unsetActiveZoneInstance(); this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_NODE_SELECTED, event.cyTarget.data().componentInstance); }); + + this._cy.on('canvasredraw', (event:Cy.EventObject) => { + if (scope.zoneTagMode) { + this.compositionGraphZoneUtils.showZoneTagIndications(this._cy, scope.activeZoneInstance); + } + }); + + this._cy.on('handletagclick', (event:Cy.EventObject, eventData:any) => { + this.compositionGraphZoneUtils.handleTagClick(this._cy, scope.activeZoneInstance, eventData.nodeId); + + + }); } private openModifyLinkMenu = (scope:ICompositionGraphScope, linkMenuObject:LinkMenu, timeOutInMilliseconds?:number) => { @@ -710,14 +769,15 @@ export class CompositionGraph implements ng.IDirective { } }); } - scope.canvasMenuProps.items.push({ - contents: 'Delete', - styleClass: 'w-sdc-canvas-menu-item-delete', - action: () => { - scope.deleteRelation(<Cy.CollectionEdges>linkMenuObject.link); - } - }); - + if(!scope.isViewOnly){ + scope.canvasMenuProps.items.push({ + contents: 'Delete', + styleClass: 'w-sdc-canvas-menu-item-delete', + action: () => { + scope.deleteRelation(<Cy.CollectionEdges>linkMenuObject.link); + } + }); + } scope.relationMenuTimeout = this.$timeout(() => { scope.hideRelationMenu(); }, timeOutInMilliseconds ? timeOutInMilliseconds : 6000); @@ -726,15 +786,19 @@ export class CompositionGraph implements ng.IDirective { private initGraphNodes(componentInstances:ComponentInstance[], isViewOnly:boolean) { - if (!isViewOnly) { //Init nodes handle extension - enable dynamic links - setTimeout(()=> { - let handles = new CytoscapeEdgeEditation; - handles.init(this._cy, 18); - handles.registerHandle(ComponentInstanceNodesStyle.getBasicNodeHanlde()); - handles.registerHandle(ComponentInstanceNodesStyle.getBasicSmallNodeHandle()); - handles.registerHandle(ComponentInstanceNodesStyle.getUcpeCpNodeHandle()); - }, 0); - } + + setTimeout(()=> { + let handles = new CytoscapeEdgeEditation; + handles.init(this._cy); + if (!isViewOnly) { //Init nodes handle extension - enable dynamic links + handles.initNodeEvents(); + handles.registerHandle(ComponentInstanceNodesStyle.getAddEdgeHandle()); + } + handles.registerHandle(ComponentInstanceNodesStyle.getTagHandle()); + handles.registerHandle(ComponentInstanceNodesStyle.getTaggedPolicyHandle()); + handles.registerHandle(ComponentInstanceNodesStyle.getTaggedGroupHandle()); + }, 0); + _.each(componentInstances, (instance) => { let compositionGraphNode:CompositionCiNodeBase = this.NodesFactory.createNode(instance); @@ -755,7 +819,7 @@ export class CompositionGraph implements ng.IDirective { scope.verifyDrop = (event:JQueryEventObject) => { - if (this.dragElement.hasClass('red')) { + if (!this.dragElement || this.dragElement.hasClass('red')) { return false; } return true; @@ -777,43 +841,85 @@ export class CompositionGraph implements ng.IDirective { private initZones = (scope:ICompositionGraphScope):void => { scope.zones = this.compositionGraphZoneUtils.createCompositionZones(); - scope.zoneInstanceModeChanged = (newMode:ZoneInstanceMode, instance:ZoneInstanceConfig, zoneId:string):void => { - if(scope.zoneTagMode) { //we're in tag mode. - if(instance == scope.activeZoneInstance && newMode == ZoneInstanceMode.TAG){ //we want to toggle tag mode off. - scope.unsetActiveZoneInstance(); + + scope.zoneMinimizeToggle = (zoneType:ZoneInstanceType):void => { + scope.zones[zoneType].minimized = !scope.zones[zoneType].minimized; + }; + + scope.zoneInstanceModeChanged = (newMode:ZoneInstanceMode, instance:ZoneInstance, zoneId:ZoneInstanceType):void => { + if (scope.zoneTagMode) { //we're in tag mode. + if (instance == scope.activeZoneInstance && newMode == ZoneInstanceMode.NONE) { //we want to turn tag mode off. + scope.zoneTagMode = null; + scope.activeZoneInstance.mode = ZoneInstanceMode.SELECTED; + this.compositionGraphZoneUtils.endCyTagMode(this._cy); + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_CANVAS_TAG_END, instance); + } } else { - scope.setZoneInstanceMode(newMode, instance, zoneId); - } - }; + if (instance != scope.activeZoneInstance || (instance == scope.activeZoneInstance && newMode > ZoneInstanceMode.HOVER)) { //when active zone instance gets hover/none,dont actually change mode, just show/hide indications + instance.mode = newMode; + } - scope.setZoneInstanceMode = (newMode:ZoneInstanceMode, instance:ZoneInstanceConfig, zoneId:string):void => { - instance.mode = newMode; - switch(newMode){ - case ZoneInstanceMode.TAG: { - scope.zoneTagMode = zoneId + "-tagging"; + if (newMode == ZoneInstanceMode.NONE) { + this.compositionGraphZoneUtils.hideZoneTagIndications(this._cy); + if (scope.zones[ZoneInstanceType.GROUP]) { + this.compositionGraphZoneUtils.hideGroupZoneIndications(scope.zones[ZoneInstanceType.GROUP].instances); + } + } + if (newMode >= ZoneInstanceMode.HOVER) { + this.compositionGraphZoneUtils.showZoneTagIndications(this._cy, instance); + if (instance.type == ZoneInstanceType.POLICY && scope.zones[ZoneInstanceType.GROUP]) { + this.compositionGraphZoneUtils.showGroupZoneIndications(scope.zones[ZoneInstanceType.GROUP].instances, instance); + } } - case ZoneInstanceMode.SELECTED: { //case TAG flows into here as well + if (newMode >= ZoneInstanceMode.SELECTED) { + this._cy.$('node:selected').unselect(); + if (scope.activeZoneInstance && scope.activeZoneInstance != instance && newMode >= ZoneInstanceMode.SELECTED) { + scope.activeZoneInstance.mode = ZoneInstanceMode.NONE; + } scope.activeZoneInstance = instance; - break; + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_ZONE_INSTANCE_SELECTED, instance); + } + if (newMode == ZoneInstanceMode.TAG) { + this.compositionGraphZoneUtils.startCyTagMode(this._cy); + scope.zoneTagMode = scope.zones[zoneId].getTagModeId(); + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_CANVAS_TAG_START, zoneId); } } }; - scope.unsetActiveZoneInstance = ():void => { - scope.activeZoneInstance.mode = ZoneInstanceMode.NONE; - scope.activeZoneInstance = null; - scope.zoneTagMode = null; - }; + scope.zoneInstanceTagged = (taggedInstance:ZoneInstance) => { + scope.activeZoneInstance.addOrRemoveAssignment(taggedInstance.instanceData.uniqueId, ZoneInstanceAssignmentType.GROUPS); + let newHandle:string = this.compositionGraphZoneUtils.getCorrectHandleForNode(taggedInstance.instanceData.uniqueId, scope.activeZoneInstance); + taggedInstance.showHandle(newHandle); + } - scope.clickOutsideZoneInstance = ():void => { - if(!scope.zoneTagMode) + scope.zoneBackgroundClicked = ():void => { + if (!scope.zoneTagMode && scope.activeZoneInstance) { scope.unsetActiveZoneInstance(); + } }; - }; + scope.zoneAssignmentSaveStart = () => { + this.LoaderService.showLoader('composition-graph'); + } + scope.zoneAssignmentSaveComplete = (success:boolean) => { + this.LoaderService.hideLoader('composition-graph'); + if (!success) { + this.GeneralGraphUtils.showUpdateFailure(); + } + }; + scope.unsetActiveZoneInstance = ():void => { + if(scope.activeZoneInstance){ + scope.activeZoneInstance.mode = ZoneInstanceMode.NONE; + scope.activeZoneInstance = null; + scope.zoneTagMode = null; + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_GRAPH_BACKGROUND_CLICKED); + } + }; + }; public static factory = ($q, @@ -835,8 +941,7 @@ export class CompositionGraph implements ng.IDirective { ModalService, ConnectionWizardService, ComponentInstanceServiceNg2, - ServicePathGraphUtils, - PoliciesService) => { + ServicePathGraphUtils) => { return new CompositionGraph( $q, $log, @@ -857,8 +962,7 @@ export class CompositionGraph implements ng.IDirective { ModalService, ConnectionWizardService, ComponentInstanceServiceNg2, - ServicePathGraphUtils, - PoliciesService); + ServicePathGraphUtils); } } @@ -882,6 +986,5 @@ CompositionGraph.factory.$inject = [ 'ModalServiceNg2', 'ConnectionWizardServiceNg2', 'ComponentInstanceServiceNg2', - 'ServicePathGraphUtils', - 'PoliciesServiceNg2' + 'ServicePathGraphUtils' ]; diff --git a/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.html b/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.html index 487e4cb65a..2d8145f81e 100644 --- a/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.html +++ b/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.html @@ -1,12 +1,12 @@ <loader display="isLoading" loader-type="composition-graph"></loader> -<div class="sdc-composition-graph-wrapper {{zoneTagMode}}" ng-class="{'view-only':isViewOnly}" - data-drop="true" +<div class="sdc-composition-graph-wrapper {{zoneTagMode}}" ng-class="{'with-sidebar': withSidebar, 'view-only':isViewOnly}" + data-drop="!zoneTagMode" data-jqyoui-options="{accept: verifyDrop}" data-jqyoui-droppable="{onDrop:'dropCallback', beforeDrop: 'beforeDropCallback'}"> </div> -<relation-menu relation-menu-directive-obj="relationMenuDirectiveObj" is-link-menu-open="isLinkMenuOpen" - create-relation="createLinkFromMenu" cancel="cancelRelationMenu()"></relation-menu> +<!-- <relation-menu relation-menu-directive-obj="relationMenuDirectiveObj" is-link-menu-open="isLinkMenuOpen" + create-relation="createLinkFromMenu" cancel="cancelRelationMenu()"></relation-menu> --> <menu-list-ng2 [props]="canvasMenuProps"></menu-list-ng2> @@ -19,10 +19,11 @@ [delete-paths]="deletePathsOnCy" [selected-path-id]="selectedPathId"> </ng2-service-path-selector> - <ng2-service-path + <ng2-service-path ng-if="component.isService()" [service]="component" - [on-create]="createOrUpdateServicePath"> + [on-create]="createOrUpdateServicePath" + [is-view-only]="isViewOnly"> </ng2-service-path> <ng2-search-with-autocomplete [search-placeholder]="'Type to search'" @@ -31,17 +32,19 @@ (search-button-clicked)="highlightSearchMatches($event)" [search-bar-class]="'composition-search'"> </ng2-search-with-autocomplete> - <div class="zoom-icons sprite-new canvas-fit-all" data-ng-click="zoomAll()"></div> + <div class="zoom-icons sprite-new canvas-fit-all" data-ng-click="zoomAllWithoutSidebar()"></div> <div class="zoom-icons sprite-new zoom-plus" data-ng-click="zoom(true)"></div> <div class="zoom-icons sprite-new zoom-minus" data-ng-click="zoom(false)"></div> </div> <!--<asset-popover ng-if="assetPopoverOpen" asset-popover-obj="assetPopoverObj" delete-asset="deleteNode(assetPopoverObj.nodeId)"></asset-popover>--> <div class="sdc-canvas-zones__wrapper {{zoneTagMode}}" data-ng-class="{'with-sidebar': withSidebar}"> - <ng2-zone-container data-ng-repeat="zoneConfig in zones" [title]="zoneConfig.title" [class]="zoneConfig.type" [count]="zoneConfig.instances.length" [show-zone] = "zoneConfig.showZone" [minify-zone] = "minifyZone"> + <ng2-zone-container data-ng-repeat="zone in zones" [title]="zone.title" [type]="zone.type" [count]="zone.instances.length" + [visible]="zone.visible" [minimized]="zone.minimized" (minimize)="zoneMinimizeToggle(zone.type)" (background-click)="zoneBackgroundClicked()"> <ng2-zone-instance - data-ng-repeat="instance in zoneConfig.instances" clicked-outside="{onClickedOutside: 'clickOutsideZoneInstance()', clickedOutsideEnable: 'activeZoneInstance == instance'}" - [config]="instance" [default-icon-text]="zoneConfig.defaultIconText" [is-active]="activeZoneInstance == instance" [active-instance-mode]="activeZoneInstance && activeZoneInstance.mode" - (mode-change)="zoneInstanceModeChanged($event.newMode, $event.instance, zoneConfig.type)"> + data-ng-repeat="instance in zone.instances" [hidden]="instance.hidden" + [zone-instance]="instance" [default-icon-text]="zone.defaultIconText" [is-active]="activeZoneInstance == instance" [active-instance-mode]="activeZoneInstance && activeZoneInstance.mode" + [is-view-only]="isViewOnly" [force-save]="instance.forceSave" (mode-change)="zoneInstanceModeChanged($event.newMode, $event.instance, zone.type)" (tag-handle-click)="zoneInstanceTagged($event)" + (assignment-save-start)="zoneAssignmentSaveStart()" (assignment-save-complete)="zoneAssignmentSaveComplete($event)"> </ng2-zone-instance> </ng2-zone-container> -</div> +</div>
\ No newline at end of file diff --git a/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.less b/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.less index 5a6a104670..7124a4b5a6 100644 --- a/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.less +++ b/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.less @@ -6,6 +6,10 @@ composition-graph { .sdc-composition-graph-wrapper{ height:100%; width: 100%; + + &.with-sidebar { + width: calc(~'100% - 300px'); + } } .view-only{ @@ -29,10 +33,18 @@ composition-graph { } } + .group-tagging { - cursor: url("/assets/styles/images/canvas-tagging-icons/adding_group.svg"), pointer; + cursor: url("../../../../assets/styles/images/canvas-tagging-icons/group_1.svg"), pointer; + } + .group-tagging-hover { + cursor: url("../../../../assets/styles/images/canvas-tagging-icons/group_2.svg"), pointer; } .policy-tagging { - cursor: url("/assets/styles/images/canvas-tagging-icons/adding_policy.svg"), pointer; + cursor: url("../../../../assets/styles/images/canvas-tagging-icons/policy_1.svg"), pointer; + } + .policy-tagging-hover { + cursor: url("../../../../assets/styles/images/canvas-tagging-icons/policy_2.svg"), pointer; } + } diff --git a/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-general-utils.ts b/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-general-utils.ts index 73e03e954d..329af56e87 100644 --- a/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-general-utils.ts +++ b/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-general-utils.ts @@ -34,7 +34,8 @@ export class CompositionGraphGeneralUtils { constructor(private $q:ng.IQService, private LoaderService:LoaderService, private commonGraphUtils:CommonGraphUtils, - private matchCapabilitiesRequirementsUtils:MatchCapabilitiesRequirementsUtils) { + private matchCapabilitiesRequirementsUtils:MatchCapabilitiesRequirementsUtils, + private Notification:any) { CompositionGraphGeneralUtils.graphUtilsUpdateQueue = new QueueUtils(this.$q); } @@ -73,6 +74,34 @@ export class CompositionGraphGeneralUtils { renderedPosition: { x: zx, y: zy } }); } + + + //saves the current zoom, and then sets a temporary maximum zoom for zoomAll, and then reverts to old value + public zoomAllWithMax = (cy:Cy.Instance, maxZoom:number):void => { + + let oldMaxZoom:number = cy.maxZoom(); + + cy.maxZoom(maxZoom); + this.zoomAll(cy); + cy.maxZoom(oldMaxZoom); + + }; + + + //Zooms to fit all of the nodes in the collection passed in. If no nodes are passed in, will zoom to fit all nodes on graph + public zoomAll = (cy:Cy.Instance, nodes?:Cy.CollectionNodes):void => { + + if (!nodes || !nodes.length) { + nodes = cy.nodes(); + } + + cy.resize(); + cy.animate({ + fit: { eles: nodes, padding: 20 }, + center: { eles: nodes } + }, { duration: 400 }); + }; + /** * will return true/false if two nodes overlapping * @@ -223,6 +252,27 @@ export class CompositionGraphGeneralUtils { }; + public showPolicyUpdateSuccess = () => { + this.Notification.success({ + message: "Policy Updated", + title: "Success" + }); + } + + public showGroupUpdateSuccess = () => { + this.Notification.success({ + message: "Group Updated", + title: "Success" + }); + } + + public showUpdateFailure = () => { + this.Notification.error({ + message: "Update Failed", + title: "Error" + }); + }; + /** * Get Graph Utils server queue * @returns {QueueUtils} @@ -270,4 +320,4 @@ export class CompositionGraphGeneralUtils { }; } -CompositionGraphGeneralUtils.$inject = ['$q', 'LoaderService', 'CommonGraphUtils', 'MatchCapabilitiesRequirementsUtils']; +CompositionGraphGeneralUtils.$inject = ['$q', 'LoaderService', 'CommonGraphUtils', 'MatchCapabilitiesRequirementsUtils', 'Notification']; diff --git a/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-nodes-utils.ts b/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-nodes-utils.ts index fb1e6650bd..cfec49267a 100644 --- a/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-nodes-utils.ts +++ b/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-nodes-utils.ts @@ -105,6 +105,8 @@ export class CompositionGraphNodesUtils { (<Service>component).forwardingPaths = response.forwardingPaths; }); + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_DELETE_COMPONENT_INSTANCE_SUCCESS, nodeId); + //update UI cy.remove(nodeToDelete); }; diff --git a/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-service-path-utils.ts b/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-service-path-utils.ts index ef047d7dd3..1a348912fc 100644 --- a/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-service-path-utils.ts +++ b/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-service-path-utils.ts @@ -47,8 +47,14 @@ export class ServicePathGraphUtils { _.forEach(pathElements, (link: ForwardingPathLink) => { let data:CompositionCiServicePathLink = new CompositionCiServicePathLink(link); - data.source = data.forwardingPathLink.fromNode; - data.target = data.forwardingPathLink.toNode; + data.source = _.find( + service.componentInstances, + instance => instance.name === data.forwardingPathLink.fromNode + ).uniqueId; + data.target = _.find( + service.componentInstances, + instance => instance.name === data.forwardingPathLink.toNode + ).uniqueId; data.pathId = forwardingPath.uniqueId; data.pathName = forwardingPath.name; this.commonGraphUtils.insertServicePathLinkToGraph(cy, data); diff --git a/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-zone-utils.ts b/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-zone-utils.ts index 28f2dc85d2..bcf0cb7bb9 100644 --- a/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-zone-utils.ts +++ b/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/composition-graph-zone-utils.ts @@ -1,55 +1,195 @@ -import { PolicyInstance } from "app/models/graph/zones/policy-instance"; -import { ZoneConfig, ZoneInstanceConfig } from "app/models/graph/zones/zone-child"; -import { DynamicComponentService } from "app/ng2/services/dynamic-component.service"; -import { PaletteAnimationComponent } from "app/ng2/components/ui/palette-animation/palette-animation.component"; -import { Point } from "../../../../models"; +import {PolicyInstance} from "app/models/graph/zones/policy-instance"; +import {ZoneInstance, ZoneInstanceType, ZoneInstanceAssignmentType} from "app/models/graph/zones/zone-instance"; +import {Zone} from "app/models/graph/zones/zone"; +import {DynamicComponentService} from "app/ng2/services/dynamic-component.service"; +import {PaletteAnimationComponent} from "app/ng2/components/ui/palette-animation/palette-animation.component"; +import {Point, LeftPaletteMetadataTypes, Component} from "../../../../models"; +import {CanvasHandleTypes} from "app/utils"; +import {PoliciesService} from "../../../../ng2/services/policies.service"; +import {Observable} from "rxjs"; +import {GroupsService} from "../../../../ng2/services/groups.service"; +import {GroupInstance} from "app/models/graph/zones/group-instance"; + export class CompositionGraphZoneUtils { - constructor(private dynamicComponentService: DynamicComponentService) {} + constructor(private dynamicComponentService:DynamicComponentService, + private policiesService:PoliciesService, + private groupsService:GroupsService) { + } + + + public createCompositionZones = ():Array<Zone> => { + let zones:Array<Zone> = []; + + zones[ZoneInstanceType.POLICY] = new Zone('Policies', 'P', ZoneInstanceType.POLICY); + zones[ZoneInstanceType.GROUP] = new Zone('Groups', 'G', ZoneInstanceType.GROUP); - public createCompositionZones(){ - let zones = { - 'policy': new ZoneConfig('Policies', 'P', 'policy', false), - 'group': new ZoneConfig('Groups', 'G', 'group', false) - }; return zones; } - public initPolicyInstances(policyZone:ZoneConfig, policies:Array<PolicyInstance>) { - if(policies && policies.length){ - policyZone.showZone = true; + public showZone = (zone:Zone):void => { + zone.visible = true; + zone.minimized = false; + } + + public getZoneTypeForPaletteComponent = (componentCategory:LeftPaletteMetadataTypes) => { + if (componentCategory == LeftPaletteMetadataTypes.Group) { + return ZoneInstanceType.GROUP; + } else if (componentCategory == LeftPaletteMetadataTypes.Policy) { + return ZoneInstanceType.POLICY; + } + }; + + public initZoneInstances(zones:Array<Zone>, component:Component) { + if (component.groupInstances && component.groupInstances.length) { + this.showZone(zones[ZoneInstanceType.GROUP]); + _.forEach(component.groupInstances, (group:GroupInstance) => { + let newInstance = new ZoneInstance(group, component); + this.addInstanceToZone(zones[ZoneInstanceType.GROUP], newInstance); + }); + } + + if (component.policies && component.policies.length) { + this.showZone(zones[ZoneInstanceType.POLICY]); + _.forEach(component.policies, (policy:PolicyInstance) => { + let newInstance = new ZoneInstance(policy, component); + this.addInstanceToZone(zones[ZoneInstanceType.POLICY], newInstance); + + }); } - _.forEach(policies, (policy:PolicyInstance) => { - policyZone.instances.push(new ZoneInstanceConfig(policy)); + } + + public findAndUpdateZoneInstanceData (zones: Array<Zone>, instanceData:PolicyInstance | GroupInstance) { + _.forEach(zones, (zone:Zone) => { + _.forEach(zone.instances, (zoneInstance:ZoneInstance) => { + if(zoneInstance.instanceData.uniqueId === instanceData.uniqueId){ + zoneInstance.updateInstanceData(instanceData); + } + }); }); } - public addInstanceToZone(zone:ZoneConfig, instance:PolicyInstance){ - zone.instances.push(new ZoneInstanceConfig(instance)); + public updateTargetsOrMembersOnCanvasDelete = (canvasNodeID:string, zones:Array<Zone>, type:ZoneInstanceAssignmentType):void => { + _.forEach(zones, (zone) => { + _.forEach(zone.instances, (zoneInstance:ZoneInstance) => { + if (zoneInstance.isAlreadyAssigned(canvasNodeID)) { + zoneInstance.addOrRemoveAssignment(canvasNodeID, type); + //remove it from our list of BE targets and members as well (so that it will not be sent in future calls to BE). + zoneInstance.instanceData.setSavedAssignments(zoneInstance.assignments); + } + }); + }); + }; + + public createZoneInstanceFromLeftPalette = (zoneType:ZoneInstanceType, component:Component, paletteComponentType:string):Observable<ZoneInstance> => { + if (zoneType === ZoneInstanceType.POLICY) { + return this.policiesService.createPolicyInstance(component.componentType, component.uniqueId, paletteComponentType).map(response => { + let newInstance = new PolicyInstance(response); + component.policies.push(newInstance); + return new ZoneInstance(newInstance, component); + }); + } else if (zoneType === ZoneInstanceType.GROUP) { + return this.groupsService.createGroupInstance(component.componentType, component.uniqueId, paletteComponentType).map(response => { + let newInstance = new GroupInstance(response); + component.groupInstances.push(newInstance); + return new ZoneInstance(newInstance, component); + }); + } + } + + public addInstanceToZone(zone:Zone, instance:ZoneInstance, hide?:boolean) { + if(hide){ + instance.hidden = true; + } + zone.instances.push(instance); + }; - private findZoneCoordinates(zoneType):Point{ - let point:Point = new Point(0,0); + private findZoneCoordinates(zoneType):Point { + let point:Point = new Point(0, 0); let zone = angular.element(document.querySelector('.' + zoneType + '-zone')); - let wrapperZone = zone.offsetParent(); - point.x = zone.prop('offsetLeft') + wrapperZone.prop('offsetLeft'); - point.y = zone.prop('offsetTop') + wrapperZone.prop('offsetTop'); + let wrapperZone = zone.offsetParent(); + point.x = zone.prop('offsetLeft') + wrapperZone.prop('offsetLeft'); + point.y = zone.prop('offsetTop') + wrapperZone.prop('offsetTop'); return point; } - public showAnimationToZone = (startPoint:Point, zoneType:string) => { - + public createPaletteToZoneAnimation = (startPoint:Point, zoneType:ZoneInstanceType, newInstance:ZoneInstance) => { + let zoneTypeName = ZoneInstanceType[zoneType].toLowerCase(); let paletteToZoneAnimation = this.dynamicComponentService.createDynamicComponent(PaletteAnimationComponent); paletteToZoneAnimation.instance.from = startPoint; - paletteToZoneAnimation.instance.to = this.findZoneCoordinates(zoneType); - paletteToZoneAnimation.instance.iconName = zoneType; + paletteToZoneAnimation.instance.type = zoneType; + paletteToZoneAnimation.instance.to = this.findZoneCoordinates(zoneTypeName); + paletteToZoneAnimation.instance.zoneInstance = newInstance; + paletteToZoneAnimation.instance.iconName = zoneTypeName; paletteToZoneAnimation.instance.runAnimation(); } - + public startCyTagMode = (cy:Cy.Instance) => { + cy.autolock(true); + cy.nodes().unselectify(); + cy.emit('tagstart'); //dont need to show handles because they're already visible bcz of hover event + + }; + + public endCyTagMode = (cy:Cy.Instance) => { + cy.emit('tagend'); + cy.nodes().selectify(); + cy.autolock(false); + }; + + public handleTagClick = (cy:Cy.Instance, zoneInstance:ZoneInstance, nodeId:string) => { + zoneInstance.addOrRemoveAssignment(nodeId, ZoneInstanceAssignmentType.COMPONENT_INSTANCES); + this.showZoneTagIndicationForNode(nodeId, zoneInstance, cy); + }; + + public showGroupZoneIndications = (groupInstances:Array<ZoneInstance>, policyInstance:ZoneInstance) => { + groupInstances.forEach((groupInstance:ZoneInstance)=> { + let handle:string = this.getCorrectHandleForNode(groupInstance.instanceData.uniqueId, policyInstance); + groupInstance.showHandle(handle); + }) + }; + + public hideGroupZoneIndications = (instances:Array<ZoneInstance>) => { + instances.forEach((instance) => { + instance.hideHandle(); + }) + } + + public showZoneTagIndications = (cy:Cy.Instance, zoneInstance:ZoneInstance) => { + + cy.nodes().forEach(node => { + let handleType:string = this.getCorrectHandleForNode(node.id(), zoneInstance); + cy.emit('showhandle', [node, handleType]); + }); + }; + + public showZoneTagIndicationForNode = (nodeId:string, zoneInstance:ZoneInstance, cy:Cy.Instance) => { + let node = cy.getElementById(nodeId); + let handleType:string = this.getCorrectHandleForNode(nodeId, zoneInstance); + cy.emit('showhandle', [node, handleType]); + } + + public hideZoneTagIndications = (cy:Cy.Instance) => { + cy.emit('hidehandles'); + }; + + public getCorrectHandleForNode = (nodeId:string, zoneInstance:ZoneInstance):string => { + if (zoneInstance.isAlreadyAssigned(nodeId)) { + if (zoneInstance.type == ZoneInstanceType.POLICY) { + return CanvasHandleTypes.TAGGED_POLICY; + } else { + return CanvasHandleTypes.TAGGED_GROUP; + } + } else { + return CanvasHandleTypes.TAG_AVAILABLE; + } + }; } CompositionGraphZoneUtils.$inject = [ - 'DynamicComponentService' + 'DynamicComponentService', + 'PoliciesServiceNg2', + 'GroupsServiceNg2' ];
\ No newline at end of file diff --git a/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/match-capability-requierment-utils.ts b/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/match-capability-requierment-utils.ts index 3a05ce901f..eac907a9b2 100644 --- a/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/match-capability-requierment-utils.ts +++ b/catalog-ui/src/app/directives/graphs-v2/composition-graph/utils/match-capability-requierment-utils.ts @@ -74,19 +74,25 @@ export class MatchCapabilitiesRequirementsUtils { } private static isRequirementFulfilled(fromNodeId:string, requirement:any, links:Array<CompositionCiLinkBase>):boolean { - return _.some(links, { + if(requirement.maxOccurrences === 'UNBOUNDED'){ + return false; + } + let linksWithThisReq:Array<CompositionCiLinkBase> = _.filter(links, { 'relation': { 'fromNode': fromNodeId, 'relationships': [{ - 'requirementOwnerId': requirement.ownerId, - 'requirement': requirement.name, - 'relationship': { - 'type': requirement.relationship + 'relation':{ + 'requirementOwnerId': requirement.ownerId, + 'requirement': requirement.name, + 'relationship': { + 'type': requirement.capability + } + } - } - ] + }] } }); + return linksWithThisReq.length == requirement.maxOccurrences; }; private static isMatch(requirement:Requirement, capability:Capability):boolean { diff --git a/catalog-ui/src/app/directives/graphs-v2/deployment-graph/deployment-graph.directive.ts b/catalog-ui/src/app/directives/graphs-v2/deployment-graph/deployment-graph.directive.ts index c542e9fc95..f335ea02d9 100644 --- a/catalog-ui/src/app/directives/graphs-v2/deployment-graph/deployment-graph.directive.ts +++ b/catalog-ui/src/app/directives/graphs-v2/deployment-graph/deployment-graph.directive.ts @@ -54,7 +54,7 @@ export class DeploymentGraph implements ng.IDirective { link = (scope: IDeploymentGraphScope, el: JQuery) => { if (scope.component.isResource()) { - if (scope.component.componentInstances && scope.component.componentInstancesRelations && scope.component.groups) { + if (scope.component.componentInstances && scope.component.componentInstancesRelations && scope.component.modules) { this.loadGraph(scope, el); } else { this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_DEPLOYMENT_GRAPH_DATA_LOADED, () => { @@ -65,8 +65,8 @@ export class DeploymentGraph implements ng.IDirective { }; public initGraphNodes = (cy: Cy.Instance, component: Component): void => { - if (component.groups) { // Init module nodes - _.each(component.groups, (groupModule: Module) => { + if (component.modules) { // Init module nodes + _.each(component.modules, (groupModule: Module) => { let moduleNode = this.NodesFactory.createModuleNode(groupModule); this.commonGraphUtils.addNodeToGraph(cy, moduleNode); @@ -74,7 +74,7 @@ export class DeploymentGraph implements ng.IDirective { } _.each(component.componentInstances, (instance: ComponentInstance) => { // Init component instance nodes let componentInstanceNode = this.NodesFactory.createNode(instance); - componentInstanceNode.parent = this.deploymentGraphGeneralUtils.findInstanceModule(component.groups, instance.uniqueId); + componentInstanceNode.parent = this.deploymentGraphGeneralUtils.findInstanceModule(component.modules, instance.uniqueId); if (componentInstanceNode.parent) { // we are not drawing instances that are not a part of a module this.commonGraphUtils.addComponentInstanceNodeToGraph(cy, componentInstanceNode); } diff --git a/catalog-ui/src/app/directives/graphs-v2/deployment-graph/deployment-utils/deployment-graph-general-utils.ts b/catalog-ui/src/app/directives/graphs-v2/deployment-graph/deployment-utils/deployment-graph-general-utils.ts index 3a90115179..ebd1f5b205 100644 --- a/catalog-ui/src/app/directives/graphs-v2/deployment-graph/deployment-utils/deployment-graph-general-utils.ts +++ b/catalog-ui/src/app/directives/graphs-v2/deployment-graph/deployment-utils/deployment-graph-general-utils.ts @@ -32,7 +32,7 @@ export class DeploymentGraphGeneralUtils { public findInstanceModule = (groupsArray:Array<Module>, componentInstanceId:string):string => { let parentGroup:Module = _.find(groupsArray, (group:Module) => { - return _.find(group.members, (member) => { + return _.find((<any>Object).values(group.members), (member: string) => { return member === componentInstanceId; }); }); diff --git a/catalog-ui/src/app/directives/graphs-v2/image-creator/image-creator.service.ts b/catalog-ui/src/app/directives/graphs-v2/image-creator/image-creator.service.ts index 6d6291d900..68c9e9a459 100644 --- a/catalog-ui/src/app/directives/graphs-v2/image-creator/image-creator.service.ts +++ b/catalog-ui/src/app/directives/graphs-v2/image-creator/image-creator.service.ts @@ -18,6 +18,14 @@ * ============LICENSE_END========================================================= */ +export interface ICanvasImage { + src: string; + width: number + height: number; + x: number; + y: number; +} + 'use strict'; export class ImageCreatorService { static '$inject' = ['$q']; @@ -31,36 +39,48 @@ export class ImageCreatorService { body.appendChild(this._canvas); } - getImageBase64(imageBaseUri:string, imageLayerUri:string, nodeWidth:number, canvasWidth:number, handleSize:number):ng.IPromise<string> { - let deferred = this.$q.defer(); - let imageBase = new Image(); - let imageLayer = new Image(); + /** + * Create an image composed of different image layers + * @param canvasImages + * @param canvasWidth + * @param canvasHeight + * returns a PROMISE + */ + getMultiLayerBase64Image(canvasImages: ICanvasImage[], canvasWidth?:number, canvasHeight?:number):ng.IPromise<string> { + const deferred = this.$q.defer<string>(); + + if(canvasImages && canvasImages.length === 0){ + return null; + } + + //If only width was set, use it for height, otherwise use first canvasImage height + canvasHeight = canvasHeight || canvasImages[0].height; + canvasWidth = canvasWidth || canvasImages[0].width; + + const images = []; let imagesLoaded = 0; - let onImageLoaded = () => { + const onImageLoaded = () => { imagesLoaded++; - - if (imagesLoaded < 2) { + if(imagesLoaded < canvasImages.length){ return; } this._canvas.setAttribute('width', canvasWidth.toString()); - this._canvas.setAttribute('height', canvasWidth.toString()); - - let canvasCtx = this._canvas.getContext('2d'); + this._canvas.setAttribute('height', canvasHeight.toString()); + const canvasCtx = this._canvas.getContext('2d'); canvasCtx.clearRect(0, 0, this._canvas.width, this._canvas.height); - - //Note: params below are: image, x to start drawing at, y to start drawing at, num of x pixels to draw, num of y pixels to draw - canvasCtx.drawImage(imageBase, 0, canvasWidth - nodeWidth, nodeWidth, nodeWidth); //Draw the node: When nodeWidth == canvasWidth, we'll start at point 0,0. Otherwise, x starts at 0 (but will end before end of canvas) and y starts low enough that node img ends at bottom of canvas. - canvasCtx.drawImage(imageLayer, canvasWidth - handleSize, 0, handleSize, handleSize); //Draw the icon: icon should be drawn in top right corner - + images.forEach((image, index) => { + const canvasImage = canvasImages[index]; + canvasCtx.drawImage(image, canvasImage.x, canvasImage.y, canvasImage.width, canvasImage.height); + }); let base64Image = this._canvas.toDataURL(); deferred.resolve(base64Image); }; - - imageBase.onload = onImageLoaded; - imageLayer.onload = onImageLoaded; - imageBase.src = imageBaseUri; - imageLayer.src = imageLayerUri; - + canvasImages.forEach(canvasImage => { + let image = new Image(); + image.onload = onImageLoaded; + image.src = canvasImage.src; + images.push(image); + }); return deferred.promise; } } diff --git a/catalog-ui/src/app/directives/graphs-v2/palette/palette.directive.ts b/catalog-ui/src/app/directives/graphs-v2/palette/palette.directive.ts index 9b9235248e..ebc52c241b 100644 --- a/catalog-ui/src/app/directives/graphs-v2/palette/palette.directive.ts +++ b/catalog-ui/src/app/directives/graphs-v2/palette/palette.directive.ts @@ -27,9 +27,10 @@ import {LeftPaletteLoaderService} from "../../../services/components/utils/compo import {Resource} from "app/models/components/resource"; import {ComponentType} from "app/utils/constants"; import {LeftPaletteMetadataTypes} from "../../../models/components/displayComponent"; +import { IDirectiveLinkFn, IScope } from "angular"; -interface IPaletteScope { +interface IPaletteScope extends IScope{ components:Array<LeftPaletteComponent>; currentComponent:Component; model:any; @@ -88,7 +89,8 @@ export class Palette implements ng.IDirective { restrict = 'E'; template = require('./palette.html'); - link = (scope:IPaletteScope, el:JQuery) => { + link:IDirectiveLinkFn = (scope:IPaletteScope, el:JQuery) => { + this.LeftPaletteLoaderService.loadLeftPanel(scope.currentComponent); this.nodeHtmlSubstitute = $('<div class="node-substitute"><span></span><img /></div>'); el.append(this.nodeHtmlSubstitute); this.registerEventListenerForLeftPalette(scope); @@ -277,7 +279,7 @@ export class Palette implements ng.IDirective { let filteredResources = []; angular.forEach(subcategory, function (component:LeftPaletteComponent) { - let resourceFilterTerm:string = component.searchFilterTerms; + let resourceFilterTerm:string = component.searchFilterTerms.toLowerCase(); if (resourceFilterTerm.indexOf(searchText.toLowerCase()) >= 0) { filteredResources.push(component); } diff --git a/catalog-ui/src/app/directives/graphs-v2/palette/palette.html b/catalog-ui/src/app/directives/graphs-v2/palette/palette.html index a8139e3140..ee0c604ea9 100644 --- a/catalog-ui/src/app/directives/graphs-v2/palette/palette.html +++ b/catalog-ui/src/app/directives/graphs-v2/palette/palette.html @@ -26,7 +26,7 @@ data-ng-class="{'default-pointer': isViewOnly}" data-ng-mouseover="!isViewOnly && onMouseOver(component, $event.currentTarget)" data-ng-mouseleave="!isViewOnly && onMouseOut(component)" - data-drag="!isViewOnly" + data-drag="!isViewOnly && component.isDraggable" data-jqyoui-options="{revert: 'invalid', helper:setElementTemplate, appendTo:'body', cursorAt: {left:38, top: 38}, cursor:'move'}" jqyoui-draggable="{index:{{$index}},animate:true,onStart:'dragStartCallback(component)',onStop:'dragStopCallback()', onDrag:'onDragCallback()'}" data-ng-repeat="component in components | orderBy: 'displayName' track by $index" diff --git a/catalog-ui/src/app/directives/graphs-v2/relation-menu/relation-menu.html b/catalog-ui/src/app/directives/graphs-v2/relation-menu/relation-menu.html deleted file mode 100644 index e1cdf499a0..0000000000 --- a/catalog-ui/src/app/directives/graphs-v2/relation-menu/relation-menu.html +++ /dev/null @@ -1,63 +0,0 @@ -<div class="link-menu-open" data-tests-id="link-menu-open" data-ng-show="isLinkMenuOpen" ng-style="{left: connectRelationModel.menuPosition.x, top: connectRelationModel.menuPosition.y}" clicked-outside="{onClickedOutside: 'hideRelationMatch()', clickedOutsideEnable: 'isLinkMenuOpen'}" > - <h4 sdc-smart-tooltip>{{relationMenuDirectiveObj.leftSideLink.componentInstance.name | resourceName}}</h4> - <h4 sdc-smart-tooltip>{{relationMenuDirectiveObj.rightSideLink.componentInstance.name | resourceName}}</h4> - - <p>Select one of the options below to connect</p> - - <perfect-scrollbar scroll-y-margin-offset="0" include-padding="true" class="scrollbar-container"> - <div class="inner-title" data-ng-show="hasMatchesToShow(connectRelationModel.leftSideLink.requirements, connectRelationModel.rightSideLink.selectedMatch)">Requirements</div> - <div class="link-item" data-tests-id="link-item-requirements" data-ng-repeat="(req ,matchArr) in connectRelationModel.leftSideLink.requirements" - data-ng-click="connectRelationModel.leftSideLink.selectMatchArr(matchArr); updateSelectionText()" - data-ng-show="showMatch(connectRelationModel.rightSideLink.selectedMatch, matchArr)" - data-ng-class="{ 'selected': connectRelationModel.leftSideLink.selectedMatch === matchArr}"> - <div sdc-smart-tooltip>{{matchArr[0].requirement.getFullTitle()}}</div> - </div> - - <div class="inner-title" data-ng-show="hasMatchesToShow(connectRelationModel.leftSideLink.capabilities, connectRelationModel.rightSideLink.selectedMatch)">Capabilities</div> - <div class="link-item" data-tests-id="link-item-capabilities" data-ng-repeat="(cap, matchArr) in connectRelationModel.leftSideLink.capabilities" - data-ng-click="connectRelationModel.leftSideLink.selectMatchArr(matchArr); updateSelectionText()" - data-ng-show="showMatch(connectRelationModel.rightSideLink.selectedMatch, matchArr)" - data-ng-class="{ 'selected': connectRelationModel.leftSideLink.selectedMatch === matchArr}"> - <div sdc-smart-tooltip>{{matchArr[0].capability.getFullTitle()}}</div> - </div> - </perfect-scrollbar> - - <perfect-scrollbar scroll-y-margin-offset="0" include-padding="true" class="scrollbar-container"> - <div class="inner-title" data-ng-show="hasMatchesToShow(connectRelationModel.rightSideLink.requirements, connectRelationModel.leftSideLink.selectedMatch)">Requirements</div> - <div class="link-item" data-tests-id="link-item-requirements" data-ng-repeat="(req, matchArr) in connectRelationModel.rightSideLink.requirements" - data-ng-click="connectRelationModel.rightSideLink.selectMatchArr(matchArr); updateSelectionText()" - data-ng-show="showMatch(connectRelationModel.leftSideLink.selectedMatch, matchArr)" - data-ng-class="{ 'selected': connectRelationModel.rightSideLink.selectedMatch === matchArr}"> - <div sdc-smart-tooltip>{{matchArr[0].secondRequirement ? matchArr[0].secondRequirement.getFullTitle() : matchArr[0].requirement.getFullTitle()}}</div> - </div> - - <div class="inner-title" data-ng-show="hasMatchesToShow(connectRelationModel.rightSideLink.capabilities, connectRelationModel.leftSideLink.selectedMatch)">Capabilities</div> - <div class="link-item" data-tests-id="link-item-capabilities" data-ng-repeat="(cap, matchArr) in connectRelationModel.rightSideLink.capabilities" - data-ng-click="connectRelationModel.rightSideLink.selectMatchArr(matchArr); updateSelectionText()" - data-ng-show="showMatch(connectRelationModel.leftSideLink.selectedMatch, matchArr)" - data-ng-class="{ 'selected': connectRelationModel.rightSideLink.selectedMatch === matchArr}"> - <div sdc-smart-tooltip>{{matchArr[0].capability.getFullTitle()}}</div> - </div> - </perfect-scrollbar> - - <div class="vl-type" data-ng-class="{'disabled': !connectRelationModel.leftSideLink.selectedMatch[0].secondRequirement || !connectRelationModel.rightSideLink.selectedMatch[0].secondRequirement}"> - <sdc-radio-button sdc-model="relationMenuDirectiveObj.vlType" value="ptp" - disabled="!relationMenuDirectiveObj.leftSideLink.selectedMatch[0].secondRequirement || !relationMenuDirectiveObj.rightSideLink.selectedMatch[0].secondRequirement || !relationMenuDirectiveObj.p2pVL" - text="Point to point" elem-id="radioPTP" elem-name="vlType"></sdc-radio-button> - - <sdc-radio-button sdc-model="relationMenuDirectiveObj.vlType" value="mptmp" - disabled="!relationMenuDirectiveObj.leftSideLink.selectedMatch[0].secondRequirement || !relationMenuDirectiveObj.rightSideLink.selectedMatch[0].secondRequirement || !relationMenuDirectiveObj.mp2mpVL" - text="Multi point" elem-id="radioMPTMP" elem-name="vlType"></sdc-radio-button> - - <span class="sprite-new info-icon" tooltips tooltip-content="You are required to choose the type of the Virtual Link."></span> - </div> - - <div class="result" sdc-smart-tooltip>​{{relationMenuDirectiveObj.selectionText}} - - </div> - - <button class="tlv-btn grey" data-tests-id="link-menu-button-cancel" data-ng-click="hideRelationMatch()">Cancel</button> - <button class="tlv-btn blue" data-tests-id="link-menu-button-connect" data-ng-disabled="!connectRelationModel.leftSideLink.selectedMatch || !connectRelationModel.rightSideLink.selectedMatch || - (connectRelationModel.leftSideLink.selectedMatch[0].secondRequirement && !connectRelationModel.vlType)" - data-ng-click="saveRelation()">Connect</button> -</div> diff --git a/catalog-ui/src/app/directives/graphs-v2/relation-menu/relation-menu.less b/catalog-ui/src/app/directives/graphs-v2/relation-menu/relation-menu.less deleted file mode 100644 index dea814dbec..0000000000 --- a/catalog-ui/src/app/directives/graphs-v2/relation-menu/relation-menu.less +++ /dev/null @@ -1,118 +0,0 @@ -.link-menu-open { - display: block !important; - color: @main_color_m; - font-size: 14px; - position: absolute; - z-index: 99999; - border-radius: 2px; - background-color: #ffffff; - box-shadow: 0px 0px 6px 0px rgba(0, 0, 0, 0.5); - width: 460px; - height: 418px; - - h4 { - width: 50%; - float: left; - background-color: @tlv_color_u; - font-size: 14px; - font-weight: bold; - line-height: 36px; - margin: 0; - padding: 0 15px; - - & + h4 { - border-left: #d8d8d8 1px solid; - } - } - p { - clear: both; - text-indent: 15px; - border-bottom: #d8d8d8 1px solid; - line-height: 34px; - margin: 0; - color: @func_color_s; - } - - .scrollbar-container { - height: 232px; - width: 50%; - float: left; - margin-bottom: 5px; - .perfect-scrollbar; - - & + .scrollbar-container { - border-left: #d8d8d8 1px solid; - } - - .inner-title { - width: 189px; - margin: 5px auto 3px auto; - //text-indent: 10px; - color: @func_color_s; - text-transform: uppercase; - font-weight: bold; - - //&:not(:first-child) { - // margin-top: 10px; - //} - } - - .link-item { - padding: 0 10px; - line-height: 23px; - height: 23px; - text-indent: 5px; - .hand; - - &.selected { - background-color: @tlv_color_v; - } - } - } - - .vl-type { - height: 33px; - border-top: #d8d8d8 solid 1px; - clear: both; - padding: 0 10px; - line-height: 32px; - color: @main_color_m; - - &.disabled { - background-color: #f2f2f2; - color: @color_m; - } - .info-icon { - float:right; - margin-top: 9px; - } - .tlv-radio { - margin-right: 10px; - } - } - - .result { - background-color: @main_color_m; - line-height: 29px; - color: #ffffff; - padding: 0 15px; - } - - button { - float: right; - margin-top: 9px; - margin-right: 10px; - } -} -.link-menu-item { - cursor: pointer; - line-height: 24px; - padding: 0 10px; - &:hover { - color: @color_a; - } -} -.link-menu::before { - right: inherit !important; - left: 50px; -}
\ No newline at end of file diff --git a/catalog-ui/src/app/directives/graphs-v2/relation-menu/relation-menu.ts b/catalog-ui/src/app/directives/graphs-v2/relation-menu/relation-menu.ts deleted file mode 100644 index 78a269ead1..0000000000 --- a/catalog-ui/src/app/directives/graphs-v2/relation-menu/relation-menu.ts +++ /dev/null @@ -1,104 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * SDC - * ================================================================================ - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ -'use strict' -import * as _ from "lodash"; -import {Match, ConnectRelationModel} from "app/models"; -import {Component} from "../../../models/components/component"; - -export interface IRelationMenuScope extends ng.IScope { - relationMenuDirectiveObj:ConnectRelationModel; - createRelation:Function; - isLinkMenuOpen:boolean; - hideRelationMatch:Function; - cancel:Function; - - saveRelation(); - showMatch(arr1:Array<Match>, arr2:Array<Match>):boolean; - hasMatchesToShow(matchesObj:Match, selectedMatch:Array<Match>); - updateSelectionText():void; - -} - - -export class RelationMenuDirective implements ng.IDirective { - - constructor(private $filter:ng.IFilterService) { - } - - scope = { - relationMenuDirectiveObj: '=', - isLinkMenuOpen: '=', - createRelation: '&', - cancel: '&' - }; - - restrict = 'E'; - replace = true; - template = ():string => { - return require('./relation-menu.html'); - }; - - link = (scope:IRelationMenuScope, element:JQuery, $attr:ng.IAttributes) => { - - scope.saveRelation = ():void=> { - let chosenMatches:Array<any> = _.intersection(scope.relationMenuDirectiveObj.rightSideLink.selectedMatch, scope.relationMenuDirectiveObj.leftSideLink.selectedMatch); - let chosenMatch:Match = chosenMatches[0]; - scope.createRelation()(chosenMatch); - }; - - - scope.hideRelationMatch = () => { - scope.isLinkMenuOpen = false; - scope.cancel(); - }; - - //to show options in link menu - scope.showMatch = (arr1:Array<Match>, arr2:Array<Match>):boolean => { - return !arr1 || !arr2 || _.intersection(arr1, arr2).length > 0; - }; - - //to show requirements/capabilities title - scope.hasMatchesToShow = (matchesObj:Match, selectedMatch:Array<Match>):boolean => { - let result:boolean = false; - _.forEach(matchesObj, (matchesArr:Array<Match>) => { - if (!result) { - result = scope.showMatch(matchesArr, selectedMatch); - } - }); - return result; - }; - - - scope.updateSelectionText = ():void => { - let left:string = scope.relationMenuDirectiveObj.leftSideLink.selectedMatch ? this.$filter('resourceName')(scope.relationMenuDirectiveObj.leftSideLink.selectedMatch[0].getDisplayText('left')) : ''; - let both:string = scope.relationMenuDirectiveObj.leftSideLink.selectedMatch && scope.relationMenuDirectiveObj.rightSideLink.selectedMatch ? ' - ' + - this.$filter('resourceName')(scope.relationMenuDirectiveObj.leftSideLink.selectedMatch[0].requirement.relationship) + ' - ' : ''; - let right:string = scope.relationMenuDirectiveObj.rightSideLink.selectedMatch ? this.$filter('resourceName')(scope.relationMenuDirectiveObj.rightSideLink.selectedMatch[0].getDisplayText('right')) : ''; - scope.relationMenuDirectiveObj.selectionText = left + both + right; - }; - - - } - public static factory = ($filter:ng.IFilterService)=> { - return new RelationMenuDirective($filter); - }; -} - -RelationMenuDirective.factory.$inject = ['$filter']; diff --git a/catalog-ui/src/app/directives/inputs-and-properties/inputs/input-row-view.html b/catalog-ui/src/app/directives/inputs-and-properties/inputs/input-row-view.html index 872a26bc27..32059c41fd 100644 --- a/catalog-ui/src/app/directives/inputs-and-properties/inputs/input-row-view.html +++ b/catalog-ui/src/app/directives/inputs-and-properties/inputs/input-row-view.html @@ -24,14 +24,14 @@ <span tooltips tooltip-content="{{input.type}}" data-tests-id="inputType_{{input.name}}">{{input.type}} </span> </div> </div> - <sdc-checkbox ng-if="instanceInputsMap" + <ng1-checkbox ng-if="instanceInputsMap" class="input-check-box" disabled="input.isAlreadySelected || isViewOnly" sdc-checklist-model="instanceInputsMap[instanceId]" sdc-checklist-value="input" sdc-checklist-change="onCheckboxClicked()" data-tests-id="inputsCheckbox_{{input.name}}" - data-ng-click=" $event.stopPropagation()"></sdc-checkbox> + data-ng-click=" $event.stopPropagation()"></ng1-checkbox> <div class="delete" ng-if="showDeleteIcon"> <span class="sprite-new delete-icon remove-input-icon" diff --git a/catalog-ui/src/app/directives/inputs-and-properties/properties/property-row-view.html b/catalog-ui/src/app/directives/inputs-and-properties/properties/property-row-view.html index ff82a8b685..95de0c4bfd 100644 --- a/catalog-ui/src/app/directives/inputs-and-properties/properties/property-row-view.html +++ b/catalog-ui/src/app/directives/inputs-and-properties/properties/property-row-view.html @@ -15,12 +15,12 @@ <span tooltips tooltip-content="{{property.schema.property.type}}" data-tests-id="propertySchema">{{property.schema.property.type}} </span> </div> </div> - <sdc-checkbox ng-if="instancePropertiesMap" + <ng1-checkbox ng-if="instancePropertiesMap" class="property-check-box" disabled="property.isAlreadySelected || isViewOnly" sdc-checklist-model="instancePropertiesMap[instanceId]" sdc-checklist-value="property" sdc-checklist-change="onCheckboxClicked()" data-tests-id="propertyCheckbox_{{property.name}}" - data-ng-click=" $event.stopPropagation()"></sdc-checkbox> + data-ng-click=" $event.stopPropagation()"></ng1-checkbox> </div> diff --git a/catalog-ui/src/app/directives/loader/loader-directive.ts b/catalog-ui/src/app/directives/loader/loader-directive.ts index 7e056c774f..cb17c0b1b9 100644 --- a/catalog-ui/src/app/directives/loader/loader-directive.ts +++ b/catalog-ui/src/app/directives/loader/loader-directive.ts @@ -126,11 +126,13 @@ export class LoaderDirective implements ng.IDirective { scope.$watch("display", (newVal, oldVal) => { element.css('display', 'none'); + let timeout; if (newVal === true) { - window.setTimeout(():void => { + timeout = window.setTimeout(():void => { element.css('display', 'block'); }, 500); } else { + window.clearTimeout(timeout); window.setTimeout(():void => { element.css('display', 'none'); }, 0); diff --git a/catalog-ui/src/app/directives/prevent-double-click/prevent-double-click.ts b/catalog-ui/src/app/directives/prevent-double-click/prevent-double-click.ts new file mode 100644 index 0000000000..fff25c4d9c --- /dev/null +++ b/catalog-ui/src/app/directives/prevent-double-click/prevent-double-click.ts @@ -0,0 +1,41 @@ +/** + * Created by ob0695 on 5/15/2018. + */ +'use strict'; + +export class PreventDoubleClickDirective implements ng.IDirective { + + constructor(private $timeout:ng.ITimeoutService) { + } + + restrict:'A'; + + link = (scope, elem) => { + + let delay = 600; + let disabled = false; + + scope.onClick = (evt) => { + if (disabled) { + evt.preventDefault(); + evt.stopImmediatePropagation(); + } else { + disabled = true; + this.$timeout(function () { + disabled = false; + }, delay, false); + } + } + + scope.$on('$destroy', function () { + elem.off('click', scope.onClick); + }); + elem.on('click', scope.onClick); + }; + + public static factory = ($timeout:ng.ITimeoutService) => { + return new PreventDoubleClickDirective($timeout); + } +} + +PreventDoubleClickDirective.factory.$inject = ['$timeout'];
\ No newline at end of file diff --git a/catalog-ui/src/app/filters.ts b/catalog-ui/src/app/filters.ts index 4ccf3bc6ad..10194b5369 100644 --- a/catalog-ui/src/app/filters.ts +++ b/catalog-ui/src/app/filters.ts @@ -21,7 +21,6 @@ /** * Created by ob0695 on 2/26/2017. */ -export * from './filters/catalog-status-filter'; export * from './filters/category-type-filter'; export * from './filters/clear-whitespaces-filter'; export * from './filters/entity-filter'; diff --git a/catalog-ui/src/app/filters/resource-type-filter.ts b/catalog-ui/src/app/filters/resource-type-filter.ts index 70abf81f8e..51bf071b41 100644 --- a/catalog-ui/src/app/filters/resource-type-filter.ts +++ b/catalog-ui/src/app/filters/resource-type-filter.ts @@ -27,7 +27,7 @@ export class ResourceTypeFilter { let filter = <ResourceTypeFilter>(resourceType:string) => { let uiConfiguration:any = cacheService.get('UIConfiguration'); - if (uiConfiguration.resourceTypes && uiConfiguration.resourceTypes[resourceType]) { + if (uiConfiguration && uiConfiguration.resourceTypes && uiConfiguration.resourceTypes[resourceType]) { return uiConfiguration.resourceTypes[resourceType]; } return resourceType; diff --git a/catalog-ui/src/app/models.ts b/catalog-ui/src/app/models.ts index 3a48335c22..e5cc483b63 100644 --- a/catalog-ui/src/app/models.ts +++ b/catalog-ui/src/app/models.ts @@ -42,6 +42,8 @@ export * from './models/componentsInstances/componentInstance'; export * from './models/componentsInstances/resourceInstance'; export * from './models/componentsInstances/serviceInstance'; export * from './models/componentsInstances/serviceProxyInstance'; +export * from './models/graph/zones/group-instance'; +export * from './models/graph/zones/policy-instance'; export * from './models/csar-component'; //export * from './models/data-type-properties'; export * from './models/properties-inputs/property-be-model'; diff --git a/catalog-ui/src/app/models/app-config.ts b/catalog-ui/src/app/models/app-config.ts index 54c059afb3..a0ebb54638 100644 --- a/catalog-ui/src/app/models/app-config.ts +++ b/catalog-ui/src/app/models/app-config.ts @@ -128,8 +128,7 @@ export interface IConfigRoles { } export interface IConfigRole { - pages:Array<string>; - states:IConfigState; + changeLifecycleStateButtons:any; } export interface IConfigState { @@ -222,6 +221,11 @@ export interface ITester { email:string; } +export interface IComponentType { + RESOURCE:any; + SERVICE:any; +} + export interface IAppMenu { roles:IConfigRoles; confirmationMessages:IConfirmationMessages; diff --git a/catalog-ui/src/app/models/catalogSelector.ts b/catalog-ui/src/app/models/catalogSelector.ts new file mode 100644 index 0000000000..b3a7aa353a --- /dev/null +++ b/catalog-ui/src/app/models/catalogSelector.ts @@ -0,0 +1,14 @@ +/* added Michael */ +// export interface ILeftSwitchItemModel { +export interface ICatalogSelector{ + value: CatalogSelectorTypes; + title: string; + header: string; + hidden?: number; + disabled?: number; +} + +export enum CatalogSelectorTypes { + Active, + Archive, +}
\ No newline at end of file diff --git a/catalog-ui/src/app/models/category.ts b/catalog-ui/src/app/models/category.ts index e45100aecc..0d5c63b5c1 100644 --- a/catalog-ui/src/app/models/category.ts +++ b/catalog-ui/src/app/models/category.ts @@ -22,8 +22,7 @@ -export class ICategoryBase { - +export interface ICategoryBase { //server properties name:string; normalizedName:string; @@ -34,32 +33,13 @@ export class ICategoryBase { filterTerms:string; isDisabled:boolean; filteredGroup:Array<IGroup>; - - constructor(category?:ICategoryBase) { - if (category) { - this.name = category.name; - this.normalizedName = category.normalizedName; - this.icons = category.icons; - this.filterTerms = category.filterTerms; - this.isDisabled = category.isDisabled; - this.filteredGroup = category.filteredGroup; - } - } } -export class IMainCategory extends ICategoryBase { +export interface IMainCategory extends ICategoryBase { subcategories:Array<ISubCategory>; - - constructor(); - constructor(category?:IMainCategory) { - super(category); - if (category) { - this.subcategories = category.subcategories; - } - } } -export class ISubCategory extends ICategoryBase { +export interface ISubCategory extends ICategoryBase { groupings:Array<ICategoryBase>; } diff --git a/catalog-ui/src/app/models/component-metadata.ts b/catalog-ui/src/app/models/component-metadata.ts index 1545739ce3..9f5e22cce4 100644 --- a/catalog-ui/src/app/models/component-metadata.ts +++ b/catalog-ui/src/app/models/component-metadata.ts @@ -47,6 +47,8 @@ export class ComponentMetadata { public highestVersion:boolean; public normalizedName:string; public systemName:string; + public archived:boolean; + public vspArchived: boolean; //Resource only public resourceType: string; @@ -66,9 +68,11 @@ export class ComponentMetadata { public serviceType:string; public serviceRole:string; public environmentContext:string; + public instantiationType:string; - //backend lifecycleState + + //backend lifecycleState public state:string; deserialize (response): ComponentMetadata { @@ -111,6 +115,9 @@ export class ComponentMetadata { this.serviceType = response.serviceType; this.serviceRole = response.serviceRole; this.environmentContext = response.environmentContext; + this.archived = response.archived; + this.instantiationType = response.instantiationType; + this.vspArchived = response.vspArchived; return this; } diff --git a/catalog-ui/src/app/models/components/component.ts b/catalog-ui/src/app/models/components/component.ts index adcf498342..8f0fa33c42 100644 --- a/catalog-ui/src/app/models/components/component.ts +++ b/catalog-ui/src/app/models/components/component.ts @@ -34,6 +34,7 @@ import {Capability} from "../capability"; import {Requirement} from "../requirement"; import {Relationship} from "../graph/relationship"; import { PolicyInstance } from "app/models/graph/zones/policy-instance"; +import { GroupInstance } from "../graph/zones/group-instance"; // import {} @@ -96,8 +97,12 @@ export interface IComponent { getModuleForDisplay(moduleId:string):ng.IPromise<DisplayModule>; getModuleInstanceForDisplay(componentInstanceId:string, moduleId:string):ng.IPromise<DisplayModule>; updateGroupMetadata(group:Module):ng.IPromise<Module>; + + //---------------------------------------------- HELP FUNCTIONS ----------------------------------------------------// + + getComponentSubType():string; isAlreadyCertified():boolean; isService():boolean; @@ -158,7 +163,8 @@ export abstract class Component implements IComponent { public systemName:string; public projectCode:string; public policies:Array<PolicyInstance>; - public groups:Array<Module>; + public groupInstances:Array<GroupInstance> + public modules:Array<Module>; //custom properties public componentService:IComponentService; public filterTerm:string; @@ -168,7 +174,8 @@ export abstract class Component implements IComponent { public subCategory:string; public selectedCategory:string; public showMenu:boolean; - + public archived:boolean; + public vspArchived: boolean; constructor(componentService:IComponentService, protected $q:ng.IQService, component?:Component) { if (component) { @@ -221,7 +228,11 @@ export abstract class Component implements IComponent { this.selectedInstance = component.selectedInstance; this.iconSprite = component.iconSprite; this.showMenu = true; - this.groups = CommonUtils.initModules(component.groups); + this.modules = component.modules; + this.groupInstances = component.groupInstances; + this.policies = component.policies; + this.archived = component.archived; + this.vspArchived = component.vspArchived; } //custom properties @@ -239,7 +250,7 @@ export abstract class Component implements IComponent { //------------------------------------------ API Calls ----------------------------------------------------------------// public changeLifecycleState = (state:string, commentObj:AsdcComment):ng.IPromise<Component> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Component>(); let onSuccess = (componentMetadata:ComponentMetadata):void => { this.setComponentMetadata(componentMetadata); // this.version = componentMetadata.version; @@ -277,7 +288,7 @@ export abstract class Component implements IComponent { }; public addOrUpdateArtifact = (artifact:ArtifactModel):ng.IPromise<ArtifactModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<ArtifactModel>(); let onSuccess = (artifactObj:ArtifactModel):void => { let newArtifact = new ArtifactModel(artifactObj); let artifacts = this.getArtifactsByType(artifactObj.artifactGroupType); @@ -309,7 +320,7 @@ export abstract class Component implements IComponent { public deleteArtifact = (artifactId:string, artifactLabel:string):ng.IPromise<ArtifactModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<ArtifactModel>(); let onSuccess = (artifactObj:ArtifactModel):void => { let newArtifact = new ArtifactModel(artifactObj); let artifacts = this.getArtifactsByType(artifactObj.artifactGroupType); @@ -327,7 +338,7 @@ export abstract class Component implements IComponent { public getArtifactByGroupType = (artifactGroupType:string):ng.IPromise<ArtifactGroupModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<ArtifactGroupModel>(); let onSuccess = (response:ArtifactGroupModel):void => { deferred.resolve(response); }; @@ -340,7 +351,7 @@ export abstract class Component implements IComponent { public getComponentInstanceArtifactsByGroupType = (componentInstanceId:string, artifactGroupType:string):ng.IPromise<ArtifactGroupModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<ArtifactGroupModel>(); let onSuccess = (response:ArtifactGroupModel):void => { deferred.resolve(response); }; @@ -352,7 +363,7 @@ export abstract class Component implements IComponent { }; public addOrUpdateProperty = (property:PropertyModel):ng.IPromise<PropertyModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<PropertyModel>(); let onError = (error:any):void => { deferred.reject(error); @@ -380,7 +391,7 @@ export abstract class Component implements IComponent { }; public addOrUpdateAttribute = (attribute:AttributeModel):ng.IPromise<AttributeModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<AttributeModel>(); let onError = (error:any):void => { deferred.reject(error); @@ -408,7 +419,7 @@ export abstract class Component implements IComponent { }; public deleteProperty = (propertyId:string):ng.IPromise<PropertyModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<PropertyModel>(); let onSuccess = ():void => { console.log("Property deleted"); delete _.remove(this.properties, {uniqueId: propertyId})[0]; @@ -423,7 +434,7 @@ export abstract class Component implements IComponent { }; public deleteAttribute = (attributeId:string):ng.IPromise<AttributeModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<AttributeModel>(); let onSuccess = ():void => { console.log("Attribute deleted"); delete _.remove(this.attributes, {uniqueId: attributeId})[0]; @@ -435,18 +446,23 @@ export abstract class Component implements IComponent { return deferred.promise; }; + + public updateInstancePropertiesSuccess = (newProperties:PropertyModel[]):void => { + newProperties.forEach((newProperty) => { + // find exist instance property in parent component for update the new value ( find bu uniqueId & path) + let existProperty: PropertyModel = <PropertyModel>_.find(this.componentInstancesProperties[newProperty.resourceInstanceUniqueId], { + uniqueId: newProperty.uniqueId, + path: newProperty.path + }); + let index = this.componentInstancesProperties[newProperty.resourceInstanceUniqueId].indexOf(existProperty); + this.componentInstancesProperties[newProperty.resourceInstanceUniqueId][index] = newProperty; + }); + } + public updateInstanceProperties = (componentInstanceId:string, properties:PropertyModel[]):ng.IPromise<PropertyModel[]> => { let deferred = this.$q.defer<PropertyModel[]>(); let onSuccess = (newProperties:PropertyModel[]):void => { - newProperties.forEach((newProperty) => { - // find exist instance property in parent component for update the new value ( find bu uniqueId & path) - let existProperty: PropertyModel = <PropertyModel>_.find(this.componentInstancesProperties[newProperty.resourceInstanceUniqueId], { - uniqueId: newProperty.uniqueId, - path: newProperty.path - }); - let index = this.componentInstancesProperties[newProperty.resourceInstanceUniqueId].indexOf(existProperty); - this.componentInstancesProperties[newProperty.resourceInstanceUniqueId][index] = newProperty; - }); + this.updateInstancePropertiesSuccess(newProperties); deferred.resolve(newProperties); }; let onFailed = (error:any):void => { @@ -458,7 +474,7 @@ export abstract class Component implements IComponent { }; public updateInstanceAttribute = (attribute:AttributeModel):ng.IPromise<AttributeModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<AttributeModel>(); let onSuccess = (newAttribute:AttributeModel):void => { let existAttribute:AttributeModel = <AttributeModel>_.find(this.componentInstancesAttributes[newAttribute.resourceInstanceUniqueId], {uniqueId: newAttribute.uniqueId}); let index = this.componentInstancesAttributes[newAttribute.resourceInstanceUniqueId].indexOf(existAttribute); @@ -478,7 +494,7 @@ export abstract class Component implements IComponent { }; public deleteInstanceArtifact = (artifactId:string, artifactLabel:string):ng.IPromise<ArtifactModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<ArtifactModel>(); let onSuccess = (artifactObj:ArtifactModel):void => { let newArtifact = new ArtifactModel(artifactObj); let artifacts = this.selectedInstance.deploymentArtifacts; @@ -495,7 +511,7 @@ export abstract class Component implements IComponent { }; public addOrUpdateInstanceArtifact = (artifact:ArtifactModel):ng.IPromise<ArtifactModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<ArtifactModel>(); let onSuccess = (artifactObj:ArtifactModel):void => { switch (artifactObj.artifactGroupType) { case ArtifactGroupType.DEPLOYMENT: @@ -519,7 +535,7 @@ export abstract class Component implements IComponent { }; public uploadInstanceEnvFile = (artifact:ArtifactModel):ng.IPromise<ArtifactModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<ArtifactModel>(); let onSuccess = (artifactObj:ArtifactModel):void => { this.selectedInstance.deploymentArtifacts[artifactObj.artifactLabel] = artifactObj; deferred.resolve(artifactObj); @@ -533,7 +549,7 @@ export abstract class Component implements IComponent { //this function will update the instance version than the function call getComponent to update the current component and return the new instance version public changeComponentInstanceVersion = (componentUid:string):ng.IPromise<Component> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Component>(); let onFailed = (error:any):void => { deferred.reject(error); }; @@ -553,7 +569,7 @@ export abstract class Component implements IComponent { }; public createComponentInstance = (componentInstance:ComponentInstance):ng.IPromise<ComponentInstance> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<ComponentInstance>(); let onSuccess = (instance:ComponentInstance):void => { this.componentInstances.push(instance); deferred.resolve(instance); @@ -566,7 +582,7 @@ export abstract class Component implements IComponent { }; public updateComponentInstance = (componentInstance:ComponentInstance):ng.IPromise<ComponentInstance> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<ComponentInstance>(); let onSuccess = (updatedInstance:ComponentInstance):void => { let componentInstance:ComponentInstance = _.find(this.componentInstances, (instance:ComponentInstance) => { return instance.uniqueId === updatedInstance.uniqueId; @@ -585,7 +601,7 @@ export abstract class Component implements IComponent { }; public updateMultipleComponentInstances = (instances:Array<ComponentInstance>):ng.IPromise<Array<ComponentInstance>> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Array<ComponentInstance>>(); let onSuccess = (updatedInstances:Array<ComponentInstance>):void => { _.forEach(updatedInstances, (updatedComponentInstance) => { let componentInstance:ComponentInstance = _.find(this.componentInstances, (instance:ComponentInstance) => { @@ -607,13 +623,13 @@ export abstract class Component implements IComponent { }; public deleteComponentInstance = (componentInstanceId:string):ng.IPromise<ComponentInstance> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<ComponentInstance>(); let onSuccess = ():void => { let onSuccess = (component:Component):void => { this.componentInstances = CommonUtils.initComponentInstances(component.componentInstances); this.componentInstancesProperties = new PropertiesGroup(component.componentInstancesProperties); this.componentInstancesAttributes = new AttributesGroup(component.componentInstancesAttributes); - this.groups = component.groups; + this.modules = component.modules; this.componentInstancesRelations = CommonUtils.initComponentInstanceRelations(component.componentInstancesRelations); deferred.resolve(); }; @@ -680,7 +696,7 @@ export abstract class Component implements IComponent { }; public createRelation = (relation:RelationshipModel):ng.IPromise<RelationshipModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<RelationshipModel>(); let onSuccess = (relation:RelationshipModel):void => { console.info('Link created successfully', relation); if (!this.componentInstancesRelations) { @@ -699,7 +715,7 @@ export abstract class Component implements IComponent { }; public deleteRelation = (relation:RelationshipModel):ng.IPromise<RelationshipModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<RelationshipModel>(); let onSuccess = (relation:RelationshipModel):void => { console.log("Link Deleted In Server"); let relationToDelete = _.find(this.componentInstancesRelations, (item) => { @@ -774,7 +790,7 @@ export abstract class Component implements IComponent { public getModuleForDisplay = (moduleId:string):ng.IPromise<DisplayModule> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<DisplayModule>(); let onSuccess = (response:DisplayModule):void => { deferred.resolve(response); }; @@ -787,7 +803,7 @@ export abstract class Component implements IComponent { public getModuleInstanceForDisplay = (componentInstanceId:string, moduleId:string):ng.IPromise<DisplayModule> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<DisplayModule>(); let onSuccess = (response:DisplayModule):void => { deferred.resolve(response); }; @@ -803,7 +819,7 @@ export abstract class Component implements IComponent { // get all the instances of the component (in service only VF instances) public getComponentInstancesFilteredByInputsAndProperties = (searchText?:string):ng.IPromise<Array<ComponentInstance>> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Array<ComponentInstance>>(); let onSuccess = (response:Array<ComponentInstance>):void => { deferred.resolve(response); }; @@ -818,7 +834,7 @@ export abstract class Component implements IComponent { // get inputs for instance - Pagination function public getComponentInputs = ():ng.IPromise<Array<InputModel>> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Array<InputModel>>(); let onSuccess = (inputsRes:Array<InputModel>):void => { this.inputs = inputsRes; deferred.resolve(inputsRes); @@ -834,7 +850,7 @@ export abstract class Component implements IComponent { // get inputs instance - Pagination function public getComponentInstanceInputs = (componentInstanceId:string, originComponentUid:string):ng.IPromise<Array<InputModel>> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Array<InputModel>>(); let onSuccess = (response:Array<InputModel>):void => { deferred.resolve(response); }; @@ -848,7 +864,7 @@ export abstract class Component implements IComponent { // get inputs inatnce - Pagination function public getComponentInstanceInputProperties = (componentInstanceId:string, inputId:string):ng.IPromise<Array<PropertyModel>> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Array<PropertyModel>>(); let onSuccess = (response:Array<PropertyModel>):void => { deferred.resolve(response); }; @@ -862,7 +878,7 @@ export abstract class Component implements IComponent { // get inputs inatnce - Pagination function public getComponentInstanceProperties = (componentInstanceId:string):ng.IPromise<Array<PropertyModel>> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Array<PropertyModel>>(); let onSuccess = (response:Array<PropertyModel>):void => { deferred.resolve(response); }; @@ -876,15 +892,15 @@ export abstract class Component implements IComponent { public updateGroupMetadata = (module:Module):ng.IPromise<Module> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Module>(); let onSuccess = (updatedModule:Module):void => { - let groupIndex:number = _.indexOf(this.groups, _.find(this.groups, (module:Module) => { + let groupIndex:number = _.indexOf(this.modules, _.find(this.modules, (module:Module) => { return module.uniqueId === updatedModule.uniqueId; })); if (groupIndex !== -1) { - this.groups[groupIndex] = updatedModule; + this.modules[groupIndex] = updatedModule; } deferred.resolve(updatedModule); }; @@ -1022,7 +1038,8 @@ export abstract class Component implements IComponent { this.systemName = componentMetadata.systemName; this.projectCode = componentMetadata.projectCode; this.categories = componentMetadata.categories; - + this.archived = componentMetadata.archived || false; + this.vspArchived = componentMetadata.vspArchived; } public toJSON = ():any => { @@ -1036,6 +1053,9 @@ export abstract class Component implements IComponent { temp.showMenu = undefined; temp.$q = undefined; temp.selectedCategory = undefined; + temp.modules = undefined + temp.groupInstances = undefined; + temp.policies = undefined; return temp; }; } diff --git a/catalog-ui/src/app/models/components/displayComponent.ts b/catalog-ui/src/app/models/components/displayComponent.ts index c89490306c..f96e0bf14b 100644 --- a/catalog-ui/src/app/models/components/displayComponent.ts +++ b/catalog-ui/src/app/models/components/displayComponent.ts @@ -22,7 +22,6 @@ */ 'use strict'; -import * as _ from "lodash"; import {ComponentType} from "../../utils/constants"; import {ComponentMetadata} from "../component-metadata"; import {PolicyMetadata} from "../policy-metadata"; @@ -48,6 +47,7 @@ export class LeftPaletteComponent { searchFilterTerms:string; certifiedIconClass:string; icon:string; + isDraggable:boolean; isRequirmentAndCapabilitiesLoaded:boolean; uuid:string; @@ -64,7 +64,7 @@ export class LeftPaletteComponent { categoryType:LeftPaletteMetadataTypes; - constructor(metadataType: LeftPaletteMetadataTypes, item: ComponentMetadata | PolicyMetadata) { + constructor(metadataType: LeftPaletteMetadataTypes, item: ComponentMetadata | PolicyMetadata | GroupMetadata) { if (metadataType === LeftPaletteMetadataTypes.Policy) { this.initPolicy(item as PolicyMetadata); return; @@ -94,6 +94,7 @@ export class LeftPaletteComponent { this.componentType = component.componentType; this.systemName = component.systemName; this.invariantUUID = component.invariantUUID; + this.isDraggable = true; if (component.categories && component.categories[0] && component.categories[0].subcategories && component.categories[0].subcategories[0]) { this.mainCategory = component.categories[0].name; @@ -118,7 +119,7 @@ export class LeftPaletteComponent { this.categoryType = LeftPaletteMetadataTypes.Group; this.uniqueId = group.uniqueId; - this.displayName = group.type; + this.displayName = group.name; this.mainCategory = "Groups"; this.subCategory = "Groups"; this.iconClass = "sprite-group-icons group"; @@ -127,14 +128,15 @@ export class LeftPaletteComponent { this.type = group.type; this.componentSubType = 'GROUP'; - this.searchFilterTerms = this.displayName + ' ' + group.description + ' ' + group.version; + this.searchFilterTerms = this.type + ' ' + group.name + ' ' + group.version; + this.isDraggable = false; } private initPolicy(policy:PolicyMetadata): void { this.categoryType = LeftPaletteMetadataTypes.Policy; this.uniqueId = policy.uniqueId; - this.displayName = policy.type; + this.displayName = policy.name; this.mainCategory = "Policies"; this.subCategory = "Policies"; this.iconClass = "sprite-policy-icons policy"; @@ -143,7 +145,8 @@ export class LeftPaletteComponent { this.type = policy.type; this.componentSubType = 'POLICY'; - this.searchFilterTerms = this.displayName + ' ' + policy.description + ' ' + policy.version; + this.searchFilterTerms = this.type + ' ' + policy.name + ' ' + policy.version; + this.isDraggable = false; } public initDisplayName = (name:string):void => { diff --git a/catalog-ui/src/app/models/components/resource.ts b/catalog-ui/src/app/models/components/resource.ts index 5bd80e3b72..733f2ff9d1 100644 --- a/catalog-ui/src/app/models/components/resource.ts +++ b/catalog-ui/src/app/models/components/resource.ts @@ -104,7 +104,7 @@ export class Resource extends Component { }; public createComponentOnServer = ():ng.IPromise<Component> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Component>(); let onSuccess = (component:Resource):void => { this.payloadData = undefined; this.payloadName = undefined; @@ -125,7 +125,7 @@ export class Resource extends Component { public updateResourceGroupProperties = (module:DisplayModule, properties:Array<PropertyModel>):ng.IPromise<Array<PropertyModel>> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Array<PropertyModel>>(); let onSuccess = (updatedProperties:Array<PropertyModel>):void => { _.forEach(updatedProperties, (property:PropertyModel) => { // Replace all updated properties on the module we needed to update _.extend(_.find(module.properties, {uniqueId: property.uniqueId}), property); @@ -144,7 +144,7 @@ export class Resource extends Component { // For now we only implement the logic in service level public createInputsFormInstances = (instanceInputsPropertiesMap:InstancesInputsOrPropertiesMapData):ng.IPromise<Array<InputModel>> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Array<InputModel>>(); return deferred.promise; }; @@ -175,6 +175,9 @@ export class Resource extends Component { temp.$q = undefined; temp.selectedCategory = undefined; temp.importedFile = undefined; + temp.modules = undefined; + temp.groupInstances = undefined; + temp.policies = undefined; return temp; }; } diff --git a/catalog-ui/src/app/models/components/service.ts b/catalog-ui/src/app/models/components/service.ts index 439925f062..a947e81716 100644 --- a/catalog-ui/src/app/models/components/service.ts +++ b/catalog-ui/src/app/models/components/service.ts @@ -39,6 +39,7 @@ export class Service extends Component { public serviceType:string; public serviceRole:string; public environmentContext:string; + public instantiationType:string; public forwardingPaths:{ [key:string]:ForwardingPath } = {}; constructor(componentService:IServiceService, $q:ng.IQService, component?:Service) { @@ -51,6 +52,7 @@ export class Service extends Component { this.namingPolicy = component.namingPolicy; this.serviceType = component.serviceType; this.serviceRole = component.serviceRole; + this.instantiationType = component.instantiationType; this.environmentContext = component.environmentContext; if (component.categories && component.categories[0]) { this.mainCategory = component.categories[0].name; @@ -78,7 +80,7 @@ export class Service extends Component { */ public createInputsFormInstances = (instancesInputsMap:InstancesInputsOrPropertiesMapData, instancePropertiesMap:InstancesInputsOrPropertiesMapData):ng.IPromise<Array<InputModel>> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Array<InputModel>>(); let onSuccess = (inputsCreated:Array<InputModel>):void => { this.inputs = inputsCreated.concat(this.inputs); deferred.resolve(inputsCreated); @@ -94,8 +96,8 @@ export class Service extends Component { }; // we need to change the name of the input to vfInstanceName + input name before sending to server in order to create the inputs on the service - public getServiceInputInputsAndProperties = (inputId:string):ng.IPromise<Array<InputModel>> => { - let deferred = this.$q.defer(); + public getServiceInputInputsAndProperties = (inputId:string):ng.IPromise<InputsAndProperties> => { + let deferred = this.$q.defer<InputsAndProperties>(); let onSuccess = (inputsAndProperties:InputsAndProperties):void => { let input:InputModel = _.find(this.inputs, (input:InputModel) => { return input.uniqueId === inputId; @@ -112,7 +114,7 @@ export class Service extends Component { }; public deleteServiceInput = (inputId:string):ng.IPromise<InputModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<InputModel>(); let onSuccess = (deletedInput:InputModel):void => { delete _.remove(this.inputs, {uniqueId: deletedInput.uniqueId})[0]; @@ -140,7 +142,7 @@ export class Service extends Component { public updateGroupInstanceProperties = (resourceInstanceId:string, group:DisplayModule, properties:Array<PropertyModel>):ng.IPromise<Array<PropertyModel>> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Array<PropertyModel>>(); let onSuccess = (updatedProperties:Array<PropertyModel>):void => { _.forEach(updatedProperties, (property:PropertyModel) => { // Replace all updated properties on the we needed to update _.extend(_.find(group.properties, {uniqueId: property.uniqueId}), property); @@ -167,6 +169,7 @@ export class Service extends Component { this.serviceType = componentMetadata.serviceType; this.serviceRole = componentMetadata.serviceRole; this.environmentContext = componentMetadata.environmentContext; + this.instantiationType = componentMetadata.instantiationType; this.setComponentDisplayData(); } @@ -178,5 +181,21 @@ export class Service extends Component { } this.iconSprite = "sprite-services-icons"; } + + public toJSON = ():any => { + let temp = angular.copy(this); + temp.componentService = undefined; + temp.filterTerm = undefined; + temp.iconSprite = undefined; + temp.mainCategory = undefined; + temp.subCategory = undefined; + temp.selectedInstance = undefined; + temp.showMenu = undefined; + temp.$q = undefined; + temp.selectedCategory = undefined; + temp.modules = undefined; + temp.groupInstances = undefined; + return temp; + }; } diff --git a/catalog-ui/src/app/models/componentsInstances/componentInstance.ts b/catalog-ui/src/app/models/componentsInstances/componentInstance.ts index e8444b3c54..fcc3298249 100644 --- a/catalog-ui/src/app/models/componentsInstances/componentInstance.ts +++ b/catalog-ui/src/app/models/componentsInstances/componentInstance.ts @@ -60,6 +60,7 @@ export class ComponentInstance { public properties:Array<PropertyModel>; public groupInstances:Array<Module>; public invariantName:string; + public originArchived:boolean; constructor(componentInstance?:ComponentInstance) { @@ -90,6 +91,7 @@ export class ComponentInstance { this.sourceModelName = componentInstance.sourceModelName; this.sourceModelUid = componentInstance.sourceModelUid; this.sourceModelUuid = componentInstance.sourceModelUuid; + this.originArchived = componentInstance.originArchived; } } @@ -171,4 +173,8 @@ export class ComponentInstance { temp.capabilities = undefined; return temp; }; + + public get iconClass() { + return this.iconSprite + ' ' + this.icon; + } } diff --git a/catalog-ui/src/app/models/graph/nodes/common-ci-node-base.ts b/catalog-ui/src/app/models/graph/nodes/common-ci-node-base.ts index fb051c891d..dfd39d1b9f 100644 --- a/catalog-ui/src/app/models/graph/nodes/common-ci-node-base.ts +++ b/catalog-ui/src/app/models/graph/nodes/common-ci-node-base.ts @@ -22,6 +22,7 @@ import {ComponentInstance} from "../../componentsInstances/componentInstance"; export abstract class CommonCINodeBase extends CommonNodeBase { public certified:boolean; + public archived:boolean; public template:string; public componentInstance:ComponentInstance; public group:string; @@ -34,6 +35,7 @@ export abstract class CommonCINodeBase extends CommonNodeBase { this.img = ''; this.certified = this.isCertified(this.componentInstance.componentVersion); this.displayName = instance.name; + this.archived = instance.originArchived; } private isCertified(version:string):boolean { diff --git a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-base.ts b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-base.ts index 3b634b1f6e..a24142348c 100644 --- a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-base.ts +++ b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-base.ts @@ -20,7 +20,7 @@ import {ComponentInstance} from "../../../componentsInstances/componentInstance"; import {CommonCINodeBase} from "../common-ci-node-base"; -import {ImageCreatorService} from "app/directives/graphs-v2/image-creator/image-creator.service"; +import {ICanvasImage, ImageCreatorService} from "app/directives/graphs-v2/image-creator/image-creator.service"; import {ImagesUrl, GraphUIObjects} from "app/utils"; import {AngularJSBridge} from "app/services"; @@ -42,47 +42,72 @@ export abstract class CompositionCiNodeBase extends CommonCINodeBase implements } private init() { - this.displayName = this.getDisplayName(); this.isUcpe = false; this.isGroup = false; this.isUcpePart = false; this.isInsideGroup = false; } + + + public setUncertifiedImageBgStyle(node:Cy.Collection, nodeMinSize:number):string { - public initUncertifiedImage(node:Cy.Collection, nodeMinSize:number):string { - let uncertifiedIconWidth:number = GraphUIObjects.HANDLE_SIZE; let nodeWidth:number = node.data('imgWidth') || node.width(); let uncertifiedCanvasWidth: number = nodeWidth; - + if (nodeWidth < nodeMinSize) { //uncertified icon will overlap too much of the node, need to expand canvas. uncertifiedCanvasWidth = nodeWidth + uncertifiedIconWidth/2; //expand canvas so that only half of the icon overlaps with the node } - - - - this.imageCreator.getImageBase64(this.imagesPath + this.componentInstance.icon + '.png', - this.imagesPath + 'uncertified.png', nodeWidth, uncertifiedCanvasWidth, uncertifiedIconWidth) - .then(imageBase64 => { - this.img = imageBase64; - node.style({ - 'background-image': this.img, - 'background-width': uncertifiedCanvasWidth, - 'background-height': uncertifiedCanvasWidth, - 'width': uncertifiedCanvasWidth, - 'height': uncertifiedCanvasWidth - }); - }); - - return this.img; + + const x = uncertifiedCanvasWidth - nodeWidth, y = x, width = nodeWidth, height = width; + + const canvasImages:ICanvasImage[] = [ + { src: this.imagesPath + this.componentInstance.icon + '.png', x, y, width, height}, + { src: this.imagesPath + 'uncertified.png', x: 0, y: 0, width: uncertifiedIconWidth, height: uncertifiedIconWidth} + ]; + + + //Create the image and update the node background styles + this.imageCreator.getMultiLayerBase64Image(canvasImages, uncertifiedCanvasWidth, uncertifiedCanvasWidth).then(img => this.updateNodeStyles(node,uncertifiedCanvasWidth,img)); + return this.img; // Return the referance to the image (in Base64 format) } - protected getDisplayName():string { + + public setArchivedImageBgStyle(node:Cy.Collection, nodeMinSize:number):string { + let archivedIconWidth:number = GraphUIObjects.HANDLE_SIZE; + let nodeWidth:number = node.data('imgWidth') || node.width(); + let archivedCanvasWidth: number = nodeWidth; + const x = archivedCanvasWidth - nodeWidth, y = x, width = nodeWidth, height = width; + const archiveImage = nodeWidth < 50? 'archive_small.png':'archive_big.png'; + + const canvasImages = [ + { src: this.imagesPath + this.componentInstance.icon + '.png', x, y, width, height}, + { src: AngularJSBridge.getAngularConfig().imagesPath + ImagesUrl.RESOURCE_ICONS + archiveImage, x, y, width, height} + ]; + + //Create the image and update the node background styles + this.imageCreator.getMultiLayerBase64Image(canvasImages, archivedCanvasWidth, archivedCanvasWidth).then(img => this.updateNodeStyles(node, archivedCanvasWidth, img)); + return this.img; // Return the default img + } + + protected getDisplayName():string { let graphResourceName = AngularJSBridge.getFilter('graphResourceName'); let resourceName = AngularJSBridge.getFilter('resourceName'); return graphResourceName(resourceName(this.componentInstance.name)); } + //TODO:: move to Base class ??? + private updateNodeStyles(node,canvasWidth,imageBase64){ + this.img = imageBase64; + node.style({ + 'background-image': this.img, + 'background-width': canvasWidth, + 'background-height': canvasWidth, + 'background-position-x':0, + 'background-position-y':0 + }); + } + } diff --git a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-configuration.ts b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-configuration.ts index 1182f5e664..78bcc17186 100644 --- a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-configuration.ts +++ b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-configuration.ts @@ -35,5 +35,8 @@ export class CompositionCiNodeConfiguration extends CompositionCiNodeBase { this.imgWidth = GraphUIObjects.SMALL_RESOURCE_WIDTH; this.type = "basic-small-node"; this.classes = 'configuration-node'; + if(this.archived){ + this.classes = this.classes + ' archived'; + } } } diff --git a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-cp.ts b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-cp.ts index 3bd57695ec..05a6d790ab 100644 --- a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-cp.ts +++ b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-cp.ts @@ -44,9 +44,12 @@ export class CompositionCiNodeCp extends CompositionCiNodeBase { } else { this.classes = 'cp-node'; } + if(this.archived){ + this.classes = this.classes + ' archived'; + return; + } if (!this.certified) { this.classes = this.classes + ' not-certified'; } - } } diff --git a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-service-proxy.ts b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-service-proxy.ts index b993490043..b025221f25 100644 --- a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-service-proxy.ts +++ b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-service-proxy.ts @@ -33,7 +33,11 @@ export class CompositionCiNodeServiceProxy extends CompositionCiNodeBase { this.imagesPath = this.imagesPath + ImagesUrl.SERVICE_PROXY_ICONS; this.img = this.imagesPath + this.componentInstance.icon + '.png'; this.imgWidth = GraphUIObjects.DEFAULT_RESOURCE_WIDTH; - this.classes = 'service-node' + this.classes = 'service-node'; + if(this.archived){ + this.classes = this.classes + ' archived'; + return; + } if (!this.certified) { this.classes = this.classes + ' not-certified'; } diff --git a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-service.ts b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-service.ts index b4e6ac354a..bf8facf002 100644 --- a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-service.ts +++ b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-service.ts @@ -33,10 +33,13 @@ export class CompositionCiNodeService extends CompositionCiNodeBase { this.imagesPath = this.imagesPath + ImagesUrl.SERVICE_ICONS; this.img = this.imagesPath + ImagesUrl.SERVICE_ICONS + this.componentInstance.icon + '.png'; this.imgWidth = GraphUIObjects.DEFAULT_RESOURCE_WIDTH; - this.classes = 'service-node' + this.classes = 'service-node'; + if(this.archived){ + this.classes = this.classes + ' archived'; + return; + } if (!this.certified) { this.classes = this.classes + ' not-certified'; } - } } diff --git a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-ucpe.ts b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-ucpe.ts index 3dd6a4e238..d4172c0eaa 100644 --- a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-ucpe.ts +++ b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-ucpe.ts @@ -38,7 +38,10 @@ export class NodeUcpe extends CompositionCiNodeBase { this.type = 'ucpe-node'; this.allowConnection = false; this.imagesPath = this.imagesPath + ImagesUrl.RESOURCE_ICONS; - + if(this.archived){ + this.classes = this.classes + ' archived'; + return; + } if (!this.certified) { this.classes = this.classes + ' not-certified-ucpe'; } diff --git a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-vf.ts b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-vf.ts index b5ad57a5c3..4aff85e6c3 100644 --- a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-vf.ts +++ b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-vf.ts @@ -35,6 +35,10 @@ export class CompositionCiNodeVf extends CompositionCiNodeBase { this.img = this.imagesPath + this.componentInstance.icon + '.png'; this.imgWidth = GraphUIObjects.DEFAULT_RESOURCE_WIDTH; this.classes = 'vf-node'; + if(this.archived){ + this.classes = this.classes + ' archived'; + return; + } if (!this.certified) { this.classes = this.classes + ' not-certified'; } diff --git a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-vl.ts b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-vl.ts index eded75d5da..a440f09156 100644 --- a/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-vl.ts +++ b/catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-vl.ts @@ -52,6 +52,10 @@ export class CompositionCiNodeVl extends CompositionCiNodeBase { this.imagesPath = this.imagesPath + ImagesUrl.RESOURCE_ICONS; this.classes = 'vl-node'; + if(this.archived){ + this.classes = this.classes + ' archived'; + return; + } if (!this.certified) { this.classes = this.classes + ' not-certified'; } diff --git a/catalog-ui/src/app/models/graph/zones/group-instance.ts b/catalog-ui/src/app/models/graph/zones/group-instance.ts new file mode 100644 index 0000000000..92d850b894 --- /dev/null +++ b/catalog-ui/src/app/models/graph/zones/group-instance.ts @@ -0,0 +1,85 @@ +import {PropertyModel} from "app/models"; +import {CommonUtils} from "app/utils"; +import {IZoneInstanceAssignment} from "./zone-instance"; +import {ComponentInstance} from "../../componentsInstances/componentInstance"; +import {MemberUiObject} from "../../ui-models/ui-member-object"; +import * as _ from "lodash"; + +export class GroupInstance { + + public artifacts:Array<string>; + public artifactsUuid:Array<string>; + public description:string; + public empty:boolean; + public groupUUID:string; + public invariantUUID:string; + public members:Array<string>; + public name:string; + public ownerId:string; + public properties:Array<PropertyModel>; + public propertyValueCounter:number; + public type:string; + public typeUid:string; + public uniqueId:string; + public version:string; + public iconSprite:string; + public icon:string; + public originArchived?:boolean; + + + constructor(group:GroupInstance) { + + this.name = group.name; + this.groupUUID = group.groupUUID; + this.invariantUUID = group.invariantUUID; + this.propertyValueCounter = group.propertyValueCounter; + this.type = group.type; + this.typeUid = group.typeUid; + this.uniqueId = group.uniqueId; + this.version = group.version; + this.artifacts = group.artifacts; + this.artifactsUuid = group.artifactsUuid; + this.properties = CommonUtils.initProperties(group.properties); + this.members = _.values(group.members); + this.description = group.description; + this.empty = group.empty; + this.ownerId = group.ownerId; + + this.iconSprite = ''; + this.icon = 'icon-group'; + } + + public getMembersAsUiObject(componentInstances?:Array<ComponentInstance>):Array<MemberUiObject> { + let savedItems:Array<MemberUiObject> = []; + if (!_.isEmpty(this.members)) { + _.forEach(this.members, (memberId:string)=> { + let componentInstance:ComponentInstance; + if (componentInstances) { + componentInstance = _.find(componentInstances, function (_componentInstance:ComponentInstance) { + return _componentInstance.uniqueId === memberId; + }) + } + savedItems.push(new MemberUiObject(memberId, componentInstance ? componentInstance.name : undefined)); + }); + } + return savedItems; + }; + + public setMembers = (newMembers:Array<MemberUiObject>):void => { + this.members = newMembers.map(member => member.uniqueId); + }; + + // This function is used for the zone + public getSavedAssignments = ():Array<IZoneInstanceAssignment> => { + return this.getMembersAsUiObject(); + }; + + public setSavedAssignments = (newMembers:Array<IZoneInstanceAssignment>):void => { + this.setMembers(newMembers); + }; + + public get iconClass() { + return this.iconSprite + ' ' + this.icon; + } + +}
\ No newline at end of file diff --git a/catalog-ui/src/app/models/graph/zones/policy-instance.ts b/catalog-ui/src/app/models/graph/zones/policy-instance.ts index 63136e6e21..c0a6678b21 100644 --- a/catalog-ui/src/app/models/graph/zones/policy-instance.ts +++ b/catalog-ui/src/app/models/graph/zones/policy-instance.ts @@ -1,8 +1,48 @@ import { PropertyModel } from "app/models"; import { CommonUtils } from "app/utils"; +import {IZoneInstanceMethod, IZoneInstanceAssignment} from "./zone-instance"; +import {GroupInstance} from "./group-instance"; +import {ComponentInstance} from "../../componentsInstances/componentInstance"; +import {TargetUiObject} from "../../ui-models/ui-target-object"; +import {TargetOrMemberType} from "../../../utils/constants"; +/* The request and response should be same model, need to fix in BE */ +export class PolicyTargetsMap { + COMPONENT_INSTANCES:Array<string>; + GROUPS:Array<string>; +} +//TODO remove this +export class PolicyTargetsRequest { -export class PolicyInstance { + requestItems:Array<PolicyTargetsRequestItem>; + + constructor(groups:Array<string>,instances:Array<string>){ + + this.requestItems = []; + + if (instances && instances.length>0) { + let instancesObj:PolicyTargetsRequestItem = { + type: "component_Instances", + uniqueIds: instances + }; + this.requestItems.push(instancesObj); + } + if (groups && groups.length>0) { + let groupsObj:PolicyTargetsRequestItem = { + type: "groups", + uniqueIds: groups + }; + this.requestItems.push(groupsObj); + } + } +} + +export class PolicyTargetsRequestItem { + type: string; + uniqueIds:Array<String>; +} + +export class PolicyInstance implements IZoneInstanceMethod { componentName:string; description:string; empty:boolean; @@ -12,13 +52,17 @@ export class PolicyInstance { name:string; normalizedName:string; - policyTypeName:string; + type:string; policyTypeUid:string; policyUUID:string; properties:Array<PropertyModel>; - targets:Array<string>; + targets:PolicyTargetsMap; uniqueId:string; version:string; + iconSprite:string; + icon:string; + originArchived:boolean; + constructor(policy?:PolicyInstance) { this.componentName = policy.componentName; @@ -30,7 +74,7 @@ export class PolicyInstance { this.name = policy.name; this.normalizedName =policy.normalizedName; - this.policyTypeName = policy.policyTypeName; + this.type = policy.type; this.policyTypeUid = policy.policyTypeUid; this.policyUUID = policy.policyUUID; this.properties = CommonUtils.initProperties(policy.properties); @@ -38,6 +82,57 @@ export class PolicyInstance { this.uniqueId = policy.uniqueId; this.version = policy.version; + this.iconSprite = ''; + this.icon = 'icon-policy'; + } + + public getTargetsAsUiObject(componentInstances?:Array<ComponentInstance>, groupInstances?:Array<GroupInstance>):Array<TargetUiObject> { + let savedItems:Array<TargetUiObject> = []; + + //get all targets from component instances + if (!_.isEmpty(this.targets.COMPONENT_INSTANCES)) { + this.targets.COMPONENT_INSTANCES.forEach((targetInstanceId:string)=> { + let componentInstance:ComponentInstance; + if (componentInstances) { + componentInstance = _.find(componentInstances, function (_componentInstance:ComponentInstance) { + return _componentInstance.uniqueId === targetInstanceId; + }) + } + savedItems.push(new TargetUiObject(targetInstanceId, TargetOrMemberType.COMPONENT_INSTANCES, componentInstance ? componentInstance.name : undefined)); + }); + } + + //get all targets from groupInstances + if (!_.isEmpty(this.targets.GROUPS)) { + this.targets.GROUPS.forEach((groupsTargetId:string)=> { + let groupInstance:GroupInstance; + if (groupInstances) { + groupInstance = _.find(groupInstances, function (_groupInstance:GroupInstance) { + return _groupInstance.uniqueId === groupsTargetId; + }) + } + savedItems.push(new TargetUiObject(groupsTargetId, TargetOrMemberType.GROUPS, groupInstance? groupInstance.name : undefined)); + }); + } + return savedItems; + }; + + public saveTargets = (newTargets:Array<TargetUiObject>):void => { + this.targets.COMPONENT_INSTANCES = newTargets.filter(target => target.type === TargetOrMemberType.COMPONENT_INSTANCES).map(target => target.uniqueId); + this.targets.GROUPS = newTargets.filter(target => target.type === TargetOrMemberType.GROUPS).map(target => target.uniqueId); + } + + // This function is used for the zone to get and set the assignment + public getSavedAssignments = ():Array<IZoneInstanceAssignment> => { + return this.getTargetsAsUiObject(); + }; + + public setSavedAssignments = (newMembers:Array<IZoneInstanceAssignment>):void => { + this.saveTargets(newMembers); + } + + public get iconClass() { + return this.iconSprite + ' ' + this.icon; } }
\ No newline at end of file diff --git a/catalog-ui/src/app/models/graph/zones/zone-child.ts b/catalog-ui/src/app/models/graph/zones/zone-child.ts deleted file mode 100644 index d6d7198222..0000000000 --- a/catalog-ui/src/app/models/graph/zones/zone-child.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Type, Component } from "@angular/core"; -import { PolicyInstance } from "app/models/graph/zones/policy-instance"; - -export class ZoneConfig { - title:string; - defaultIconText:string; - type:string; 'policy|group'; - tagModeId:string; - instances:Array<ZoneInstanceConfig>; - showZone:boolean; - - - constructor (title:string, defaultText:string, type:string, showZone:boolean) { - this.title = title; - this.defaultIconText = defaultText; - this.type = type; - this.tagModeId = this.type + "-tagging"; - this.instances = []; - this.showZone = showZone; - } -} - -export class ZoneInstanceConfig { - - name:string; - assignments:Array<string>; //targets or members - instanceData:PolicyInstance; // | GroupInstance; - mode:ZoneInstanceMode; - - constructor(instance:PolicyInstance) { /* | GroupInstance */ - - this.name = instance.name; - this.instanceData = instance; - this.mode = ZoneInstanceMode.NONE; - - if(instance instanceof PolicyInstance) { - this.assignments = instance.targets; - } - } - -} - -export enum ZoneInstanceMode { - NONE, - HOVER, - SELECTED, - TAG -}
\ No newline at end of file diff --git a/catalog-ui/src/app/models/graph/zones/zone-instance.ts b/catalog-ui/src/app/models/graph/zones/zone-instance.ts new file mode 100644 index 0000000000..fb8ec7761a --- /dev/null +++ b/catalog-ui/src/app/models/graph/zones/zone-instance.ts @@ -0,0 +1,106 @@ +import {PolicyInstance} from "app/models/graph/zones/policy-instance"; +import {GroupInstance} from "./group-instance"; +import {Component as TopologyTemplate} from "app/models"; +import {IUiBaseObject} from "../../ui-models/ui-base-object"; +import { Subject } from "rxjs"; + +export enum ZoneInstanceMode { + NONE, + HOVER, + SELECTED, + TAG +} + +export enum ZoneInstanceType { + GROUP, + POLICY +} + +export enum ZoneInstanceAssignmentType { + COMPONENT_INSTANCES, + GROUPS +} + +export interface IZoneInstanceMethod { + + getSavedAssignments():Array<IZoneInstanceAssignment>; + setSavedAssignments(newAssignments:Array<IZoneInstanceAssignment>):void; +} + +export interface IZoneInstanceAssignment extends IUiBaseObject{ + type: ZoneInstanceAssignmentType +} + +export class ZoneInstance { + + parentComponentType:string; + parentComponentID:string; + instanceData: PolicyInstance | GroupInstance; + mode:ZoneInstanceMode; + type:ZoneInstanceType; + handle:string; + assignments:Array<IZoneInstanceAssignment>; //temp assignments visible on the UI; not the saved values on the BE + hidden:boolean; + forceSave:Subject<Function>; + + constructor(instance: PolicyInstance | GroupInstance, topologyTemplate:TopologyTemplate) { + + this.instanceData = instance; + this.parentComponentType = topologyTemplate.componentType; + this.parentComponentID = topologyTemplate.uniqueId; + + if (instance instanceof PolicyInstance) { + this.type = ZoneInstanceType.POLICY; + } else { + this.type = ZoneInstanceType.GROUP; + } + + this.assignments = this.instanceData.getSavedAssignments(); + this.mode = ZoneInstanceMode.NONE; + this.hidden = false; + this.forceSave = new Subject(); + } + + public isAlreadyAssigned = (nodeId:string):boolean => { + let matchingAssignments = this.assignments.filter((assignment) => { + return assignment.uniqueId == nodeId; + }); + return matchingAssignments && matchingAssignments.length > 0; + } + + public addOrRemoveAssignment = (nodeId:string, nodeType:ZoneInstanceAssignmentType)=> { //change temp assignments, unsaved but visible in UI. + + if (!this.isAlreadyAssigned(nodeId)) { + this.assignments.push(<IZoneInstanceAssignment>{uniqueId: nodeId, type: nodeType}); + } else { + this.assignments = this.assignments.filter(assignment => assignment.uniqueId != nodeId); + } + } + + public isZoneAssignmentChanged(oldAssignments:Array<IZoneInstanceAssignment>, newAssignments:Array<IZoneInstanceAssignment>):boolean { + if (oldAssignments.length != newAssignments.length) { + return true; + } + let difference:Array<IZoneInstanceAssignment> = oldAssignments.filter((oldAssignment) => { + return !newAssignments.find(newAssignment => newAssignment.uniqueId == oldAssignment.uniqueId); + }); + if (difference.length) { + return true; + } + + return false; + } + + public updateInstanceData (instanceData: PolicyInstance | GroupInstance):void { + this.instanceData = instanceData; + this.assignments = this.instanceData.getSavedAssignments(); + } + + public showHandle = (handleId:string) => { + this.handle = handleId; + } + + public hideHandle = ():void => { + this.handle = null; + } +} diff --git a/catalog-ui/src/app/models/graph/zones/zone.ts b/catalog-ui/src/app/models/graph/zones/zone.ts new file mode 100644 index 0000000000..eaabc62a25 --- /dev/null +++ b/catalog-ui/src/app/models/graph/zones/zone.ts @@ -0,0 +1,46 @@ +/** + * Created by ob0695 on 10.04.2018. + */ +import {ZoneInstanceType, ZoneInstance, IZoneInstanceAssignment} from "./zone-instance"; +import {Observable} from "rxjs/Rx"; +import { CANVAS_TAG_MODE } from "app/utils/constants"; + +export class Zone { + title:string; + type:ZoneInstanceType; + defaultIconText:string; + instances:Array<ZoneInstance>; + visible:boolean; + minimized:boolean; + + constructor(title:string, defaultText:string, type:ZoneInstanceType) { + this.title = title; + this.defaultIconText = defaultText; + this.type = type; + this.instances = []; + this.visible = false; + this.minimized = false; + } + + + public getTagModeId = () => { + let tagModeId = ZoneInstanceType[this.type].toUpperCase(); + return CANVAS_TAG_MODE[tagModeId + "_TAGGING"]; + } + + public getHoverTagModeId = () => { + let tagModeId = ZoneInstanceType[this.type].toUpperCase(); + return CANVAS_TAG_MODE[tagModeId + "_TAGGING_HOVER"]; + } + + public removeInstance = (instanceId:string) => { + this.instances = this.instances.filter(instance => instance.instanceData.uniqueId != instanceId); + }; +} + + +export interface IZoneService { + updateZoneInstanceAssignments(topologyTemplateType:string, topologyTemplateId:string, zoneInstanceId:string, assignments:Array<IZoneInstanceAssignment>):Observable<any>; + updateName(topologyTemplateType:string, topologyTemplateId:string, zoneInstanceId:string, newName:string):Observable<any>; + deleteZoneInstance(topologyTemplateType:string, topologyTemplateId:string, zoneInstanceId:string):Observable<any>; +}
\ No newline at end of file diff --git a/catalog-ui/src/app/models/group-metadata.ts b/catalog-ui/src/app/models/group-metadata.ts index ecd6e3e91c..1c137ac1be 100644 --- a/catalog-ui/src/app/models/group-metadata.ts +++ b/catalog-ui/src/app/models/group-metadata.ts @@ -1,4 +1,6 @@ export class GroupMetadata { + public name:string; + public icon:string; public uniqueId: string; public type: string; public version: string; @@ -11,6 +13,8 @@ export class GroupMetadata { deserialize (response): GroupMetadata { this.uniqueId = response.uniqueId; this.type = response.type; + this.name = response.name; + this.icon = response.icon; this.version = response.version; this.description = response.description; this.creationTime = response.creationTime; diff --git a/catalog-ui/src/app/models/instance-fe-details.ts b/catalog-ui/src/app/models/instance-fe-details.ts new file mode 100644 index 0000000000..b0a6baccc4 --- /dev/null +++ b/catalog-ui/src/app/models/instance-fe-details.ts @@ -0,0 +1,5 @@ +export class InstanceFeDetails { + name: string; + iconClass: string; + originArchived: boolean; +} diff --git a/catalog-ui/src/app/models/modules/base-module.ts b/catalog-ui/src/app/models/modules/base-module.ts index 63f4cc7103..e27065bbfa 100644 --- a/catalog-ui/src/app/models/modules/base-module.ts +++ b/catalog-ui/src/app/models/modules/base-module.ts @@ -43,7 +43,7 @@ export class Module { public artifacts:Array<string> | Array<ArtifactModel>; public artifactsUuid:Array<string>; public properties:Array<PropertyModel>; - public members:Array<string>; + public members:Map<string, string>; public customizationUUID:string; public groupInstanceUniqueId:string; // This will only have a value if this is a group instance diff --git a/catalog-ui/src/app/models/policy-metadata.ts b/catalog-ui/src/app/models/policy-metadata.ts index 33e0185e33..3f489bbaab 100644 --- a/catalog-ui/src/app/models/policy-metadata.ts +++ b/catalog-ui/src/app/models/policy-metadata.ts @@ -1,5 +1,7 @@ export class PolicyMetadata { public uniqueId: string; + public name:string; + public icon:string; public type: string; public version: string; public description: string; @@ -11,6 +13,8 @@ export class PolicyMetadata { deserialize (response): PolicyMetadata { this.uniqueId = response.uniqueId; this.type = response.type; + this.name = response.name; + this.icon = response.icon; this.version = response.version; this.description = response.description; this.creationTime = response.creationTime; diff --git a/catalog-ui/src/app/models/properties-inputs/property-fe-map.ts b/catalog-ui/src/app/models/properties-inputs/property-fe-map.ts index 30cfcf09fd..de943fcc3e 100644 --- a/catalog-ui/src/app/models/properties-inputs/property-fe-map.ts +++ b/catalog-ui/src/app/models/properties-inputs/property-fe-map.ts @@ -32,10 +32,14 @@ export class InstanceFePropertiesMap { export class InstancePropertiesAPIMap { componentInstanceProperties: InstanceBePropertiesMap; componentInstanceInputsMap: InstanceBePropertiesMap; + groupProperties: InstanceBePropertiesMap; + policyProperties: InstanceBePropertiesMap; - constructor(inputsMapData: InstanceBePropertiesMap, propertiesMapData: InstanceBePropertiesMap) { + constructor(inputsMapData: InstanceBePropertiesMap, propertiesMapData: InstanceBePropertiesMap, groupPropertiesMapData: InstanceBePropertiesMap, policyPropertiesMapData: InstanceBePropertiesMap) { this.componentInstanceInputsMap = inputsMapData ? inputsMapData: new InstanceBePropertiesMap(); this.componentInstanceProperties = propertiesMapData ? propertiesMapData: new InstanceBePropertiesMap(); + this.groupProperties = groupPropertiesMapData ? groupPropertiesMapData : new InstanceBePropertiesMap(); + this.policyProperties = policyPropertiesMapData ? policyPropertiesMapData : new InstanceBePropertiesMap(); } } diff --git a/catalog-ui/src/app/models/properties-inputs/property-fe-model.ts b/catalog-ui/src/app/models/properties-inputs/property-fe-model.ts index a0c087bdc2..c0af885d18 100644 --- a/catalog-ui/src/app/models/properties-inputs/property-fe-model.ts +++ b/catalog-ui/src/app/models/properties-inputs/property-fe-model.ts @@ -228,7 +228,7 @@ export class PropertyFEModel extends PropertyBEModel { }; /* Returns array of individual parents for given prop path, with list/map UUIDs replaced with index/mapkey */ - public getParentNamesArray = (parentPropName: string, parentNames?: Array<string>): Array<string> => { + public getParentNamesArray = (parentPropName: string, parentNames?: Array<string>, noHashKeys:boolean = false): Array<string> => { parentNames = parentNames || []; if (parentPropName.indexOf("#") == -1) { return parentNames; } //finished recursing parents. return @@ -236,7 +236,7 @@ export class PropertyFEModel extends PropertyBEModel { let nameToInsert: string = parentProp.name; if (parentProp.isChildOfListOrMap) { - if (parentProp.derivedDataType == DerivedPropertyType.MAP) { + if (!noHashKeys && parentProp.derivedDataType == DerivedPropertyType.MAP) { nameToInsert = parentProp.getActualMapKey(); } else { //LIST let siblingProps = this.flattenedChildren.filter(prop => prop.parentName == parentProp.parentName).map(prop => prop.propertiesName); @@ -245,7 +245,7 @@ export class PropertyFEModel extends PropertyBEModel { } parentNames.splice(0, 0, nameToInsert); //add prop name to array - return this.getParentNamesArray(parentProp.parentName, parentNames); //continue recursing + return this.getParentNamesArray(parentProp.parentName, parentNames, noHashKeys); //continue recursing } public hasValueObjChanged() { diff --git a/catalog-ui/src/app/models/properties.ts b/catalog-ui/src/app/models/properties.ts index 7ff27706b0..a629140cb8 100644 --- a/catalog-ui/src/app/models/properties.ts +++ b/catalog-ui/src/app/models/properties.ts @@ -147,9 +147,10 @@ export class PropertyModel extends PropertyBEModel implements IPropertyModel { temp.simpleType = undefined; temp.value = temp.value === "{}" || temp.value === "[]" ? undefined : temp.value; temp.defaultValue = temp.defaultValue === "{}" || temp.defaultValue === "[]" ? undefined : temp.defaultValue; - temp.rules = null; //don't send rules to server until feature is fully supported + temp.rules = undefined; //don't send rules to server until feature is fully supported temp.isAlreadySelected = undefined; temp.addOn = undefined; + temp.filterTerm = undefined; return temp; }; } diff --git a/catalog-ui/src/app/models/ui-models/ui-base-object.ts b/catalog-ui/src/app/models/ui-models/ui-base-object.ts new file mode 100644 index 0000000000..a5989e4718 --- /dev/null +++ b/catalog-ui/src/app/models/ui-models/ui-base-object.ts @@ -0,0 +1,20 @@ +/** + * Created by ob0695 on 10.04.2018. + */ + +export interface IUiBaseObject { + name:string; + uniqueId:string; + type:any; +} +export class UiBaseObject implements IUiBaseObject{ + name:string; + uniqueId:string; + type:any; + + constructor(uniqueId: string, type?: any, name?:string) { + this.uniqueId = uniqueId; + this.name = name; + this.type = type; + } +}
\ No newline at end of file diff --git a/catalog-ui/src/app/models/ui-models/ui-member-object.ts b/catalog-ui/src/app/models/ui-models/ui-member-object.ts new file mode 100644 index 0000000000..92cda1bd7c --- /dev/null +++ b/catalog-ui/src/app/models/ui-models/ui-member-object.ts @@ -0,0 +1,9 @@ +import {IZoneInstanceAssignment} from "../graph/zones/zone-instance"; +import {UiBaseObject} from "./ui-base-object"; +import {TargetOrMemberType} from "../../utils/constants"; + +export class MemberUiObject extends UiBaseObject implements IZoneInstanceAssignment { + constructor(uniqueId: string, name:string) { + super(uniqueId, TargetOrMemberType.COMPONENT_INSTANCES, name); + } +}
\ No newline at end of file diff --git a/catalog-ui/src/app/models/ui-models/ui-target-object.ts b/catalog-ui/src/app/models/ui-models/ui-target-object.ts new file mode 100644 index 0000000000..e8a114e299 --- /dev/null +++ b/catalog-ui/src/app/models/ui-models/ui-target-object.ts @@ -0,0 +1,9 @@ +import {IZoneInstanceAssignment} from "../graph/zones/zone-instance"; +import {UiBaseObject} from "./ui-base-object"; +import {TargetOrMemberType} from "../../utils/constants"; + +export class TargetUiObject extends UiBaseObject implements IZoneInstanceAssignment { + constructor(uniqueId:string, type:TargetOrMemberType, name:string) { + super(uniqueId, type, name); + } +}
\ No newline at end of file diff --git a/catalog-ui/src/app/models/ui-models/ui-zone-instance-object.ts b/catalog-ui/src/app/models/ui-models/ui-zone-instance-object.ts new file mode 100644 index 0000000000..d8648f2c99 --- /dev/null +++ b/catalog-ui/src/app/models/ui-models/ui-zone-instance-object.ts @@ -0,0 +1,11 @@ +import { UiBaseObject } from "app/models/ui-models/ui-base-object"; +import { ZoneInstanceType } from "../graph/zones/zone-instance"; + + +export class UIZoneInstanceObject extends UiBaseObject{ + type:ZoneInstanceType; + + constructor(uniqueId: string, type?: ZoneInstanceType, name?:string) { + super(uniqueId, type, name); + } +}
\ No newline at end of file diff --git a/catalog-ui/src/app/modules/directive-module.ts b/catalog-ui/src/app/modules/directive-module.ts index 3b3a71609b..7892d5b43f 100644 --- a/catalog-ui/src/app/modules/directive-module.ts +++ b/catalog-ui/src/app/modules/directive-module.ts @@ -64,7 +64,7 @@ import {LinksFactory} from "../models/graph/graph-links/links-factory"; import {ImageCreatorService} from "../directives/graphs-v2/image-creator/image-creator.service"; import {Palette} from "../directives/graphs-v2/palette/palette.directive"; import {CompositionGraph} from "../directives/graphs-v2/composition-graph/composition-graph.directive"; -import {RelationMenuDirective} from "../directives/graphs-v2/relation-menu/relation-menu"; +// import {RelationMenuDirective} from "../directives/graphs-v2/relation-menu/relation-menu"; import {DeploymentGraph} from "../directives/graphs-v2/deployment-graph/deployment-graph.directive"; import {CommonGraphUtils} from "../directives/graphs-v2/common/common-graph-utils"; import {CompositionGraphNodesUtils} from "../directives/graphs-v2/composition-graph/utils/composition-graph-nodes-utils"; @@ -77,7 +77,7 @@ import {MatchCapabilitiesRequirementsUtils} from "../directives/graphs-v2/compos import {CapabilitiesListDirective} from "../directives/capabilities-and-requirements/capability/capabilities-list-directive"; import {RequirementsListDirective} from "../directives/capabilities-and-requirements/requirement/requirements-list-directive"; import {ServicePathGraphUtils} from "../directives/graphs-v2/composition-graph/utils/composition-graph-service-path-utils"; -import {PaletteAnimationComponent} from './../ng2/components/ui/palette-animation/palette-animation.component'; +import {PreventDoubleClickDirective} from "../directives/prevent-double-click/prevent-double-click"; let moduleName:string = 'Sdc.Directives'; let directiveModule:ng.IModule = angular.module(moduleName, []); @@ -91,7 +91,7 @@ directiveModule.directive('fileType', FileTypeDirective.factory); directiveModule.directive('invalidCharacters', InvalidCharactersDirective.factory); directiveModule.directive('perfectScrollbar', PerfectScrollerDirective.factory); directiveModule.directive('expandCollapse', ExpandCollapseDirective.factory); -directiveModule.directive('sdcModal', SdcModalDirective.factory); +directiveModule.directive('ng1Modal', SdcModalDirective.factory); directiveModule.directive('fileOpener', FileOpenerDirective.factory); directiveModule.directive('fileUpload', FileUploadDirective.factory); directiveModule.directive('structureTree', StructureTreeDirective.factory); @@ -113,17 +113,19 @@ directiveModule.directive('selectTypeMap', SelectTypeMapDirective.factory); directiveModule.directive('selectTypeList', SelectTypeListDirective.factory); directiveModule.directive('infoTooltip', InfoTooltipDirective.factory); directiveModule.directive('validationOnLoad', ValidationOnLoadDirective.factory); -directiveModule.directive('sdcTabs', SdcTabsDirective.factory); +directiveModule.directive('ng1Tabs', SdcTabsDirective.factory); directiveModule.directive('sdcSingleTab', SdcSingleTabDirective.factory); directiveModule.directive('innerSdcSingleTab', InnerSdcSingleTabDirective.factory); directiveModule.directive('jsonExportExcel', JsonExportExcelDirective.factory); directiveModule.directive('expandCollapseListHeader', ExpandCollapseListHeaderDirective.factory); +directiveModule.directive('preventDoubleClick', PreventDoubleClickDirective.factory); +// // // // Layouts directiveModule.directive('topProgress', TopProgressDirective.factory); // // // Elements -directiveModule.directive('sdcCheckbox', CheckboxElementDirective.factory); +directiveModule.directive('ng1Checkbox', CheckboxElementDirective.factory); directiveModule.directive('sdcRadioButton', RadiobuttonElementDirective.factory); // // // Events @@ -144,7 +146,7 @@ directiveModule.service('ImageCreatorService', ImageCreatorService); // //composition directiveModule.directive('palette', Palette.factory); directiveModule.directive('compositionGraph', CompositionGraph.factory); -directiveModule.directive('relationMenu', RelationMenuDirective.factory); +// directiveModule.directive('relationMenu', RelationMenuDirective.factory); //directiveModule.directive('assetPopover', AssetPopoverDirective.factory); // // //deployment @@ -178,13 +180,18 @@ import { MenuListNg2Component } from "../ng2/components/downgrade-wrappers/menu- import { TopNavComponent } from "../ng2/components/layout/top-nav/top-nav.component"; import { ZoneContainerComponent } from "../ng2/components/ui/canvas-zone/zone-container.component"; import { ZoneInstanceComponent } from "../ng2/components/ui/canvas-zone/zone-instance/zone-instance.component"; +import { CompositionPanelComponent } from 'app/ng2/pages/composition/panel/panel.component'; +import { CompositionPanelHeaderComponent } from 'app/ng2/pages/composition/panel/panel-header/panel-header.component'; import { PropertiesAssignmentComponent } from "../ng2/pages/properties-assignment/properties-assignment.page.component"; import { SearchWithAutoCompleteComponent } from "../ng2/components/ui/search-with-autocomplete/search-with-autocomplete.component"; import { PalettePopupPanelComponent } from "../ng2/components/ui/palette-popup-panel/palette-popup-panel.component"; import { ServicePathComponent } from '../ng2/components/logic/service-path/service-path.component'; import { ServicePathSelectorComponent } from '../ng2/components/logic/service-path-selector/service-path-selector.component'; +import { MultilineEllipsisComponent } from "../ng2/shared/multiline-ellipsis/multiline-ellipsis.component"; import { InterfaceOperationComponent } from '../ng2/pages/interface-operation/interface-operation.page.component'; import { PluginFrameComponent } from "../ng2/components/ui/plugin/plugin-frame.component"; +import { TileComponent } from "../ng2/components/ui/tile/tile.component"; + directiveModule.directive('menuListNg2', downgradeComponent({ component: MenuListNg2Component, @@ -193,20 +200,25 @@ directiveModule.directive('menuListNg2', downgradeComponent({ directiveModule.directive('topNav', downgradeComponent({ component: TopNavComponent, - inputs: ['version', 'menuModel', 'topLvlSelectedIndex', 'hideSearch', 'searchTerm', 'notificationIconCallback'], + inputs: ['version', 'menuModel', 'topLvlSelectedIndex', 'hideSearch', 'searchTerm', 'notificationIconCallback', 'unsavedChanges', 'unsavedChangesCallback'], outputs: ['searchTermChange'] }) as ng.IDirectiveFactory); directiveModule.directive('ng2ZoneContainer', downgradeComponent({ component: ZoneContainerComponent, - inputs: ['title', 'count', 'class', 'showZone', 'minifyZone'], - outputs: [] + inputs: ['title', 'count', 'type', 'visible', 'minimized'], + outputs: ['minimize', 'backgroundClick'] }) as angular.IDirectiveFactory); directiveModule.directive('ng2ZoneInstance', downgradeComponent({ - component: ZoneInstanceComponent, - inputs: ['config', 'isActive', 'activeInstanceMode', 'defaultIconText'], - outputs: ['modeChange'] + component: ZoneInstanceComponent, + inputs: ['zoneInstance', 'isActive', 'activeInstanceMode', 'defaultIconText', 'isViewOnly', 'hidden', 'forceSave'], + outputs: ['modeChange', 'tagHandleClick', 'assignmentSaveStart', 'assignmentSaveComplete'] +}) as angular.IDirectiveFactory); + +directiveModule.directive('ng2CompositionPanel', downgradeComponent({ + component: CompositionPanelComponent, + inputs: ['isViewOnly', 'isLoading', 'isCertified', 'selectedZoneInstanceId', 'selectedZoneInstanceType', 'selectedZoneInstanceName', 'topologyTemplate'], }) as angular.IDirectiveFactory); directiveModule.directive('propertiesAssignment', downgradeComponent({ @@ -219,12 +231,6 @@ directiveModule.directive('ng2SearchWithAutocomplete', downgradeComponent({ outputs: ['searchChanged', 'searchButtonClicked'] }) as angular.IDirectiveFactory); -directiveModule.directive('ng2PaletteAnimation', downgradeComponent({ - component: PaletteAnimationComponent, - inputs: ['from', 'to', 'icon' ], - outputs: [] - }) as angular.IDirectiveFactory); - directiveModule.directive('ng2PalettePopupPanel', downgradeComponent({ component: PalettePopupPanelComponent, inputs: [], @@ -233,7 +239,7 @@ directiveModule.directive('ng2PalettePopupPanel', downgradeComponent({ directiveModule.directive('ng2ServicePath', downgradeComponent({ component: ServicePathComponent, - inputs: ['onCreate', 'service'], + inputs: ['onCreate', 'service', 'isViewOnly'], outputs: [] }) as angular.IDirectiveFactory); @@ -249,6 +255,18 @@ directiveModule.directive('ng2InterfaceOperation', downgradeComponent({ outputs: [] }) as angular.IDirectiveFactory); +directiveModule.directive('ng2MultilineEllipsis', downgradeComponent({ + component: MultilineEllipsisComponent, + inputs: ['lines', 'lineHeight', 'className'], + outputs: ['hasEllipsisChanged'] +}) as angular.IDirectiveFactory); + +directiveModule.directive('ng2UiTile', downgradeComponent({ + component: TileComponent, + inputs: ['component'], + outputs: ['onTileClick'] +}) as angular.IDirectiveFactory); + directiveModule.directive('pluginFrame', downgradeComponent( { component: PluginFrameComponent, inputs: ['plugin', 'queryParams'], diff --git a/catalog-ui/src/app/modules/filters.ts b/catalog-ui/src/app/modules/filters.ts index 95fe583a04..fdce1e3e11 100644 --- a/catalog-ui/src/app/modules/filters.ts +++ b/catalog-ui/src/app/modules/filters.ts @@ -23,7 +23,6 @@ import {TrimFilter} from "../filters/trim-filter"; import {ResourceTypeFilter} from "../filters/resource-type-filter"; import {StringToDateFilter} from "../filters/string-to-date-filter"; import {CategoryTypeFilter} from "../filters/category-type-filter"; -import {CatalogStatusFilter} from "../filters/catalog-status-filter"; import {TruncateFilter} from "../filters/truncate-filter"; import {EntityFilter} from "../filters/entity-filter"; import {GraphResourceNameFilter} from "../filters/graph-resource-name-filter"; @@ -37,7 +36,6 @@ filterModule.filter("resourceName", ResourceNameFilter); filterModule.filter("graphResourceName", GraphResourceNameFilter); filterModule.filter("entityFilter", EntityFilter); filterModule.filter("truncate", TruncateFilter); -filterModule.filter("catalogStatusFilter", CatalogStatusFilter); filterModule.filter("categoryTypeFilter", CategoryTypeFilter); filterModule.filter("stringToDateFilter", StringToDateFilter); filterModule.filter("resourceTypeName", ResourceTypeFilter); diff --git a/catalog-ui/src/app/modules/service-module.ts b/catalog-ui/src/app/modules/service-module.ts index c934b630c8..f4350a39d4 100644 --- a/catalog-ui/src/app/modules/service-module.ts +++ b/catalog-ui/src/app/modules/service-module.ts @@ -46,22 +46,28 @@ import {LoaderService} from "../services/loader-service"; import {CategoryResourceService} from "../services/category-resource-service"; import {downgradeInjectable} from "@angular/upgrade/static"; import {ModalService} from "../ng2/services/modal.service"; +import {SdcUiComponents} from "sdc-ui/lib/angular"; import {ComponentServiceNg2} from "../ng2/services/component-services/component.service"; import {ServiceServiceNg2} from "../ng2/services/component-services/service.service"; import {ComponentServiceFactoryNg2} from "../ng2/services/component-services/component.service.factory"; import {ConnectionWizardService} from "../ng2/pages/connection-wizard/connection-wizard.service"; import {ComponentInstanceServiceNg2} from "../ng2/services/component-instance-services/component-instance.service"; import {UserService as UserServiceNg2} from "../ng2/services/user.service"; +import {PoliciesService as PoliciesServiceNg2} from "../ng2/services/policies.service"; +import {GroupsService as GroupsServiceNg2} from "../ng2/services/groups.service"; import {PluginsService} from "../ng2/services/plugins.service"; import {EventBusService} from "../ng2/services/event-bus.service"; -import {PoliciesService as PoliciesServiceNg2} from "../ng2/services/policies.service"; import {DynamicComponentService} from "app/ng2/services/dynamic-component.service"; +import {AutomatedUpgradeService} from "../ng2/pages/automated-upgrade/automated-upgrade.service"; +import {ArchiveService as ArchiveServiceNg2} from "app/ng2/services/archive.service"; +import {ComponentFactory} from "app/utils/component-factory"; let moduleName:string = 'Sdc.Services'; let serviceModule:ng.IModule = angular.module(moduleName, []); serviceModule.service('Sdc.Services.ConfigurationUiService', ConfigurationUiService); serviceModule.service('Sdc.Services.CookieService', CookieService); +serviceModule.service('Sdc.Services.ComponentFactory', ComponentFactory); // Why you need to declare it again, already done in utils.ts serviceModule.service('Sdc.Services.EntityService', EntityService); serviceModule.service('Sdc.Services.AvailableIconsService', AvailableIconsService); serviceModule.service('Sdc.Services.UrlToBase64Service', UrlToBase64Service); @@ -98,10 +104,14 @@ serviceModule.factory('ComponentServiceNg2', downgradeInjectable(ComponentServic serviceModule.factory('ComponentServiceFactoryNg2', downgradeInjectable(ComponentServiceFactoryNg2)); serviceModule.factory('ServiceServiceNg2', downgradeInjectable(ServiceServiceNg2)); serviceModule.factory('ModalServiceNg2', downgradeInjectable(ModalService)); +serviceModule.factory('ModalServiceSdcUI', downgradeInjectable(SdcUiComponents.ModalService)); serviceModule.factory('ConnectionWizardServiceNg2', downgradeInjectable(ConnectionWizardService)); serviceModule.factory('ComponentInstanceServiceNg2', downgradeInjectable(ComponentInstanceServiceNg2)); serviceModule.factory('UserServiceNg2', downgradeInjectable(UserServiceNg2)); +serviceModule.factory('PoliciesServiceNg2', downgradeInjectable(PoliciesServiceNg2)); +serviceModule.factory('GroupsServiceNg2', downgradeInjectable(GroupsServiceNg2)); serviceModule.factory('PluginsService', downgradeInjectable(PluginsService)); serviceModule.factory('EventBusService', downgradeInjectable(EventBusService)); -serviceModule.factory('PoliciesServiceNg2', downgradeInjectable(PoliciesServiceNg2)); serviceModule.factory('DynamicComponentService', downgradeInjectable(DynamicComponentService)); +serviceModule.factory('ArchiveServiceNg2', downgradeInjectable(ArchiveServiceNg2)); +serviceModule.factory('AutomatedUpgradeService', downgradeInjectable(AutomatedUpgradeService)); diff --git a/catalog-ui/src/app/modules/view-model-module.ts b/catalog-ui/src/app/modules/view-model-module.ts index de7d6d8a5d..b732be7eb0 100644 --- a/catalog-ui/src/app/modules/view-model-module.ts +++ b/catalog-ui/src/app/modules/view-model-module.ts @@ -67,8 +67,8 @@ import {ManagementWorkflowViewModel} from "../view-models/workspace/tabs/managem import {InterfaceOperationViewModel} from "../view-models/workspace/tabs/interface-operation/interface-operation-view-model"; import {NetworkCallFlowViewModel} from "../view-models/workspace/tabs/network-call-flow/network-call-flow-view-model"; import {DeploymentViewModel} from "../view-models/workspace/tabs/deployment/deployment-view-model"; -import {ResourceInputsViewModel} from "../view-models/workspace/tabs/inputs/resource-input/resource-inputs-view-model"; -import {ServiceInputsViewModel} from "../view-models/workspace/tabs/inputs/service-input/service-inputs-view-model"; +// import {ResourceInputsViewModel} from "../view-models/workspace/tabs/inputs/resource-input/resource-inputs-view-model"; +// import {ServiceInputsViewModel} from "../view-models/workspace/tabs/inputs/service-input/service-inputs-view-model"; import {ReqAndCapabilitiesViewModel} from "../view-models/workspace/tabs/req-and-capabilities/req-and-capabilities-view-model"; import {InputFormViewModel} from "../view-models/forms/input-form/input-form-view-modal"; import {HierarchyViewModel} from "../view-models/tabs/hierarchy/hierarchy-view-model"; @@ -135,8 +135,8 @@ viewModelModule .controller(moduleName + '.InterfaceOperationViewModel', InterfaceOperationViewModel) .controller(moduleName + '.NetworkCallFlowViewModel', NetworkCallFlowViewModel) .controller(moduleName + '.DeploymentViewModel', DeploymentViewModel) - .controller(moduleName + '.ResourceInputsViewModel', ResourceInputsViewModel) - .controller(moduleName + '.ServiceInputsViewModel', ServiceInputsViewModel) + // .controller(moduleName + '.ResourceInputsViewModel', ResourceInputsViewModel) + // .controller(moduleName + '.ServiceInputsViewModel', ServiceInputsViewModel) .controller(moduleName + '.ReqAndCapabilitiesViewModel', ReqAndCapabilitiesViewModel) .controller(moduleName + '.InputFormViewModel', InputFormViewModel) .controller(moduleName + '.PluginsTabViewModel', PluginsTabViewModel) diff --git a/catalog-ui/src/app/ng2/app.module.ts b/catalog-ui/src/app/ng2/app.module.ts index c3cd06043b..c949a73248 100644 --- a/catalog-ui/src/app/ng2/app.module.ts +++ b/catalog-ui/src/app/ng2/app.module.ts @@ -18,51 +18,61 @@ * ============LICENSE_END========================================================= */ -import {BrowserModule} from '@angular/platform-browser'; -import {NgModule, APP_INITIALIZER} from '@angular/core'; -import {FormsModule} from '@angular/forms'; -import {forwardRef} from '@angular/core'; -import {AppComponent} from './app.component'; -import {UpgradeAdapter} from '@angular/upgrade'; -import {UpgradeModule} from '@angular/upgrade/static'; -import {PropertiesAssignmentModule} from './pages/properties-assignment/properties-assignment.module'; +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule, APP_INITIALIZER } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { forwardRef } from '@angular/core'; +import { AppComponent } from './app.component'; +import { UpgradeAdapter } from '@angular/upgrade'; +import { UpgradeModule } from '@angular/upgrade/static'; +import { SdcUiComponentsModule, SdcUiComponents } from "sdc-ui/lib/angular"; +import { PropertiesAssignmentModule } from './pages/properties-assignment/properties-assignment.module'; import { DataTypesServiceProvider, SharingServiceProvider, CookieServiceProvider, StateServiceFactory, StateParamsServiceFactory, CacheServiceProvider, EventListenerServiceProvider, ScopeServiceFactory, - NotificationServiceProvider + NotificationServiceProvider, ComponentFactoryProvider } from "./utils/ng1-upgraded-provider"; -import {ConfigService} from "./services/config.service"; -import {HttpModule} from '@angular/http'; -import {HttpService} from './services/http.service'; -import {AuthenticationService} from './services/authentication.service'; -import {Cookie2Service} from "./services/cookie.service"; -import {ComponentServiceNg2} from "./services/component-services/component.service"; -import {ComponentServiceFactoryNg2} from "./services/component-services/component.service.factory"; -import {ServiceServiceNg2} from "./services/component-services/service.service"; -import {ComponentInstanceServiceNg2} from "./services/component-instance-services/component-instance.service"; -import {ModalService} from "./services/modal.service"; -import {UiElementsModule} from "./components/ui/ui-elements.module"; -import {ConnectionWizardModule} from "./pages/connection-wizard/connection-wizard.module"; +import { ConfigService } from "./services/config.service"; +import { HttpModule } from '@angular/http'; +import { HttpService } from './services/http.service'; +import { AuthenticationService } from './services/authentication.service'; +import { Cookie2Service } from "./services/cookie.service"; +import { ComponentServiceNg2 } from "./services/component-services/component.service"; +import { ComponentServiceFactoryNg2 } from "./services/component-services/component.service.factory"; +import { ServiceServiceNg2 } from "./services/component-services/service.service"; +import { ComponentInstanceServiceNg2 } from "./services/component-instance-services/component-instance.service"; +import { ModalService } from "./services/modal.service"; +import { UiElementsModule } from "./components/ui/ui-elements.module"; +import { ConnectionWizardModule } from "./pages/connection-wizard/connection-wizard.module"; import {InterfaceOperationModule} from "./pages/interface-operation/interface-operation.module"; import {OperationCreatorModule} from "./pages/interface-operation/operation-creator/operation-creator.module"; -import {LayoutModule} from "./components/layout/layout.module"; -import {UserService} from "./services/user.service"; -import {PoliciesService} from "./services/policies.service"; -import {DynamicComponentService} from "./services/dynamic-component.service"; -import {SdcConfig} from "./config/sdc-config.config"; +import { LayoutModule } from "./components/layout/layout.module"; +import { UserService } from "./services/user.service"; +import { DynamicComponentService } from "./services/dynamic-component.service"; +import { SdcConfig } from "./config/sdc-config.config"; +import { SdcMenu } from "./config/sdc-menu.config"; import { TranslateModule } from "./shared/translator/translate.module"; import { TranslationServiceConfig } from "./config/translation.service.config"; -import {ServicePathCreatorModule} from './pages/service-path-creator/service-path-creator.module'; -import {ServicePathsListModule} from './pages/service-paths-list/service-paths-list.module'; +import { MultilineEllipsisModule } from "./shared/multiline-ellipsis/multiline-ellipsis.module"; +import { ServicePathCreatorModule } from './pages/service-path-creator/service-path-creator.module'; +import { ServicePathsListModule } from './pages/service-paths-list/service-paths-list.module'; +import { ServicePathModule } from 'app/ng2/components/logic/service-path/service-path.module'; +import { ServicePathSelectorModule } from 'app/ng2/components/logic/service-path-selector/service-path-selector.module'; +import { CompositionPanelModule } from 'app/ng2/pages/composition/panel/panel.module'; +import { WindowRef } from "./services/window.service"; +import {ArchiveService} from "./services/archive.service"; +import { ModalsHandlerProvider } from './utils/ng1-upgraded-provider'; import {PluginFrameModule} from "./components/ui/plugin/plugin-frame.module"; import {PluginsService} from "./services/plugins.service"; import {EventBusService} from "./services/event-bus.service"; -import {ServicePathModule} from 'app/ng2/components/logic/service-path/service-path.module'; -import {ServicePathSelectorModule} from 'app/ng2/components/logic/service-path-selector/service-path-selector.module'; +import {GroupsService} from "./services/groups.service"; +import {PoliciesService} from "./services/policies.service"; +import {AutomatedUpgradeService} from "./pages/automated-upgrade/automated-upgrade.service"; +import {AutomatedUpgradeModule} from "./pages/automated-upgrade/automated-upgrade.module"; export const upgradeAdapter = new UpgradeAdapter(forwardRef(() => AppModule)); -export function configServiceFactory(config:ConfigService) { +export function configServiceFactory(config: ConfigService) { return () => { return Promise.all([ config.loadValidationConfiguration(), @@ -83,8 +93,11 @@ export function configServiceFactory(config:ConfigService) { HttpModule, LayoutModule, TranslateModule, + MultilineEllipsisModule, UiElementsModule, - + CompositionPanelModule, + SdcUiComponentsModule, + AutomatedUpgradeModule, //We need to import them here since we use them in angular1 ConnectionWizardModule, PropertiesAssignmentModule, @@ -97,10 +110,15 @@ export function configServiceFactory(config:ConfigService) { ServicePathSelectorModule ], exports: [], - entryComponents: [], + entryComponents: [ + // *** sdc-ui components to be used as downgraded: + // SdcUiComponents.ButtonComponent + ], providers: [ + WindowRef, DataTypesServiceProvider, SharingServiceProvider, + ComponentFactoryProvider, CookieServiceProvider, StateServiceFactory, StateParamsServiceFactory, @@ -108,6 +126,7 @@ export function configServiceFactory(config:ConfigService) { CacheServiceProvider, EventListenerServiceProvider, NotificationServiceProvider, + ModalsHandlerProvider, AuthenticationService, Cookie2Service, ConfigService, @@ -115,14 +134,18 @@ export function configServiceFactory(config:ConfigService) { ComponentServiceFactoryNg2, ModalService, ServiceServiceNg2, + AutomatedUpgradeService, HttpService, UserService, PoliciesService, + GroupsService, DynamicComponentService, SdcConfig, + SdcMenu, ComponentInstanceServiceNg2, TranslationServiceConfig, PluginsService, + ArchiveService, EventBusService, { provide: APP_INITIALIZER, @@ -130,13 +153,13 @@ export function configServiceFactory(config:ConfigService) { deps: [ConfigService], multi: true }, - ], + ], bootstrap: [AppComponent] }) export class AppModule { + constructor(public upgrade: UpgradeModule, public eventBusService:EventBusService) { - constructor(public upgrade:UpgradeModule, eventBusService:EventBusService) { } } diff --git a/catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.html b/catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.html index 55c4bf0460..78f311112e 100644 --- a/catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.html +++ b/catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.html @@ -20,7 +20,7 @@ <li [ngClass]="{'selected': $last }"> <a (click)="menuItemClick(groupItem, groupItem.menuItems[groupItem.selectedIndex])" [attr.data-tests-id]="'breadcrumbs-button-' + $index"> - {{groupItem.menuItems[groupItem.selectedIndex].text}} + {{groupItem.menuItems[groupItem.selectedIndex]?.text}} </a> </li> <li class="triangle-dropdown" diff --git a/catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.ts b/catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.ts index a0b6b2b543..881a91613d 100644 --- a/catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.ts +++ b/catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.ts @@ -41,6 +41,8 @@ export class TopNavComponent { @Input() public hideSearch:boolean; @Input() public searchTerm:string; @Input() public notificationIconCallback:Function; + @Input() public unsavedChanges: boolean; + @Input() public unsavedChangesCallback: (completeCallback:Function)=> Promise<any>; @Output() public searchTermChange:EventEmitter<string> = new EventEmitter<string>(); emitSearchTerm(event:string) { this.searchTermChange.emit(event); @@ -80,17 +82,21 @@ export class TopNavComponent { return true; }); - //if it's a different state , checking previous state param + //if it's a different state if (result === -1) { - this.topLvlMenu.menuItems.forEach((item:MenuItem, index:number)=> { - if (item.state === this.$state.params['previousState']) { - result = index; - } - }); - } + //if in 'workspace' - checking previous state param + if (this.$state.includes('workspace')) { + // if previous state is 'dashboard' or 'catalog', then select it - otherwise, use 'catalog' as default for 'workspace' + const selectedStateName = (['dashboard', 'catalog'].indexOf(this.$state.params['previousState']) !== -1) + ? this.$state.params['previousState'] + : 'catalog'; + result = this.topLvlMenu.menuItems.findIndex((item:MenuItem) => item.state === selectedStateName); + } - if (result === -1) { - result = 0; + //if yet, none is selected, then select the first as default + if (result === -1) { + result = 0; + } } return result; @@ -151,8 +157,21 @@ export class TopNavComponent { } menuItemClick(itemGroup:MenuItemGroup, item:MenuItem) { - itemGroup.itemClick = false; + let onSuccessFunction = () => { + this.navigate(itemGroup, item); + } + if (this.unsavedChanges && this.unsavedChangesCallback){ + this.unsavedChangesCallback(onSuccessFunction).then((onSuccess)=> { + this.navigate(itemGroup, item); + }, (onReject) => {}); + } else { + this.navigate(itemGroup, item); + } + } + + navigate(itemGroup:MenuItemGroup, item:MenuItem) { + itemGroup.itemClick = false; let onSuccess = ():void => { itemGroup.selectedIndex = itemGroup.menuItems.indexOf(item); }; @@ -165,4 +184,5 @@ export class TopNavComponent { this[item.action](item.state, item.params).then(onSuccess, onFailed); } } + } diff --git a/catalog-ui/src/app/ng2/components/logic/hierarchy-navigtion/hierarchy-display-options.ts b/catalog-ui/src/app/ng2/components/logic/hierarchy-navigtion/hierarchy-display-options.ts index c8d4566653..36257ca94e 100644 --- a/catalog-ui/src/app/ng2/components/logic/hierarchy-navigtion/hierarchy-display-options.ts +++ b/catalog-ui/src/app/ng2/components/logic/hierarchy-navigtion/hierarchy-display-options.ts @@ -23,10 +23,16 @@ export class HierarchyDisplayOptions { valueProperty: string; childrenProperty: string; searchText:string; - constructor(idProperty:string, valueProperty:string, childrenProperty?:string, searchText?:string) { + archived:boolean; + + iconProperty: string; + constructor(idProperty:string, valueProperty:string, childrenProperty?:string, searchText?:string, iconProperty?:string, archived?:boolean) { + this.idProperty = idProperty; this.valueProperty = valueProperty; this.childrenProperty = childrenProperty; this.searchText = searchText; + this.archived = archived; + this.iconProperty = iconProperty; } } diff --git a/catalog-ui/src/app/ng2/components/logic/hierarchy-navigtion/hierarchy-navigation.component.html b/catalog-ui/src/app/ng2/components/logic/hierarchy-navigtion/hierarchy-navigation.component.html index c3f9e5ac74..aa60337f84 100644 --- a/catalog-ui/src/app/ng2/components/logic/hierarchy-navigtion/hierarchy-navigation.component.html +++ b/catalog-ui/src/app/ng2/components/logic/hierarchy-navigtion/hierarchy-navigation.component.html @@ -1,7 +1,12 @@ <div class="navigation-wrapper"> <div class="node-item" *ngFor="let item of displayData" (click)="onClick($event, item)"> <div class="node-data-wrapper" [ngClass]="{'selected': selectedItem && selectedItem === item[displayOptions.idProperty]}"> - <span class="node-data" [ngClass]="{'mark':item[displayOptions.valueProperty] === displayOptions.searchText}" [attr.data-tests-id]="item[displayOptions.valueProperty]">{{item[displayOptions.valueProperty]}}</span> + <span class="node-data" [ngClass]="{'mark':item[displayOptions.valueProperty] === displayOptions.searchText}" [attr.data-tests-id]="item[displayOptions.valueProperty]"> + + <span *ngIf="displayOptions.iconProperty" [ngClass]="['node-data-icon', item[displayOptions.iconProperty], 'small']"></span> + {{item[displayOptions.valueProperty]}} + <span class="sprite-new archive-label" *ngIf="item.originArchived"></span> + </span> </div> <div class="children-node" *ngIf="item[displayOptions.childrenProperty]"> <hierarchy-navigation class="children-hierarchy" [displayData]="item[displayOptions.childrenProperty]" diff --git a/catalog-ui/src/app/ng2/components/logic/hierarchy-navigtion/hierarchy-navigation.component.less b/catalog-ui/src/app/ng2/components/logic/hierarchy-navigtion/hierarchy-navigation.component.less index 4befa2c797..33ffb49537 100644 --- a/catalog-ui/src/app/ng2/components/logic/hierarchy-navigtion/hierarchy-navigation.component.less +++ b/catalog-ui/src/app/ng2/components/logic/hierarchy-navigtion/hierarchy-navigation.component.less @@ -1,3 +1,5 @@ +@import './../../../../../assets/styles/mixins.less'; + .navigation-wrapper { text-align: left; } @@ -30,6 +32,25 @@ .node-data { margin-left: 10px; margin-right: 10px; + align-items: center; + display: block; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 300px; + .archive-label{ + margin-left: 5px; + } +} + +.node-data-icon { + vertical-align: middle; + margin-right: 7px; + + &.defaulticon.small { + background-color: #999; + border-radius: 14px; + } } .node-data-wrapper.selected { @@ -50,3 +71,20 @@ +.icon-group { + .square-icon(); + background-color: @main_color_a; + + &::before { + content: "G"; + } +} +.icon-policy { + .square-icon(); + background-color: @main_color_r; + + &::before { + content: "P"; + } +} + diff --git a/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.html b/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.html index b7cde7eb23..daffc9efea 100644 --- a/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.html +++ b/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.html @@ -17,8 +17,8 @@ tooltip="{{input.description}}" tooltipDelay="0"></span> </div> <div class="table-cell col3"> - <div class="inner-cell-div" tooltip="{{instanceNamesMap[input.instanceUniqueId]}}"> - <span>{{instanceNamesMap[input.instanceUniqueId]}}</span> + <div class="inner-cell-div" tooltip="{{instanceNamesMap[input.instanceUniqueId]?.name}}"> + <span>{{instanceNamesMap[input.instanceUniqueId]?.name}}</span> </div> </div> <div class="table-cell col2"> @@ -34,7 +34,8 @@ [type]="input.type" [name]="input.name" (elementChanged)="onInputChanged(input, $event)" - [readonly]="readonly"> + [readonly]="readonly" + [testId]="'input-' + input.name"> </dynamic-element> <div class="delete-button-container"> <span *ngIf="input.instanceUniqueId && !readonly" class="sprite-new delete-btn" (click)="openDeleteModal(input)" data-tests-id="delete-input-button"></span> diff --git a/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.less b/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.less index d709f3f0c5..5fbb62f7fb 100644 --- a/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.less +++ b/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.less @@ -85,8 +85,8 @@ border-right:#d2d2d2 solid 1px; } &.col1 { - flex: 1 0 210px; - max-width:210px; + flex: 1 0 120px; + max-width:120px; display: flex; justify-content: space-between; @@ -112,14 +112,7 @@ } &.valueCol { - flex: 1 0 auto; - min-width: 350px; - display: flex; - justify-content: flex-end; - padding: 0px; - align-items: center; - - .value-input { + .value-input { flex: 1; border: none; background-color: inherit; @@ -142,7 +135,7 @@ padding: 0px; .delete-button-container { - padding: 3px 5px 0 0 ; + padding: 0 8px 0 0 ; } } } diff --git a/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.ts b/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.ts index ebecbc9390..0c7fc2a24c 100644 --- a/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.ts +++ b/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.ts @@ -24,6 +24,7 @@ import {Component, Input, Output, EventEmitter} from "@angular/core"; import {InputFEModel} from "app/models"; import {ModalService} from "../../../services/modal.service"; +import { InstanceFeDetails } from "app/models/instance-fe-details"; @Component({ selector: 'inputs-table', @@ -33,7 +34,7 @@ import {ModalService} from "../../../services/modal.service"; export class InputsTableComponent { @Input() inputs: Array<InputFEModel>; - @Input() instanceNamesMap: Map<string, string>; + @Input() instanceNamesMap: Map<string, InstanceFeDetails>; @Input() readonly:boolean; @Input() isLoading:boolean; @Output() inputChanged: EventEmitter<any> = new EventEmitter<any>(); diff --git a/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.html b/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.html index 4805875d83..b5ae7a8f66 100644 --- a/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.html +++ b/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.html @@ -19,6 +19,7 @@ [name]="property.name" (elementChanged)="mapKeyChanged.emit($event.value)" [readonly]="readonly" + [testId]="'prop-key-' + propertyTestsId" ></dynamic-element> </div> </ng-container> @@ -27,12 +28,13 @@ <div class="table-cell"> <dynamic-element class="value-input" pattern="validationUtils.getValidationPattern(property.type)" - [value]="property.valueObj" + [value]="property.isDeclared ? property.value : property.valueObj" [type]="property.isDeclared ? 'string' : property.type" [name]="property.name" [path]="property.propertiesName" (elementChanged)="onElementChanged($event)" [readonly]="readonly || property.isDeclared || property.isDisabled" + [testId]="'prop-' + propertyTestsId" ></dynamic-element> </div> </ng-container> @@ -45,9 +47,9 @@ </ng-container> <!-- ICONS: add, delete, and expand --> <ng-container *ngIf="!property.isDeclared"> - <a *ngIf="(propType == derivedPropertyTypes.LIST || propType == derivedPropertyTypes.MAP) && !property.isChildOfListOrMap" class="property-icon add-item" (click)="createNewChildProperty();" [ngClass]="{'disabled':readonly || preventInsertItem(property)}">Add value to list</a> - <span *ngIf="property.isChildOfListOrMap" (click)="deleteItem.emit(property);" class="property-icon sprite-new delete-item-icon" [ngClass]="{'disabled':readonly}"></span> - <span *ngIf="!isPropertyFEModel && (propType == derivedPropertyTypes.COMPLEX || ((propType == derivedPropertyTypes.LIST || propType == derivedPropertyTypes.MAP) && hasChildren))" (click)="expandChildById(propPath)" class="property-icon sprite-new round-expand-icon" [class.open]="expandedChildId.indexOf(propPath) == 0"></span> + <a *ngIf="(propType == derivedPropertyTypes.LIST || propType == derivedPropertyTypes.MAP) && !property.isChildOfListOrMap" class="property-icon add-item" (click)="createNewChildProperty();" [ngClass]="{'disabled':readonly || preventInsertItem(property)}" [attr.data-tests-id]="'add-to-list-' + propertyTestsId">Add value to list</a> + <span *ngIf="property.isChildOfListOrMap" (click)="deleteItem.emit(property);" class="property-icon sprite-new delete-item-icon" [ngClass]="{'disabled':readonly}" [attr.data-tests-id]="'delete-from-list-' + propertyTestsId"></span> + <span *ngIf="!isPropertyFEModel && (propType == derivedPropertyTypes.COMPLEX || ((propType == derivedPropertyTypes.LIST || propType == derivedPropertyTypes.MAP) && hasChildren))" (click)="expandChildById(propPath)" class="property-icon sprite-new round-expand-icon" [class.open]="expandedChildId.indexOf(propPath) == 0" [attr.data-tests-id]="'expand-' + propertyTestsId"></span> </ng-container> </div> @@ -59,6 +61,7 @@ [hasDeclareOption]="hasDeclareOption" [canBeDeclared]="hasDeclareOption && prop.canBeDeclared" [property]="prop" + [rootProperty]="rootProperty || property" [expandedChildId]="expandedChildId" [propertyNameSearchText]="propertyNameSearchText" [readonly]="readonly" diff --git a/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.ts b/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.ts index 6f7e57b643..6e19c95003 100644 --- a/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.ts +++ b/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.ts @@ -41,6 +41,7 @@ export class DynamicPropertyComponent { propPath: string; isPropertyFEModel: boolean; nestedLevel: number; + propertyTestsId: string; @Input() canBeDeclared: boolean; @Input() property: PropertyFEModel | DerivedFEProperty; @@ -50,6 +51,7 @@ export class DynamicPropertyComponent { @Input() readonly: boolean; @Input() hasChildren: boolean; @Input() hasDeclareOption:boolean; + @Input() rootProperty: PropertyFEModel; @Output('propertyChanged') emitter: EventEmitter<void> = new EventEmitter<void>(); @Output() expandChild: EventEmitter<string> = new EventEmitter<string>(); @@ -69,6 +71,8 @@ export class DynamicPropertyComponent { this.propType = this.property.derivedDataType; this.propPath = (this.property instanceof PropertyFEModel) ? this.property.name : this.property.propertiesName; this.nestedLevel = (this.property.propertiesName.match(/#/g) || []).length; + this.rootProperty = (this.rootProperty) ? this.rootProperty : <PropertyFEModel>this.property; + this.propertyTestsId = this.getPropertyTestsId(); } ngDoCheck() { @@ -105,6 +109,10 @@ export class DynamicPropertyComponent { }).length > 1; } + getPropertyTestsId = () => { + return [this.rootProperty.name].concat(this.rootProperty.getParentNamesArray(this.property.propertiesName, [], true)).join('.'); + }; + onElementChanged = (event: IUiElementChangeEvent) => { this.property.updateValueObj(event.value, event.isValid); this.emitter.emit(); diff --git a/catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.html b/catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.html index ecfa7e7c5e..b574b552ae 100644 --- a/catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.html +++ b/catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.html @@ -9,8 +9,14 @@ <div class="table-body" [ngClass]="{'view-mode': readonly}"> <div class="no-data" *ngIf="!fePropertiesMap || !(fePropertiesMap | keys).length">No data to display</div> - <ng-container *ngFor="let instanceId of fePropertiesMap | keys; trackBy:instanceId"> - <div class="table-rows-header white-sub-header" *ngIf="feInstanceNamesMap">{{feInstanceNamesMap[instanceId]}}</div> + <ng-container *ngFor="let instanceId of fePropertiesMap | keys; trackBy:vspId"> + <div class="table-rows-header white-sub-header" *ngIf="feInstanceNamesMap"> + + + <span [ngClass]="['prop-instance-icon', feInstanceNamesMap[instanceId].iconClass, 'small']"></span> + {{feInstanceNamesMap[instanceId].name}} + <div class="sprite-new archive-label" *ngIf="feInstanceNamesMap[instanceId].originArchived == true" ></div> + </div> <div class="table-row" *ngFor="let property of fePropertiesMap[instanceId] | searchFilter:'name':searchTerm; trackBy:property?.name" @@ -22,8 +28,8 @@ <checkbox *ngIf="hasDeclareOption" [(checked)]="property.isSelected" [disabled]="property.isDisabled || property.isDeclared || readonly" (checkedChange)="propertyChecked(property)" [attr.data-tests-id]="property.name"></checkbox> - <div class="inner-cell-div" tooltip="{{property.name}}"> - <span>{{property.name}}</span> + <div class="inner-cell-div-multiline" tooltip="{{property.name}}"> + <multiline-ellipsis className="table-cell-multiline-ellipsis" [lines]="2">{{property.name}}</multiline-ellipsis> </div> </div> <span *ngIf="property.description" class="property-description-icon sprite-new show-desc" tooltip="{{property.description}}" tooltipDelay="0"></span> diff --git a/catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.less b/catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.less index 20da0b6ec2..72f67e434e 100644 --- a/catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.less +++ b/catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.less @@ -1,4 +1,4 @@ -@import './../../../../../assets/styles/variables.less'; +@import './../../../../../assets/styles/mixins.less'; @import '../../../../../assets/styles/sprite'; @smaller-screen: ~"only screen and (max-width: 1580px)"; @@ -12,13 +12,16 @@ text-align:left; - .inner-cell-div{ - max-width: 100%; + .inner-cell-div { text-overflow: ellipsis; overflow: hidden; height: 20px; } + .inner-cell-div-multiline { + max-width: 100%; + } + .table-header { display: flex; flex-direction:row; @@ -36,6 +39,11 @@ .table-rows-header { border: #d2d2d2 solid 1px; border-top:none; + display: flex; + align-items: center; + .archive-label{ + margin-left: 10px; + } } .table-body { @@ -120,7 +128,7 @@ .property-description-icon { float: right; margin-top: 4px; - margin-left: 5px; + margin-left: 15px; flex: 0 0 auto; } } @@ -177,4 +185,53 @@ } } + .table-row { + /deep/ .table-cell-multiline-ellipsis .multiline-ellipsis-dots { + background: linear-gradient(to right, transparent 0%, #ffffff 80%); + padding-left: 1em; + } + + &.selected /deep/ .table-cell-multiline-ellipsis .multiline-ellipsis-dots { + background: linear-gradient(to right, transparent 0%, #e6f6fb 80%); + padding-left: 1em; + } + + &.readonly /deep/ .table-cell-multiline-ellipsis .multiline-ellipsis-dots { + background: linear-gradient(to right, transparent 0%, #f8f8f8 80%); + padding-left: 1em; + } + + &:hover:not(.selected) /deep/ .table-cell-multiline-ellipsis .multiline-ellipsis-dots { + background: linear-gradient(to right, transparent 0%, #f8f8f8 80%); + padding-left: 1em; + } + } + + .prop-instance-icon { + vertical-align: middle; + margin-right: 7px; + &.defaulticon.small { + background-color: @main_color_q; + border-radius:14px; + } + // square icons + + &.icon-group { + .square-icon(); + background-color: @main_color_a; + + &::before { + content: "G"; + } + } + &.icon-policy { + .square-icon(); + background-color: @main_color_r; + + &::before { + content: "P"; + } + } + + } } diff --git a/catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.ts b/catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.ts index 093fae1684..da1fb82ba0 100644 --- a/catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.ts +++ b/catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.ts @@ -21,6 +21,7 @@ import { Component, Input, Output, EventEmitter} from "@angular/core"; import {PropertyFEModel, DerivedFEProperty, InstanceFePropertiesMap} from "app/models"; import {PropertiesService} from "../../../services/properties.service"; +import { InstanceFeDetails } from "../../../../models/instance-fe-details"; @Component({ selector: 'properties-table', @@ -30,7 +31,7 @@ import {PropertiesService} from "../../../services/properties.service"; export class PropertiesTableComponent { @Input() fePropertiesMap: InstanceFePropertiesMap; - @Input() feInstanceNamesMap: Map<string, string>; + @Input() feInstanceNamesMap: Map<string, InstanceFeDetails>; @Input() selectedPropertyId: string; @Input() propertyNameSearchText:string; @Input() searchTerm:string; diff --git a/catalog-ui/src/app/ng2/components/logic/properties-table/property-table.module.ts b/catalog-ui/src/app/ng2/components/logic/properties-table/property-table.module.ts index 91f33485a9..91baaf1bc1 100644 --- a/catalog-ui/src/app/ng2/components/logic/properties-table/property-table.module.ts +++ b/catalog-ui/src/app/ng2/components/logic/properties-table/property-table.module.ts @@ -8,6 +8,7 @@ import {HttpModule} from "@angular/http"; import {FilterChildPropertiesPipe} from "./pipes/filterChildProperties.pipe"; import {GlobalPipesModule} from "../../../pipes/global-pipes.module"; import {PropertiesService} from "../../../services/properties.service"; +import {MultilineEllipsisModule} from "../../../shared/multiline-ellipsis/multiline-ellipsis.module"; @NgModule({ imports: [ @@ -15,7 +16,8 @@ import {PropertiesService} from "../../../services/properties.service"; HttpModule, CommonModule, GlobalPipesModule, - UiElementsModule + UiElementsModule, + MultilineEllipsisModule ], declarations: [ FilterChildPropertiesPipe, diff --git a/catalog-ui/src/app/ng2/components/logic/select-requirement-or-capability/select-requirement-or-capability.component.html b/catalog-ui/src/app/ng2/components/logic/select-requirement-or-capability/select-requirement-or-capability.component.html index 6e0f93f750..9d570f036a 100644 --- a/catalog-ui/src/app/ng2/components/logic/select-requirement-or-capability/select-requirement-or-capability.component.html +++ b/catalog-ui/src/app/ng2/components/logic/select-requirement-or-capability/select-requirement-or-capability.component.html @@ -9,7 +9,7 @@ </radio-buttons> <label class="select-type-label">Select type:</label> <div class="select-type"> - <ui-element-dropdown [values]="types" [(value)]="selectedType" (valueChange)="onTypeSelected($event)"></ui-element-dropdown> + <ui-element-dropdown [values]="types" [(value)]="selectedType" (valueChange)="onTypeSelected($event)" testId="select"></ui-element-dropdown> </div> <div class="table-and-list-container"> diff --git a/catalog-ui/src/app/ng2/components/logic/service-path-selector/service-path-selector.component.html b/catalog-ui/src/app/ng2/components/logic/service-path-selector/service-path-selector.component.html index 72e083534c..af7a470495 100644 --- a/catalog-ui/src/app/ng2/components/logic/service-path-selector/service-path-selector.component.html +++ b/catalog-ui/src/app/ng2/components/logic/service-path-selector/service-path-selector.component.html @@ -1,5 +1,5 @@ <div class="service-path-selector"> - <label>Service Paths:</label> + <label>Service Flows:</label> <ui-element-dropdown class="path-dropdown" data-tests-id="service-path-selector" diff --git a/catalog-ui/src/app/ng2/components/logic/service-path-selector/service-path-selector.component.ts b/catalog-ui/src/app/ng2/components/logic/service-path-selector/service-path-selector.component.ts index be9966acef..e09001fc6c 100644 --- a/catalog-ui/src/app/ng2/components/logic/service-path-selector/service-path-selector.component.ts +++ b/catalog-ui/src/app/ng2/components/logic/service-path-selector/service-path-selector.component.ts @@ -1,4 +1,3 @@ -import * as _ from "lodash"; import {Component, Input, KeyValueDiffer, IterableDiffers, KeyValueDiffers, DoCheck} from '@angular/core'; import {Service} from "app/models/components/service"; import {TranslateService} from "app/ng2/shared/translator/translate.service"; diff --git a/catalog-ui/src/app/ng2/components/logic/service-path/service-path.component.html b/catalog-ui/src/app/ng2/components/logic/service-path/service-path.component.html index ff7902e2b9..75f064230c 100644 --- a/catalog-ui/src/app/ng2/components/logic/service-path/service-path.component.html +++ b/catalog-ui/src/app/ng2/components/logic/service-path/service-path.component.html @@ -1,22 +1,15 @@ <div class='service-path'> <button class='zoom-icons create-path-button' data-tests-id="pathsMenuBtn" (click)="showServicePathMenu = !showServicePathMenu">...</button> - <div class="service-path-menu" - *ngIf="showServicePathMenu" > + <div class="service-path-menu" *ngIf="showServicePathMenu"> <div > <ul> - <li><div class="hand" (click)="onCreateServicePath()" data-tests-id="createPathMenuItem"> - Create Service Path + <li *ngIf='!isViewOnly'><div class="hand" (click)="onCreateServicePath()" data-tests-id="createPathMenuItem"> + Create Service Flow </div></li> <li><div class="hand" (click)="onListServicePath()" data-tests-id="pathsListMenuItem"> - Service Paths List + Service Flows List </div></li> </ul> </div> </div> - <!-- TODO - ask Orit about positioning issues and styling issues --> - <!-- - <menu-list [open]="showServicePathMenu" [position]="menuPos" > - <menu-item [action]="onCreateServicePath">Create Path</menu-item> - <menu-item [action]="onListServicePath">Paths' List</menu-item> - </menu-list> --> </div>
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/components/logic/service-path/service-path.component.ts b/catalog-ui/src/app/ng2/components/logic/service-path/service-path.component.ts index 4a6209fb6f..d66c5f0132 100644 --- a/catalog-ui/src/app/ng2/components/logic/service-path/service-path.component.ts +++ b/catalog-ui/src/app/ng2/components/logic/service-path/service-path.component.ts @@ -39,6 +39,7 @@ export class ServicePathComponent { @Input() service: Service; @Input() onCreate: Function; @Input() onSave: Function; + @Input() isViewOnly:boolean; constructor(private ModalServiceNg2: ModalService) {} @@ -46,7 +47,7 @@ export class ServicePathComponent { this.showServicePathMenu = false; let cancelButton: ButtonModel = new ButtonModel('Cancel', 'outline white', this.ModalServiceNg2.closeCurrentModal); let saveButton: ButtonModel = new ButtonModel('Create', 'blue', this.createPath, this.getDisabled ); - let modalModel: ModalModel = new ModalModel('l', 'Create Service Path', '', [saveButton, cancelButton], 'standard', true); + let modalModel: ModalModel = new ModalModel('l', 'Create Service Flow', '', [saveButton, cancelButton], 'standard', true); this.modalInstance = this.ModalServiceNg2.createCustomModal(modalModel); this.ModalServiceNg2.addDynamicContentToModal(this.modalInstance, ServicePathCreatorComponent, {service: this.service}); this.modalInstance.instance.open(); @@ -55,10 +56,10 @@ export class ServicePathComponent { onListServicePath = ():void => { this.showServicePathMenu = false; let cancelButton: ButtonModel = new ButtonModel('Close', 'outline white', this.ModalServiceNg2.closeCurrentModal); - let modalModel: ModalModel = new ModalModel('md', 'Service Paths List','', [cancelButton], 'standard', true); + let modalModel: ModalModel = new ModalModel('md', 'Service Flows List','', [cancelButton], 'standard', true); this.modalInstance = this.ModalServiceNg2.createCustomModal(modalModel); this.ModalServiceNg2.addDynamicContentToModal(this.modalInstance, ServicePathsListComponent, {service: this.service, - onCreateServicePath: this.onCreateServicePath, onEditServicePath: this.onEditServicePath}); + onCreateServicePath: this.onCreateServicePath, onEditServicePath: this.onEditServicePath, isViewOnly: this.isViewOnly}); this.modalInstance.instance.open(); }; @@ -70,14 +71,14 @@ export class ServicePathComponent { onEditServicePath = (id:string):void => { let cancelButton: ButtonModel = new ButtonModel('Cancel', 'outline white', this.ModalServiceNg2.closeCurrentModal); let saveButton: ButtonModel = new ButtonModel('Save', 'blue', this.createPath, this.getDisabled ); - let modalModel: ModalModel = new ModalModel('l', 'Edit Path', '', [saveButton, cancelButton]); + let modalModel: ModalModel = new ModalModel('l', 'Edit Path', '', [saveButton, cancelButton], 'standard', true); this.modalInstance = this.ModalServiceNg2.createCustomModal(modalModel); this.ModalServiceNg2.addDynamicContentToModal(this.modalInstance, ServicePathCreatorComponent, {service: this.service, pathId: id}); this.modalInstance.instance.open(); }; getDisabled = ():boolean => { - return !this.modalInstance.instance.dynamicContent.instance.checkFormValidForSubmit(); + return this.isViewOnly || !this.modalInstance.instance.dynamicContent.instance.checkFormValidForSubmit(); }; } diff --git a/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-container.component.html b/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-container.component.html index e279e3f704..981efbb58e 100644 --- a/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-container.component.html +++ b/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-container.component.html @@ -1,11 +1,11 @@ -<div class="sdc-canvas-zone {{class}}-zone" [class.minimized]="minifyZone" [class.hidden]="!showZone"> - <div class="sdc-canvas-zone__header" (click)="unminifyZone()" > +<div class="sdc-canvas-zone {{class}}-zone" [class.minimized]="minimized" [class.hidden]="!visible" (click)="backgroundClicked()"> + <div class="sdc-canvas-zone__header" (click)="unminifyZone(); $event.stopPropagation();" > <div class="sdc-canvas-zone__title">{{title}} <span class="sdc-canvas-zone__counter">{{count}}</span> </div> <span class="sdc-canvas-zone__state-button">–</span> </div> - <div class="sdc-canvas-zone__container"> + <div class="sdc-canvas-zone__container" #scrollDiv > <ng-content></ng-content> </div> </div>
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-container.component.less b/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-container.component.less index 3e77c5ca3b..02880a9202 100644 --- a/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-container.component.less +++ b/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-container.component.less @@ -1,5 +1,5 @@ .sdc-canvas-zone { - width: 280px; + width: 285px; max-height:186px; display:flex; flex-direction:column; diff --git a/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-container.component.ts b/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-container.component.ts index 7e60cb37a6..4059ad6cae 100644 --- a/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-container.component.ts +++ b/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-container.component.ts @@ -1,6 +1,5 @@ -import { Component, Input, Output, ViewEncapsulation, EventEmitter } from '@angular/core'; -import { EventListenerService } from 'app/services'; -import { GRAPH_EVENTS } from 'app/utils'; +import { Component, Input, Output, ViewEncapsulation, EventEmitter, OnInit } from '@angular/core'; +import { ZoneInstanceType } from '../../../../models/graph/zones/zone-instance'; @Component({ selector: 'zone-container', @@ -9,17 +8,28 @@ import { GRAPH_EVENTS } from 'app/utils'; encapsulation: ViewEncapsulation.None }) -export class ZoneContainerComponent { +export class ZoneContainerComponent implements OnInit { @Input() title:string; - @Input() class:string; - @Input() count:number; - @Input() showZone:boolean; - @Input() minifyZone:boolean; - constructor(private eventListenerService:EventListenerService) {} + @Input() type:ZoneInstanceType; + @Input() count:number; + @Input() visible:boolean; + @Input() minimized:boolean; + @Output() minimize: EventEmitter<any> = new EventEmitter<any>(); + @Output() backgroundClick: EventEmitter<void> = new EventEmitter<void>(); + private class:string; + + constructor() {} + + ngOnInit() { + this.class = ZoneInstanceType[this.type].toLowerCase(); + } private unminifyZone = () => { - this.minifyZone = !this.minifyZone; - this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_ZONE_SIZE_CHANGE); + this.minimize.emit(); + } + + private backgroundClicked = () => { + this.backgroundClick.emit(); } }
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-instance/zone-instance.component.html b/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-instance/zone-instance.component.html index d36b7aec6f..031b081323 100644 --- a/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-instance/zone-instance.component.html +++ b/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-instance/zone-instance.component.html @@ -1,8 +1,10 @@ -<div class="zone-child mode-{{config.mode}}" [class.locked]="activeInstanceMode > MODE.HOVER" - (mouseenter)="setMode(MODE.HOVER)" (mouseleave)="setMode(MODE.NONE)" (click)="setMode(MODE.SELECTED)"> - <div class="zone-child__handle" (click)="setMode(MODE.TAG, $event)">+</div> - <div class="zone-child__body"> - <div class="zone-child__body-content">{{config.count || defaultIconText}}</div> +<div tooltip="{{zoneInstance.instanceData.name}}" #currentComponent + class="zone-instance mode-{{zoneInstance.mode}}" [class.locked]="activeInstanceMode > MODE.HOVER" [class.hiding]="hidden" + (mouseenter)="setMode(MODE.HOVER)" (mouseleave)="setMode(MODE.NONE)" (click)="setMode(MODE.SELECTED, $event)"> + <div *ngIf="zoneInstance.handle" class="target-handle {{zoneInstance.handle}}" (click)="tagHandleClicked($event)"></div> + <div *ngIf="!isViewOnly" class="zone-instance__handle" (click)="setMode(MODE.TAG, $event)">+</div> + <div class="zone-instance__body"> + <div class="zone-instance__body-content">{{zoneInstance.assignments.length || defaultIconText}}</div> </div> - <div class="zone-child__name">{{config.name}}</div> + <div class="zone-instance__name">{{zoneInstance.instanceData.name}}</div> </div>
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-instance/zone-instance.component.less b/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-instance/zone-instance.component.less index a1d56df96e..b562c08514 100644 --- a/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-instance/zone-instance.component.less +++ b/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-instance/zone-instance.component.less @@ -1,9 +1,12 @@ -.zone-child { +@import '../../../../../../assets/styles/variables'; + +.zone-instance { position:relative; width:76px; margin:5px; + opacity:1; - .zone-child__handle { + .zone-instance__handle { display:none; position:absolute; right:4px; @@ -11,33 +14,34 @@ width:22px; height:22px; cursor:pointer; - border: solid white 1px; + border: solid @main_color_p 1px; border-radius: 2px; text-align: center; font-weight:bold; } - .zone-child__body { + .zone-instance__body { margin:0 auto; width:43px; height:43px; display:flex; padding:3px; - } - .zone-child__body-content { + .zone-instance__body-content { border-radius: 2px; flex:1; - color:white; - font-size:18px; + color:@main_color_p; + font-size:16px; text-align:center; display:flex; align-items: center; justify-content: center; + box-shadow:none; + transition:box-shadow 5s; } - .zone-child__name { + .zone-instance__name { text-overflow: ellipsis; overflow: hidden; white-space: nowrap; @@ -45,66 +49,86 @@ } /* Dynamic classes below */ + .target-handle { + position:absolute; + width:18px; + height:18px; + display:block; + top: -4px; + right: 10px; + background-size: 100% 100%; + cursor: url("../../../../../../assets/styles/images/canvas-tagging-icons/policy_2.svg"), pointer; + + &.tagged-policy { + background-image: url('../../../../../../assets/styles/images/canvas-tagging-icons/policy_added.svg'); + } + + &.tag-available { + background-image: url('../../../../../../assets/styles/images/canvas-tagging-icons/indication.svg'); + } + } + + &.mode-1, &.mode-2, &.mode-3 { //hover, selected, tag - .zone-child__body { + .zone-instance__body { border:solid 2px; border-radius: 2px; padding:2px; cursor:pointer; } - .zone-child__handle{ + } + + &.mode-1, &.mode-2:hover{ + .zone-instance__handle{ display:block; - cursor:pointer; } } &.locked { - cursor: default; + cursor: inherit; } - - // &:not(.locked):hover .zone-child__handle{ - // display:block; - // } - .zone-child__body { - cursor: default; + + &.hiding { + opacity:0; + .zone-instance__body-content { + box-shadow: #CCC 0px 0px 15px; + } } - &.mode-3 .zone-child__handle { + + + &.mode-3 .zone-instance__handle { width:24px; height:24px; right:3px; top:9px; display:block; background-image: linear-gradient(-140deg, #009E98 0%, #97D648 100%); - border: 2px solid #FFFFFF; + border: 2px solid @main_color_p; border-radius: 2px; box-shadow: inset 2px -2px 3px 0 #007A3E; - cursor: pointer; } } .sdc-canvas-zone.group-zone { - .zone-child__handle { - background-color:#009FDB; - } - .zone-child__body { - border-color:#009FDB; + .zone-instance__handle { + background-color:@main_color_a; } - .zone-child__body-content { - background: #009FDB; + .zone-instance__body { + border-color:@main_color_a; + .zone-instance__body-content { + background: @main_color_a; + } } } .sdc-canvas-zone.policy-zone { - .zone-child__handle { - background-color:#0568AE; + .zone-instance__handle { + background-color:@main_color_r; } - .zone-child__body { - border-color:#1287D9; - .zone-child__body-content { - background: #1287D9; + .zone-instance__body { + border-color:@main_color_r; + .zone-instance__body-content { + background: @main_color_r; } } - .zone-child__body-content { - background: #0568AE; - } }
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-instance/zone-instance.component.ts b/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-instance/zone-instance.component.ts index 8057ae908a..3c2dd45db5 100644 --- a/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-instance/zone-instance.component.ts +++ b/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-instance/zone-instance.component.ts @@ -1,5 +1,14 @@ -import { Component, Input, Output, EventEmitter, ViewEncapsulation } from '@angular/core'; -import { ZoneInstanceConfig, ZoneInstanceMode } from 'app/models/graph/zones/zone-child'; +import { Component, Input, Output, EventEmitter, ViewEncapsulation, OnInit, SimpleChange, ElementRef, ViewChild, SimpleChanges } from '@angular/core'; +import { + ZoneInstance, ZoneInstanceMode, ZoneInstanceType, + IZoneInstanceAssignment +} from 'app/models/graph/zones/zone-instance'; +import { PoliciesService } from '../../../../services/policies.service'; +import { GroupsService } from '../../../../services/groups.service'; +import { IZoneService } from "../../../../../models/graph/zones/zone"; +import { EventListenerService } from 'app/services'; +import { GRAPH_EVENTS } from '../../../../../utils'; +import { Subject, Observable } from 'rxjs'; @Component({ selector: 'zone-instance', @@ -7,22 +16,95 @@ import { ZoneInstanceConfig, ZoneInstanceMode } from 'app/models/graph/zones/zon styleUrls: ['./zone-instance.component.less'], encapsulation: ViewEncapsulation.None }) -export class ZoneInstanceComponent { +export class ZoneInstanceComponent implements OnInit { - @Input() config:ZoneInstanceConfig; + @Input() zoneInstance:ZoneInstance; @Input() defaultIconText:string; @Input() isActive:boolean; + @Input() isViewOnly:boolean; @Input() activeInstanceMode: ZoneInstanceMode; + @Input() hidden:boolean; + @Input() forceSave:Subject<Function>; @Output() modeChange: EventEmitter<any> = new EventEmitter<any>(); + @Output() assignmentSaveStart: EventEmitter<void> = new EventEmitter<void>(); + @Output() assignmentSaveComplete: EventEmitter<boolean> = new EventEmitter<boolean>(); + @Output() tagHandleClick: EventEmitter<ZoneInstance> = new EventEmitter<ZoneInstance>(); + @ViewChild('currentComponent') currentComponent: ElementRef; private MODE = ZoneInstanceMode; + private zoneService:IZoneService; - private setMode = (mode:ZoneInstanceMode, event?:any):void => { - if(!this.isActive || this.isActive && mode == ZoneInstanceMode.TAG){ //when active, do not allow hover/select mode toggling - this.modeChange.emit({newMode: mode, instance: this.config}); + constructor(private policiesService:PoliciesService, private groupsService:GroupsService, private eventListenerService:EventListenerService){} + + ngOnInit(){ + if(this.zoneInstance.type == ZoneInstanceType.POLICY){ + this.zoneService = this.policiesService; + } else { + this.zoneService = this.groupsService; } - if(event){ - event.stopPropagation(); + this.forceSave.subscribe((afterSaveFunction:Function) => { + this.setMode(ZoneInstanceMode.TAG, null, afterSaveFunction); + }) + } + + ngOnChanges(changes:SimpleChanges) { + if(changes.hidden){ + this.currentComponent.nativeElement.scrollIntoView({behavior: "smooth", block: "nearest", inline:"end"}); } } + ngOnDestroy() { + this.forceSave.unsubscribe(); + } + + private setMode = (mode:ZoneInstanceMode, event?:any, afterSaveCallback?:Function):void => { + + if(event){ //prevent event from handle and then repeat event from zone instance + event.stopPropagation(); + } + + if(!this.isActive && this.activeInstanceMode === ZoneInstanceMode.TAG) { + return; //someone else is tagging. No events allowed + } + + if(this.isActive && this.zoneInstance.mode === ZoneInstanceMode.TAG){ + if(mode !== ZoneInstanceMode.TAG) { + return; //ignore all other events. The only valid option is saving changes. + } + + let oldAssignments:Array<IZoneInstanceAssignment> = this.zoneInstance.instanceData.getSavedAssignments(); + if(this.zoneInstance.isZoneAssignmentChanged(oldAssignments, this.zoneInstance.assignments)) { + + this.assignmentSaveStart.emit(); + + this.zoneService.updateZoneInstanceAssignments(this.zoneInstance.parentComponentType, this.zoneInstance.parentComponentID, this.zoneInstance.instanceData.uniqueId, this.zoneInstance.assignments).subscribe( + (success) => { + this.zoneInstance.instanceData.setSavedAssignments(this.zoneInstance.assignments); + if(this.zoneInstance.type === ZoneInstanceType.POLICY){ + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_POLICY_INSTANCE_UPDATE, this.zoneInstance.instanceData); + } else { + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_GROUP_INSTANCE_UPDATE, this.zoneInstance.instanceData); + } + this.assignmentSaveComplete.emit(true); + if(afterSaveCallback) afterSaveCallback(); + }, (error) => { + this.zoneInstance.assignments = oldAssignments; + this.assignmentSaveComplete.emit(false); + }); + } else { + if(afterSaveCallback) afterSaveCallback(); + } + this.modeChange.emit({newMode: ZoneInstanceMode.NONE, instance: this.zoneInstance}); + + } else { + this.modeChange.emit({newMode: mode, instance: this.zoneInstance}); + } + + + } + + private tagHandleClicked = (event:Event) => { + this.tagHandleClick.emit(this.zoneInstance); + event.stopPropagation(); + }; + }
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/components/ui/dynamic-element/dynamic-element.component.ts b/catalog-ui/src/app/ng2/components/ui/dynamic-element/dynamic-element.component.ts index d1e68f3088..c15f92ccb8 100644 --- a/catalog-ui/src/app/ng2/components/ui/dynamic-element/dynamic-element.component.ts +++ b/catalog-ui/src/app/ng2/components/ui/dynamic-element/dynamic-element.component.ts @@ -53,6 +53,7 @@ export class DynamicElementComponent { @ViewChild('target', { read: ViewContainerRef }) target: any; @Input() type: any; @Input() name: string; + @Input() testId: string; @Input() readonly:boolean; @Input() path:string;//optional param. used only for for subnetpoolid type @@ -111,6 +112,7 @@ export class DynamicElementComponent { if (this.cmpRef) { this.cmpRef.instance.name = this.name; this.cmpRef.instance.type = this.type; + this.cmpRef.instance.testId = this.testId; this.cmpRef.instance.value = this.value; this.cmpRef.instance.readonly = this.readonly; } @@ -133,7 +135,7 @@ export class DynamicElementComponent { case DynamicElementComponentCreatorIdentifier.FLOAT: this.createComponent(UiElementIntegerInputComponent); - this.cmpRef.instance.pattern = /^[-+]?[0-9]+(\.[0-9]+)?([eE][-+]?[0-9]+)?$/; + this.cmpRef.instance.pattern = /^[-+]?[0-9]+(\.[0-9]+)?([eE][-+]?[0-9]+)?$/.source; break; case DynamicElementComponentCreatorIdentifier.STRING: @@ -156,10 +158,10 @@ export class DynamicElementComponent { case DynamicElementComponentCreatorIdentifier.DEFAULT: default: this.createComponent(UiElementInputComponent); - console.log("ERROR: No ui component to handle type: " + this.type); + console.log("ERROR: No ui-models component to handle type: " + this.type); } - // Subscribe to change event of of ui-element-basic and fire event to change the value + // Subscribe to change event of of ui-models-element-basic and fire event to change the value this.cmpRef.instance.baseEmitter.subscribe((event) => { this.emitter.emit(event); }); this.cmpRef.instance.valueChange.subscribe((event) => { this.valueChange.emit(event); }); } diff --git a/catalog-ui/src/app/ng2/components/ui/expand-collapse/expand-collapse.component.html b/catalog-ui/src/app/ng2/components/ui/expand-collapse/expand-collapse.component.html new file mode 100644 index 0000000000..83daca2ae5 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/ui/expand-collapse/expand-collapse.component.html @@ -0,0 +1,13 @@ +<h1 class="w-sdc-designer-sidebar-section-title" + tooltip="{{titleTooltip}}" + [ngClass]="{'expanded': state == 0, 'collapsed': state == 1}" + (click)="toggleState()"> + {{caption}}<span class="w-sdc-designer-sidebar-section-title-icon"></span> + <ng-content select="header"></ng-content> + <span class="w-sdc-designer-sidebar-section-title-icon"></span> +</h1> + +<div class="expand-collapse-content" [ngClass]="{'visible': state === 0, 'hidden': state === 1}"> + <ng-content></ng-content> + <ng-content select="content"></ng-content> +</div> diff --git a/catalog-ui/src/app/ng2/components/ui/expand-collapse/expand-collapse.component.less b/catalog-ui/src/app/ng2/components/ui/expand-collapse/expand-collapse.component.less new file mode 100644 index 0000000000..e5dd2527c1 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/ui/expand-collapse/expand-collapse.component.less @@ -0,0 +1,7 @@ +.ellipsis-directive-more-less { + float: right; + margin-right: 10px; + line-height: 23px; + text-decoration: underline; + text-align: left; +} diff --git a/catalog-ui/src/app/ng2/components/ui/expand-collapse/expand-collapse.component.ts b/catalog-ui/src/app/ng2/components/ui/expand-collapse/expand-collapse.component.ts new file mode 100644 index 0000000000..0fa0d33de9 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/ui/expand-collapse/expand-collapse.component.ts @@ -0,0 +1,56 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import { Component, Input, Output, ViewEncapsulation, AfterViewInit } from '@angular/core'; + +export enum ExpandState { + EXPANDED, + COLLAPSED +} + +@Component({ + selector: 'ng2-expand-collapse', + templateUrl: './expand-collapse.component.html', + styleUrls: ['./expand-collapse.component.less'], + encapsulation: ViewEncapsulation.None +}) + +export class ExpandCollapseComponent implements AfterViewInit { + @Input() caption: String; + @Input() state: ExpandState; + @Input() titleTooltip: String; + + constructor() { + + } + + toggleState():void { + if (this.state == ExpandState.EXPANDED) { + this.state = ExpandState.COLLAPSED; + } else { + this.state = ExpandState.EXPANDED; + } + } + + ngAfterViewInit(): void { + + } + +} diff --git a/catalog-ui/src/app/ng2/components/ui/form-components/dropdown/ui-element-dropdown.component.html b/catalog-ui/src/app/ng2/components/ui/form-components/dropdown/ui-element-dropdown.component.html index 805e5ac295..c564abc092 100644 --- a/catalog-ui/src/app/ng2/components/ui/form-components/dropdown/ui-element-dropdown.component.html +++ b/catalog-ui/src/app/ng2/components/ui/form-components/dropdown/ui-element-dropdown.component.html @@ -1,3 +1,3 @@ -<select name='{{name}}' [(ngModel)]="value" (change)="onChange()" [ngClass]="{'disabled':readonly}" data-tests-id="SelectType"> +<select name='{{name}}' [(ngModel)]="value" (change)="onChange()" [ngClass]="{'disabled':readonly}" [attr.data-tests-id]="'value-' + testId"> <option *ngFor="let ddvalue of values" [ngValue]="ddvalue.label != undefined ? ddvalue.value : ddvalue">{{ddvalue.label||ddvalue}}</option> </select> diff --git a/catalog-ui/src/app/ng2/components/ui/form-components/input/ui-element-input.component.html b/catalog-ui/src/app/ng2/components/ui/form-components/input/ui-element-input.component.html index 057e731ada..fdba850e93 100644 --- a/catalog-ui/src/app/ng2/components/ui/form-components/input/ui-element-input.component.html +++ b/catalog-ui/src/app/ng2/components/ui/form-components/input/ui-element-input.component.html @@ -11,4 +11,5 @@ [formControl]="control" tooltip="{{value}}" [readonly]="readonly" + [attr.data-tests-id]="'value-' + testId" /> diff --git a/catalog-ui/src/app/ng2/components/ui/form-components/integer-input/ui-element-integer-input.component.html b/catalog-ui/src/app/ng2/components/ui/form-components/integer-input/ui-element-integer-input.component.html index e1555e87fd..04307e4c2d 100644 --- a/catalog-ui/src/app/ng2/components/ui/form-components/integer-input/ui-element-integer-input.component.html +++ b/catalog-ui/src/app/ng2/components/ui/form-components/integer-input/ui-element-integer-input.component.html @@ -11,4 +11,5 @@ [formControl]="control" tooltip="{{value}}" [readonly]="readonly" + [attr.data-tests-id]="'value-' + testId" /> diff --git a/catalog-ui/src/app/ng2/components/ui/form-components/popover-input/ui-element-popover-input.component.html b/catalog-ui/src/app/ng2/components/ui/form-components/popover-input/ui-element-popover-input.component.html index 3bd51b4e36..3bc94de1e4 100644 --- a/catalog-ui/src/app/ng2/components/ui/form-components/popover-input/ui-element-popover-input.component.html +++ b/catalog-ui/src/app/ng2/components/ui/form-components/popover-input/ui-element-popover-input.component.html @@ -7,7 +7,7 @@ [value]="value!=undefined?value:''" disabled /> - <button [popover]="popoverForm" [ngClass]="{'disabled':readonly}">Edit</button> + <button [popover]="popoverForm" (onShown)="setEditValue()" [ngClass]="{'disabled':readonly}" [attr.data-tests-id] ="'edit-button-' + testId">Edit</button> </div> <popover-content #popoverForm [title]="name" [buttons]="buttonsArray" [placement]="'top'" [closeOnClickOutside]="true"> @@ -16,11 +16,12 @@ #textArea class="subnet-value" [ngClass]="{'error': control.invalid}" - [(ngModel)]="value" + [(ngModel)]="editValue" [attr.maxlength]="validation.propertyValue.max" [attr.minlength]="validation.propertyValue.min" [pattern]="pattern" [formControl]="control" + [attr.data-tests-id]="'value-' + testId" ></textarea> </div> </popover-content> diff --git a/catalog-ui/src/app/ng2/components/ui/form-components/popover-input/ui-element-popover-input.component.ts b/catalog-ui/src/app/ng2/components/ui/form-components/popover-input/ui-element-popover-input.component.ts index 525cd1742c..f485d270fa 100644 --- a/catalog-ui/src/app/ng2/components/ui/form-components/popover-input/ui-element-popover-input.component.ts +++ b/catalog-ui/src/app/ng2/components/ui/form-components/popover-input/ui-element-popover-input.component.ts @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -import {Component, ViewChild, ElementRef, Input} from '@angular/core'; +import {Component, ViewChild, ElementRef} from '@angular/core'; import {ButtonsModelMap, ButtonModel} from "app/models"; import {PopoverContentComponent} from "../../popover/popover-content.component"; import {UiElementBase, UiElementBaseInterface} from "../ui-element-base.component"; @@ -32,13 +32,14 @@ export class UiElementPopoverInputComponent extends UiElementBase implements UiE @ViewChild('textArea') textArea: ElementRef; @ViewChild('popoverForm') popoverContentComponent: PopoverContentComponent; + editValue: any; saveButton: ButtonModel; buttonsArray: ButtonsModelMap; constructor() { super(); // Create Save button and insert to buttons map - this.saveButton = new ButtonModel('save', 'blue', this.onChange); + this.saveButton = new ButtonModel('Set', 'blue', this.onChange.bind(this)); this.buttonsArray = { 'test': this.saveButton }; // Define the regex pattern for this controller @@ -47,4 +48,15 @@ export class UiElementPopoverInputComponent extends UiElementBase implements UiE // Disable / Enable button according to validation //this.control.valueChanges.subscribe(data => this.saveButton.disabled = this.control.invalid); } + + public setEditValue() { + // copy value to edit + this.editValue = angular.copy(this.value); + } + + public onChange() { + this.popoverContentComponent.hide(); + this.value = this.editValue; + super.onChange(); + } } diff --git a/catalog-ui/src/app/ng2/components/ui/form-components/ui-element-base.component.ts b/catalog-ui/src/app/ng2/components/ui/form-components/ui-element-base.component.ts index b4e9e7d36a..31fa7c3442 100644 --- a/catalog-ui/src/app/ng2/components/ui/form-components/ui-element-base.component.ts +++ b/catalog-ui/src/app/ng2/components/ui/form-components/ui-element-base.component.ts @@ -46,9 +46,12 @@ export class UiElementBase { @Input() name: string; @Input() type: string; + @Input() path: string; @Input() pattern: any; @Input() readonly:boolean; + @Input() testId:string; + constructor() { //this.control = new FormControl('', [Validators.required]); this.control = new FormControl('', []); diff --git a/catalog-ui/src/app/ng2/components/ui/forms/modal-forms.module.ts b/catalog-ui/src/app/ng2/components/ui/forms/modal-forms.module.ts new file mode 100644 index 0000000000..34404e50a5 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/ui/forms/modal-forms.module.ts @@ -0,0 +1,27 @@ +import { NgModule } from "@angular/core"; +import { CommonModule } from '@angular/common'; +import { SdcUiComponentsModule } from "sdc-ui/lib/angular"; +import { ValueEditComponent } from './value-edit/value-edit.component'; +import { UnsavedChangesComponent } from "./unsaved-changes/unsaved-changes.component"; +import { UiElementsModule } from "../ui-elements.module"; + + + +@NgModule({ + declarations: [ + ValueEditComponent, + UnsavedChangesComponent + ], + imports: [ + CommonModule, + SdcUiComponentsModule, + UiElementsModule + ], + exports: [ValueEditComponent, UnsavedChangesComponent], + entryComponents: [ UnsavedChangesComponent + ], + providers: [] +}) +export class ModalFormsModule { + +}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/components/ui/forms/unsaved-changes/unsaved-changes.component.html b/catalog-ui/src/app/ng2/components/ui/forms/unsaved-changes/unsaved-changes.component.html new file mode 100644 index 0000000000..bdf21dec62 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/ui/forms/unsaved-changes/unsaved-changes.component.html @@ -0,0 +1,6 @@ +<div class="unsaved-changes-modal"> + <div class="message"> + <p>Your changes {{isValidChangedData ? '' : '(invalid)'}} have not been saved.</p> + <p>Do you want to {{isValidChangedData ? 'save' : 'discard'}} them?</p> + </div> +</div>
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/components/ui/forms/unsaved-changes/unsaved-changes.component.ts b/catalog-ui/src/app/ng2/components/ui/forms/unsaved-changes/unsaved-changes.component.ts new file mode 100644 index 0000000000..b8fdeaf659 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/ui/forms/unsaved-changes/unsaved-changes.component.ts @@ -0,0 +1,17 @@ +import { Component, Input } from "@angular/core"; + +@Component({ + selector: 'unsaved-changes', + templateUrl: './unsaved-changes.component.html', + styleUrls: [] +}) +export class UnsavedChangesComponent { + + @Input() isValidChangedData:boolean; + + constructor(){ + } + + + +}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/components/ui/forms/value-edit/value-edit.component.html b/catalog-ui/src/app/ng2/components/ui/forms/value-edit/value-edit.component.html new file mode 100644 index 0000000000..464b756a3f --- /dev/null +++ b/catalog-ui/src/app/ng2/components/ui/forms/value-edit/value-edit.component.html @@ -0,0 +1,12 @@ +<div class="name-update-container"> + <sdc-input #updateNameInput + label="Instance Name" + required="true" + [maxLength]="50" + [(value)]="name" + testId="instanceName"></sdc-input> + <sdc-validation [validateElement]="updateNameInput" (validityChanged)="validityChanged($event)"> + <sdc-required-validator message="Name is required."></sdc-required-validator> + <sdc-regex-validator message="Special characters not allowed." [pattern]="pattern"></sdc-regex-validator> + </sdc-validation> +</div>
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/components/ui/forms/value-edit/value-edit.component.less b/catalog-ui/src/app/ng2/components/ui/forms/value-edit/value-edit.component.less new file mode 100644 index 0000000000..b958ca17b7 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/ui/forms/value-edit/value-edit.component.less @@ -0,0 +1,3 @@ +.name-update-container { + min-height: 90px; +}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/components/ui/forms/value-edit/value-edit.component.ts b/catalog-ui/src/app/ng2/components/ui/forms/value-edit/value-edit.component.ts new file mode 100644 index 0000000000..08bc0586c7 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/ui/forms/value-edit/value-edit.component.ts @@ -0,0 +1,25 @@ +import { Component, Input } from "@angular/core"; + +@Component({ + selector: 'value-edit', + templateUrl: './value-edit.component.html', + styleUrls: ['./value-edit.component.less'] +}) +export class ValueEditComponent { + + @Input() name:String; + @Input() validityChangedCallback: Function; + + private pattern:string = "^[\\s\\w\&_.:-]{1,1024}$" + constructor(){ + } + + private validityChanged = (value):void => { + if(this.validityChangedCallback) { + this.validityChangedCallback(value); + } + } + + + +}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/components/ui/modal/add-elements/add-elements.component.html b/catalog-ui/src/app/ng2/components/ui/modal/add-elements/add-elements.component.html new file mode 100644 index 0000000000..ba897198d6 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/ui/modal/add-elements/add-elements.component.html @@ -0,0 +1,30 @@ +<div class="component-add-element"> + <div class="add-element-selection-container"> + <sdc-dropdown class="add-element-selection" selectedOption="selectedElement" placeHolder="Please choose option" + (changed)="onElementSelected($event)" [options]="dropdownOptions"></sdc-dropdown> + <svg-icon-label class="add-element-button" [class.disabled]="!selectedElement" + name="plus-circle-o" + mode="primary" + size="medium" + label="ADD" + labelPlacement="right" + clickable="{{!!selectedElement}}" + (click)="addElement()"> + </svg-icon-label> + </div> + + <div class="elements-list"> + <ul> + <li *ngFor="let element of existingElements" class="elements-list-item"> + <span>{{element.name}}</span> + <svg-icon-label name="trash-o" clickable="true" size="small" class="elements-list-item-delete" + data-tests-id="delete_target" (click)="removeElement(element)"></svg-icon-label> + </li> + </ul> + <div *ngIf="existingElements.length===0" class="add-element-no-data"> + <div class="add-element-no-data-title">No {{elementName}} have been added yet.</div> + <div class="add-element-no-data-content">Begin typing or select {{elementName}} above</div> + </div> + </div> + +</div>
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/components/ui/modal/add-elements/add-elements.component.less b/catalog-ui/src/app/ng2/components/ui/modal/add-elements/add-elements.component.less new file mode 100644 index 0000000000..522483dfb7 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/ui/modal/add-elements/add-elements.component.less @@ -0,0 +1,61 @@ +@import "./../../../../../../assets/styles/variables-old"; + +.component-add-element { + + .add-element-selection-container { + + display: flex; + flex-direction: row; + .add-element-selection { + flex: 2; + } + + .add-element-button { + padding: 0px 0px 0px 15px; + &:not(.disabled) { + cursor:pointer; + } + } + + } + + .elements-list { + border: 1px solid #d2d2d2; + margin-top: 10px; + height: 300px; + overflow: auto; + + .elements-list-item { + padding: 10px 20px 10px 20px; + + &:first-child { + padding-top: 15px; + } + + &:hover { + background-color: #f8f8f8; + .elements-list-item-delete { + visibility: visible; + } + } + } + } + + .elements-list-item-delete { + float:right; + cursor: pointer; + visibility: hidden; + } + + + .add-element-no-data { + margin: 0 auto; + padding-top: 30px; + text-align: center; + + .add-element-no-data-title { + font-family: @font-opensans-bold; + } + + } +}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/components/ui/modal/add-elements/add-elements.component.ts b/catalog-ui/src/app/ng2/components/ui/modal/add-elements/add-elements.component.ts new file mode 100644 index 0000000000..1d05b27d68 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/ui/modal/add-elements/add-elements.component.ts @@ -0,0 +1,65 @@ +/** + * Created by ob0695 on 11.04.2018. + */ +import {Component, Input} from "@angular/core"; +import {UiBaseObject} from "../../../../../models/ui-models/ui-base-object"; +import {IDropDownOption} from "sdc-ui/lib/angular/form-elements/dropdown/dropdown-models"; + +@Component({ + selector: 'add-elements', + templateUrl: './add-elements.component.html', + styleUrls: ['./add-elements.component.less'] +}) + +export class AddElementsComponent { + + @Input() elementsToAdd:Array<UiBaseObject>; + @Input() elementName: string; + + private existingElements:Array<UiBaseObject>; + private dropdownOptions:Array<IDropDownOption>; + private selectedElement:IDropDownOption; + + ngOnInit() { + this.existingElements = []; + this.convertElementToDropdownDisplay(); + + } + + private convertElementToDropdownDisplay = () => { + this.dropdownOptions = []; + _.forEach(this.elementsToAdd, (elementToAdd:UiBaseObject) =>{ + this.dropdownOptions.push({label:elementToAdd.name, value: elementToAdd.uniqueId }) + }); + } + + onElementSelected(selectedElement:IDropDownOption):void { + this.selectedElement = selectedElement + } + + addElement():void { + + if(this.selectedElement){ + this.dropdownOptions = _.reject(this.dropdownOptions, (option: IDropDownOption) => { // remove from dropDown + return option.value === this.selectedElement.value; + }); + + let selected = _.find(this.elementsToAdd, (element:UiBaseObject) => { + return this.selectedElement.value === element.uniqueId; + }); + + this.elementsToAdd =_.without(this.elementsToAdd, selected); // remove from optional elements to add + this.existingElements.push(selected); // add to existing element list + this.selectedElement = undefined; + } else { + console.log("no element selected"); //TODO:show error? + } + } + + removeElement(element:UiBaseObject):void { + + this.existingElements =_.without(this.existingElements, element); // remove from optional elements to add + this.dropdownOptions.push({label:element.name, value: element.uniqueId }); + this.elementsToAdd.push(element); + } +} diff --git a/catalog-ui/src/app/ng2/components/ui/modal/add-elements/add-elements.module.ts b/catalog-ui/src/app/ng2/components/ui/modal/add-elements/add-elements.module.ts new file mode 100644 index 0000000000..a1c34f5686 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/ui/modal/add-elements/add-elements.module.ts @@ -0,0 +1,30 @@ +/** + * Created by ob0695 on 11.04.2018. + */ +import {NgModule} from "@angular/core"; +import {SdcUiComponentsModule} from "sdc-ui/lib/angular/index"; +import {AddElementsComponent} from "./add-elements.component"; +import {CommonModule} from "@angular/common"; + +/** + * Created by ob0695 on 9.04.2018. + */ +@NgModule({ + declarations: [ + AddElementsComponent + ], + + imports: [ + CommonModule, + SdcUiComponentsModule + ], + + entryComponents: [ + AddElementsComponent + ], + exports: [], + providers: [] +}) +export class AddElementsModule { + +} diff --git a/catalog-ui/src/app/ng2/components/ui/modal/modal.component.html b/catalog-ui/src/app/ng2/components/ui/modal/modal.component.html index 6fc55d19e7..1708fc4c23 100644 --- a/catalog-ui/src/app/ng2/components/ui/modal/modal.component.html +++ b/catalog-ui/src/app/ng2/components/ui/modal/modal.component.html @@ -1,6 +1,5 @@ <div class="custom-modal {{input.size}}"> <div class="ng2-modal-content" - ngDraggable [ngDraggable]="input.isMovable" [handle]="ModalHandle" [bounds]="ModalBounds" diff --git a/catalog-ui/src/app/ng2/components/ui/palette-animation/palette-animation.component.ts b/catalog-ui/src/app/ng2/components/ui/palette-animation/palette-animation.component.ts index 609a1fc5e1..7e45b9e55b 100644 --- a/catalog-ui/src/app/ng2/components/ui/palette-animation/palette-animation.component.ts +++ b/catalog-ui/src/app/ng2/components/ui/palette-animation/palette-animation.component.ts @@ -24,6 +24,7 @@ import { setTimeout } from 'core-js/library/web/timers'; import { EventListenerService } from 'app/services'; import { GRAPH_EVENTS } from 'app/utils'; import { Point } from 'app/models'; +import { ZoneInstanceType, ZoneInstance } from '../../../../models/graph/zones/zone-instance'; @@ -37,8 +38,9 @@ export class PaletteAnimationComponent { @Input() from : Point; @Input() to : Point; + @Input() type: ZoneInstanceType; @Input() iconName : string; - @Input() data : any; + @Input() zoneInstance : ZoneInstance; public animation; private visible:boolean = false; @@ -47,6 +49,11 @@ export class PaletteAnimationComponent { constructor(private eventListenerService:EventListenerService) {} + + ngOnDestroy(){ + this.zoneInstance.hidden = false; //if animation component is destroyed before animation is complete + } + public runAnimation() { this.visible = true; let positionDiff:Point = new Point(this.to.x - this.from.x, this.to.y - this.from.y); @@ -57,7 +64,7 @@ export class PaletteAnimationComponent { public animationComplete = (e) => { this.visible = false; - this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_FINISH_ANIMATION_ZONE); + this.zoneInstance.hidden = false; }; diff --git a/catalog-ui/src/app/ng2/components/ui/palette-popup-panel/palette-popup-panel.component.ts b/catalog-ui/src/app/ng2/components/ui/palette-popup-panel/palette-popup-panel.component.ts index d30d5f6178..a10ca7dc81 100644 --- a/catalog-ui/src/app/ng2/components/ui/palette-popup-panel/palette-popup-panel.component.ts +++ b/catalog-ui/src/app/ng2/components/ui/palette-popup-panel/palette-popup-panel.component.ts @@ -35,7 +35,8 @@ export class PalettePopupPanelComponent implements OnInit { public addZoneInstance(): void { if(this.displayComponent) { - this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_ADD_COMPONENT_INSTANCE_ZONE_START, this.component, this.displayComponent, this.popupPanelPosition); + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_ADD_ZONE_INSTANCE_FROM_PALETTE, this.component, this.displayComponent, this.popupPanelPosition); + this.hidePopupPanel(); } } diff --git a/catalog-ui/src/app/ng2/components/ui/tile/tile.component.html b/catalog-ui/src/app/ng2/components/ui/tile/tile.component.html new file mode 100644 index 0000000000..a7a7b2c5b5 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/ui/tile/tile.component.html @@ -0,0 +1,28 @@ +<div class="sdc-tile sdc-tile-fix-width"> + + <div class='sdc-tile-header' [ngClass]="{'purple': component.isResource(), 'blue': !component.isResource()}"> + <div *ngIf="component.isResource()" data-tests-id="asset-type">{{component.getComponentSubType()}}</div> + <div *ngIf="component.isService()">S</div> + </div> + + <div class='sdc-tile-content' data-tests-id="dashboard-Elements" (click)="tileClicked()"> + <div class='sdc-tile-content-icon'> + <div [ngClass]="[component.iconSprite, component.icon]" [ngClass]="{'sprite-resource-icons': component.isResource(), 'sprite-services-icons': component.isService()}" + [attr.data-tests-id]="component.name"></div> + </div> + + <div class='sdc-tile-content-info'> + <div class="sdc-tile-info-line title" [attr.data-tests-id]="component.name | resourceName" [tooltip]="component.name | resourceName" [tooltipDisabled]="!hasEllipsis"> + <multiline-ellipsis className="w-sdc-tile-multiline-ellipsis" [lines]="3" (hasEllipsisChanged)="hasEllipsis = $event">{{component.name | resourceName}}</multiline-ellipsis> + </div> + <div class="sdc-tile-info-line subtitle" [attr.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> diff --git a/catalog-ui/src/app/ng2/components/ui/tile/tile.component.less b/catalog-ui/src/app/ng2/components/ui/tile/tile.component.less new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/ui/tile/tile.component.less diff --git a/catalog-ui/src/app/ng2/components/ui/tile/tile.component.ts b/catalog-ui/src/app/ng2/components/ui/tile/tile.component.ts new file mode 100644 index 0000000000..b6f63584be --- /dev/null +++ b/catalog-ui/src/app/ng2/components/ui/tile/tile.component.ts @@ -0,0 +1,24 @@ +import {Component, Input, Output, Inject, EventEmitter} from '@angular/core'; +import {Component as ComponentModel} from 'app/models'; +import {SdcMenuToken, IAppMenu} from "../../../config/sdc-menu.config"; + +@Component({ + selector: 'ui-tile', + templateUrl: './tile.component.html', + styleUrls: ['./tile.component.less'] +}) +export class TileComponent { + @Input() public component: ComponentModel; + @Output() public onTileClick: EventEmitter<ComponentModel>; + + public hasEllipsis: boolean; + + constructor(@Inject(SdcMenuToken) public sdcMenu:IAppMenu) { + this.onTileClick = new EventEmitter<ComponentModel>(); + this.hasEllipsis = false; + } + + public tileClicked() { + this.onTileClick.emit(this.component); + } +} diff --git a/catalog-ui/src/app/ng2/components/ui/tile/tile.module.ts b/catalog-ui/src/app/ng2/components/ui/tile/tile.module.ts new file mode 100644 index 0000000000..55b34400d6 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/ui/tile/tile.module.ts @@ -0,0 +1,15 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { TileComponent } from './tile.component'; +import { GlobalPipesModule } from "../../../pipes/global-pipes.module"; +import { TooltipModule } from "../tooltip/tooltip.module"; +import {MultilineEllipsisModule} from "../../../shared/multiline-ellipsis/multiline-ellipsis.module"; + + +@NgModule({ + imports: [BrowserModule, GlobalPipesModule, TooltipModule, MultilineEllipsisModule], + declarations: [TileComponent], + exports: [TileComponent], + entryComponents: [TileComponent] +}) +export class TileModule { } diff --git a/catalog-ui/src/app/ng2/components/ui/ui-elements.module.ts b/catalog-ui/src/app/ng2/components/ui/ui-elements.module.ts index 44314734c3..e905db73a6 100644 --- a/catalog-ui/src/app/ng2/components/ui/ui-elements.module.ts +++ b/catalog-ui/src/app/ng2/components/ui/ui-elements.module.ts @@ -20,26 +20,28 @@ import { NgModule } from '@angular/core'; import { NavbarModule } from "./navbar/navbar.module"; -import {DynamicElementModule} from "./dynamic-element/dynamic-element.module"; -import {FormElementsModule} from "./form-components/form-elements.module"; -import {LoaderComponent} from "./loader/loader.component"; -import {ModalModule} from "./modal/modal.module"; -import {PopoverModule} from "./popover/popover.module"; -import {SearchBarComponent} from "./search-bar/search-bar.component"; -import {SearchWithAutoCompleteComponent} from "./search-with-autocomplete/search-with-autocomplete.component"; -import {PalettePopupPanelComponent} from "./palette-popup-panel/palette-popup-panel.component"; -import {ZoneContainerComponent} from "./canvas-zone/zone-container.component"; -import {ZoneInstanceComponent } from "./canvas-zone/zone-instance/zone-instance.component"; -import {PaletteAnimationComponent} from "./palette-animation/palette-animation.component" -import {TabModule} from "./tabs/tabs.module"; -import {TooltipModule} from "./tooltip/tooltip.module"; -import {CommonModule} from "@angular/common"; -import {FormsModule} from "@angular/forms"; -import {BrowserModule} from "@angular/platform-browser"; -import {MultiStepsWizardModule} from "./multi-steps-wizard/multi-steps-wizard.module"; -import {MenuListModule} from "./menu/menu-list.module"; -import {MenuListNg2Module} from "../downgrade-wrappers/menu-list-ng2/menu-list-ng2.module"; -//import {SdcUiComponentsModule} from "sdc-ui/lib/angular"; +import { DynamicElementModule } from "./dynamic-element/dynamic-element.module"; +import { FormElementsModule } from "./form-components/form-elements.module"; +import { LoaderComponent } from "./loader/loader.component"; +import { ModalModule } from "./modal/modal.module"; +import { PopoverModule } from "./popover/popover.module"; +import { SearchBarComponent } from "./search-bar/search-bar.component"; +import { SearchWithAutoCompleteComponent } from "./search-with-autocomplete/search-with-autocomplete.component"; +import { PalettePopupPanelComponent } from "./palette-popup-panel/palette-popup-panel.component"; +import { ZoneContainerComponent } from "./canvas-zone/zone-container.component"; +import { ZoneInstanceComponent } from "./canvas-zone/zone-instance/zone-instance.component"; +import { PaletteAnimationComponent } from "./palette-animation/palette-animation.component" +import { TabModule } from "./tabs/tabs.module"; +import { TooltipModule } from "./tooltip/tooltip.module"; +import { CommonModule } from "@angular/common"; +import { FormsModule } from "@angular/forms"; +import { BrowserModule } from "@angular/platform-browser"; +import { MultiStepsWizardModule } from "./multi-steps-wizard/multi-steps-wizard.module"; +import { MenuListModule } from "./menu/menu-list.module"; +import { MenuListNg2Module } from "../downgrade-wrappers/menu-list-ng2/menu-list-ng2.module"; +import { ExpandCollapseComponent } from './expand-collapse/expand-collapse.component'; +import { SdcUiComponentsModule } from "sdc-ui/lib/angular"; +import { TileModule } from "./tile/tile.module"; @NgModule({ declarations: [ @@ -49,11 +51,12 @@ import {MenuListNg2Module} from "../downgrade-wrappers/menu-list-ng2/menu-list-n PalettePopupPanelComponent, ZoneContainerComponent, ZoneInstanceComponent, - PaletteAnimationComponent + PaletteAnimationComponent, + ExpandCollapseComponent ], - + imports: [ - //SdcUiComponentsModule, + SdcUiComponentsModule, BrowserModule, FormsModule, CommonModule, @@ -66,7 +69,8 @@ import {MenuListNg2Module} from "../downgrade-wrappers/menu-list-ng2/menu-list-n TooltipModule, MultiStepsWizardModule, MenuListModule, - MenuListNg2Module + MenuListNg2Module, + TileModule ], exports: [ LoaderComponent, @@ -85,7 +89,9 @@ import {MenuListNg2Module} from "../downgrade-wrappers/menu-list-ng2/menu-list-n TooltipModule, MenuListModule, MenuListNg2Module, - PaletteAnimationComponent + PaletteAnimationComponent, + ExpandCollapseComponent, + TileModule ], entryComponents: [SearchWithAutoCompleteComponent, PalettePopupPanelComponent, ZoneContainerComponent, ZoneInstanceComponent, PaletteAnimationComponent] }) diff --git a/catalog-ui/src/app/ng2/config/sdc-menu.config.factory.ts b/catalog-ui/src/app/ng2/config/sdc-menu.config.factory.ts new file mode 100644 index 0000000000..4417c32f27 --- /dev/null +++ b/catalog-ui/src/app/ng2/config/sdc-menu.config.factory.ts @@ -0,0 +1,6 @@ +import {IAppMenu} from "app/models"; + +export function getSdcMenu() : IAppMenu{ + const sdcMenu:IAppMenu = require('./../../../../configurations/menu.js'); + return sdcMenu; +} diff --git a/catalog-ui/src/app/ng2/config/sdc-menu.config.ts b/catalog-ui/src/app/ng2/config/sdc-menu.config.ts new file mode 100644 index 0000000000..07680b5bc9 --- /dev/null +++ b/catalog-ui/src/app/ng2/config/sdc-menu.config.ts @@ -0,0 +1,12 @@ +import {Provider, OpaqueToken} from "@angular/core"; +import {getSdcMenu} from "./sdc-menu.config.factory"; +import {IAppMenu} from "app/models"; + +export { IAppMenu }; + +export const SdcMenuToken = new OpaqueToken('SdcMenuToken'); + +export const SdcMenu:Provider = { + provide: SdcMenuToken, + useFactory: getSdcMenu +}; diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-models/ui-component-to-upgrade.ts b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-models/ui-component-to-upgrade.ts new file mode 100644 index 0000000000..97fb71e210 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-models/ui-component-to-upgrade.ts @@ -0,0 +1,103 @@ +import {ComponentState} from "../../../../utils/constants"; +import {IDependenciesServerResponse} from "../../../services/responses/dependencies-server-response"; +import {UiBaseObject} from "../../../../models/ui-models/ui-base-object"; + +/** + * Created by ob0695 on 5/1/2018. + */ +export enum AutomatedUpgradeInstanceType { + VF, SERVICE_PROXY, ALLOTTED_RESOURCE +} +export class ServiceContainerToUpgradeUiObject extends UiBaseObject { + + icon:string; + version:string; + isLock:boolean; // true if service is in check-out or ceritification-in-progress + vspInstances:Array<VspInstanceUiObject>; // list of instances of the vsp contain in the service - intances can be vf, proxy or allotted + isAlreadyUpgrade:boolean; // true if all instances is in latest version + + constructor(componentToUpgrade:IDependenciesServerResponse) { + super(componentToUpgrade.uniqueId, componentToUpgrade.type, componentToUpgrade.name); + this.icon = componentToUpgrade.icon; + this.version = componentToUpgrade.version; + this.isAlreadyUpgrade = true; + this.isLock = componentToUpgrade.state === ComponentState.CERTIFICATION_IN_PROGRESS || componentToUpgrade.state === ComponentState.NOT_CERTIFIED_CHECKOUT; + this.vspInstances = []; + } + + public addVfInstance = (vsp: IDependenciesServerResponse, latestVersion:string):void => { + let isNeededUpgrade = parseInt(vsp.version) < parseInt(latestVersion); + this.vspInstances.push(new VspInstanceUiObject(vsp.uniqueId, vsp.name, vsp.version, vsp.icon)); + if (isNeededUpgrade) { + this.isAlreadyUpgrade = false; + } + } + + public addProxyInstance = (vsp: IDependenciesServerResponse, isNeededUpgrade:boolean, instanceName:string):void => { + this.vspInstances.push(new ProxyVspInstanceUiObject(vsp.uniqueId, vsp.name, vsp.version, vsp.icon, instanceName)); + if (isNeededUpgrade) { + this.isAlreadyUpgrade = false; + } + } + + public addAllottedResourceInstance = (vsp: IDependenciesServerResponse, isNeededUpgrade:boolean, instanceName:string, vfName:string, vfId:string):void => { + this.vspInstances.push(new AllottedResourceInstanceUiObject(vsp.uniqueId, vsp.name, vsp.version, vsp.icon, instanceName, vfName, vfId)); + if (isNeededUpgrade) { + this.isAlreadyUpgrade = false; + } + } + + public addMultipleInstances = (vsp: IDependenciesServerResponse, vspLatestVersion:string, instancesNames:Array<string>, allottedOriginVf: IDependenciesServerResponse):void => { + _.forEach(instancesNames, (instanceName:string) => { + let isNeededUpgrade = parseInt(vsp.version) < parseInt(vspLatestVersion); + if (allottedOriginVf) { + this.addAllottedResourceInstance(vsp, isNeededUpgrade, instanceName, allottedOriginVf.name, allottedOriginVf.uniqueId); + } else { + this.addProxyInstance(vsp, isNeededUpgrade, instanceName); + } + }) + } +} + +export class VspInstanceUiObject { + + vspName:string; + vspVersion:string; + vspId:string; + icon:string; + instanceType:AutomatedUpgradeInstanceType; + + constructor(uniqueId:string, vspName:string, vspVersion:string, icon:string) { + this.vspId = uniqueId; + this.vspName = vspName; + this.vspVersion = vspVersion; + this.icon = icon; + this.instanceType = AutomatedUpgradeInstanceType.VF; + } +} + +export class ProxyVspInstanceUiObject extends VspInstanceUiObject { + + instanceName:string; + + constructor(uniqueId:string, vspName:string, vspVersion:string, icon:string, instanceName: string) { + super(uniqueId, vspName, vspVersion, icon); + this.instanceName = instanceName; + this.instanceType = AutomatedUpgradeInstanceType.SERVICE_PROXY; + } +} + +export class AllottedResourceInstanceUiObject extends VspInstanceUiObject { + + instanceName:string; + originVfName:string; + originVfId:string; + + constructor(uniqueId:string, vspName:string, vspVersion:string, icon:string, instanceName:string, originVfName:string, originVfId:string) { + super(uniqueId, vspName, vspVersion, icon) + this.instanceName = instanceName; + this.originVfId = originVfId; + this.originVfName = originVfName; + this.instanceType = AutomatedUpgradeInstanceType.ALLOTTED_RESOURCE; + } +} diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-status/automated-upgrade-status.component.html b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-status/automated-upgrade-status.component.html new file mode 100644 index 0000000000..12a3b72b92 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-status/automated-upgrade-status.component.html @@ -0,0 +1,10 @@ +<div class="automated-upgrade-component"> + <span innerHTML="{{statusText}}"> </span> + <div class="components-to-upgrade-list"> + <ul> + <li class="components-to-upgrade-list-item " *ngFor="let component of upgradedComponentsList"> + <upgrade-list-status-item [upgradedComponent]="component" [upgradeComponentStatus]="upgradeStatusMap[component.name]"></upgrade-list-status-item> + </li> + </ul> + </div> +</div> diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-status/automated-upgrade-status.component.ts b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-status/automated-upgrade-status.component.ts new file mode 100644 index 0000000000..0bc342ce65 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-status/automated-upgrade-status.component.ts @@ -0,0 +1,24 @@ +/** + * Created by ob0695 on 4/24/2018. + */ +import {Component, Input} from "@angular/core"; +import Dictionary = _.Dictionary; +import {AutomatedUpgradeStatusResponse} from "../../../services/responses/automated-upgrade-response"; +import {ServiceContainerToUpgradeUiObject} from "../automated-upgrade-models/ui-component-to-upgrade"; + +@Component({ + selector: 'automated-upgrade-status', + templateUrl: './automated-upgrade-status.component.html', + styleUrls: ['./../automated-upgrade.component.less'] +}) +export class AutomatedUpgradeStatusComponent { + + @Input() upgradedComponentsList: Array<ServiceContainerToUpgradeUiObject>; + @Input() upgradeStatusMap: Dictionary<AutomatedUpgradeStatusResponse>; + @Input() statusText: string; + + constructor () { + + } + +} diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-inner-content/list-item-inner-content.component.html b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-inner-content/list-item-inner-content.component.html new file mode 100644 index 0000000000..2a03d94c8c --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-inner-content/list-item-inner-content.component.html @@ -0,0 +1,25 @@ +<ul class="list-item-inner-content"> + <li *ngFor="let vspInstance of vspInstances" class="first-line"> + <div [ngSwitch]="vspInstance.instanceType"> + + <div *ngSwitchCase="automatedUpgradeType.VF"> + <upgrade-line-item arrowName="arrow2-right-child" text="{{vspInstance.vspName}} ({{vspInstance.vspVersion}})"></upgrade-line-item> + </div> + + <div *ngSwitchCase="automatedUpgradeType.SERVICE_PROXY"> + <upgrade-line-item arrowName="arrow2-right-child" prefix="Service Proxy: " text="{{vspInstance.instanceName}}"></upgrade-line-item> + <div class="second-line"> + <upgrade-line-item arrowName="arrow2-right-child" icon="{{vspInstance.icon}}" text="{{ vspInstance.vspName }} ({{vspInstance.vspVersion}})"></upgrade-line-item> + </div> + </div> + + <div *ngSwitchCase="automatedUpgradeType.ALLOTTED_RESOURCE"> + <upgrade-line-item class="allotted-resource-line" arrowName="arrow2-right-child" prefix=" VNF: " text="{{vspInstance.originVfName}}"></upgrade-line-item> + <upgrade-line-item arrowName="arrow2-right" prefix=" VFC: " text="{{vspInstance.instanceName}}"></upgrade-line-item> + <div class="second-line"> + <upgrade-line-item arrowName="arrow2-right-child" icon="vspInstance.icon" prefix=" VFC: " text="{{ vspInstance.vspName }} ({{vspInstance.vspVersion}})"></upgrade-line-item> + </div> + </div> + </div> + </li> +</ul>
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-inner-content/list-item-inner-content.component.less b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-inner-content/list-item-inner-content.component.less new file mode 100644 index 0000000000..24f8107e84 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-inner-content/list-item-inner-content.component.less @@ -0,0 +1,25 @@ +@import "./../../../../../../assets/styles/override"; + +.list-item-inner-content { + .first-line { + + padding: 2px 20px 2px 65px; + border-bottom: 1px solid @sdcui_color_silver; + + &:last-child { + border-bottom: none; + } + } + + .second-line { + padding-left: 45px; + font-weight: bold; + } + + .allotted-resource-line { + + float: left; + margin-right: 15px; + + } +}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-inner-content/list-item-inner-content.component.ts b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-inner-content/list-item-inner-content.component.ts new file mode 100644 index 0000000000..0fa467c3ae --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-inner-content/list-item-inner-content.component.ts @@ -0,0 +1,24 @@ +/** + * Created by ob0695 on 5/7/2018. + */ +/** + * Created by ob0695 on 5/2/2018. + */ +import {Component, Input} from "@angular/core"; +import { + VspInstanceUiObject, + AutomatedUpgradeInstanceType +} from "../../automated-upgrade-models/ui-component-to-upgrade"; + + +@Component({ + selector: 'upgrade-list-item-inner-content', + templateUrl: './list-item-inner-content.component.html', + styleUrls: ['./list-item-inner-content.component.less'] +}) +export class UpgradeListItemInnerContent { + + @Input() vspInstances:Array<VspInstanceUiObject>; + + automatedUpgradeType = AutomatedUpgradeInstanceType; +} diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-order-pipe/list-item-order-pipe.ts b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-order-pipe/list-item-order-pipe.ts new file mode 100644 index 0000000000..abebe0bdd8 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-order-pipe/list-item-order-pipe.ts @@ -0,0 +1,42 @@ +import {Pipe, PipeTransform} from "@angular/core"; +import {ServiceContainerToUpgradeUiObject} from "../../automated-upgrade-models/ui-component-to-upgrade"; + +/* + This filter needs to return all not upgraded components sorted by name first, after that all upgraded components sorted by name + And in the end all the locked components sorted by name + */ + +@Pipe({ + name: 'upgradeListItemOrderBy' +}) +export class UpgradeListItemOrderPipe implements PipeTransform { + + private orderByName = (firstName:string, secondName:string):number => { + var textA = firstName.toLocaleLowerCase(); + var textB = secondName.toLocaleLowerCase(); + return (textA < textB) ? -1 : (textA > textB) ? 1 : 0; + } + + transform(array:Array<ServiceContainerToUpgradeUiObject>):Array<ServiceContainerToUpgradeUiObject> { + array.sort((first:ServiceContainerToUpgradeUiObject, second:ServiceContainerToUpgradeUiObject) => { + if (first.isLock && second.isLock) { + return this.orderByName(first.name, second.name); + } else if (first.isLock) { + return 1; + } else if (second.isLock) { + return -1; + } else { + if (first.isAlreadyUpgrade && second.isAlreadyUpgrade) { + return this.orderByName(first.name, second.name); + } else if (first.isAlreadyUpgrade) { + return 1; + } else if (second.isAlreadyUpgrade) { + return -1; + } else { + return this.orderByName(first.name, second.name); + } + } + }); + return array; + } +}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-line-item/upgrade-line-item.component.html b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-line-item/upgrade-line-item.component.html new file mode 100644 index 0000000000..e848283f67 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-line-item/upgrade-line-item.component.html @@ -0,0 +1,6 @@ +<div class="upgrade-line-item"> + <svg-icon *ngIf="arrowName" name="{{arrowName}}" size="medium" mode="secondary"></svg-icon> + <div *ngIf="icon" class="line-item-icon small sprite-services-icons {{icon}}"></div> + <span *ngIf="prefix" class="line-item-prefix">{{prefix}}</span> + <span class="line-item-text">{{text}}</span> +</div>
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-line-item/upgrade-line-item.component.less b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-line-item/upgrade-line-item.component.less new file mode 100644 index 0000000000..d558e881c2 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-line-item/upgrade-line-item.component.less @@ -0,0 +1,17 @@ +.upgrade-line-item{ + + display: flex; + align-items: center; + + .line-item-icon { + margin-left: 10px; + } + + .line-item-prefix { + margin-left: 7px; + } + + .line-item-text { + margin-left: 7px; + } +}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-line-item/upgrade-line-item.component.ts b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-line-item/upgrade-line-item.component.ts new file mode 100644 index 0000000000..b256d7efe8 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-line-item/upgrade-line-item.component.ts @@ -0,0 +1,19 @@ +import {Component, Input} from "@angular/core"; + +@Component({ + selector: 'upgrade-line-item', + templateUrl: './upgrade-line-item.component.html', + styleUrls: ['./upgrade-line-item.component.less'] +}) + +export class UpgradeLineItemComponent { + + @Input() arrowName:string; + @Input() icon:string; + @Input() prefix:string; + @Input() text:string; + + constructor() { + + } +} diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item-status/upgrade-list-status-item.component.html b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item-status/upgrade-list-status-item.component.html new file mode 100644 index 0000000000..c6d3add7e6 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item-status/upgrade-list-status-item.component.html @@ -0,0 +1,13 @@ +<div class="components-to-upgrade-list-item"> + <div class="component-to-upgrade-data"> + <div class="component-to-upgrade-icon small sprite-services-icons {{upgradedComponent.icon}}"></div> + <span class="component-to-upgrade-name">{{upgradedComponent.name}} ({{upgradedComponent.version}})</span> + <svg-icon-label class="upgraded-component-status" *ngIf="upgradeComponentStatus.status === 'OK'" + name="success-circle-o" mode="success" size="medium" clickable="false"></svg-icon-label> + <svg-icon-label class="upgraded-component-status" *ngIf="upgradeComponentStatus.status !== 'OK'" + name="x-circle-o" mode="error" + size="medium" [label]="'Update Failed'" clickable="false" disabled="false" labelPlacement="left"></svg-icon-label> + </div> + + <upgrade-list-item-inner-content [vspInstances]="upgradedComponent.vspInstances"></upgrade-list-item-inner-content> +</div>
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item-status/upgrade-list-status-item.component.ts b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item-status/upgrade-list-status-item.component.ts new file mode 100644 index 0000000000..726bc67fcf --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item-status/upgrade-list-status-item.component.ts @@ -0,0 +1,19 @@ +import {Component, Input} from "@angular/core"; +import {AutomatedUpgradeStatusResponse} from "../../../../services/responses/automated-upgrade-response"; +import {ServiceContainerToUpgradeUiObject} from "../../automated-upgrade-models/ui-component-to-upgrade"; + +@Component({ + selector: 'upgrade-list-status-item', + templateUrl: './upgrade-list-status-item.component.html', + styleUrls: ['./../upgrade-list-item.component.less'] +}) +export class UpgradeListItemStatusComponent { + + @Input() upgradedComponent: ServiceContainerToUpgradeUiObject; + @Input() upgradeComponentStatus: AutomatedUpgradeStatusResponse; + + constructor () { + + } + +} diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item.component.less b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item.component.less new file mode 100644 index 0000000000..4507929b7f --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item.component.less @@ -0,0 +1,44 @@ +@import "./../../../../../assets/styles/override"; + +.components-to-upgrade-list-item { + border: 1px solid @sdcui_color_light-gray; + box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.11); + margin-bottom: 10px; + line-height: 40px; + + .component-to-upgrade-data { + display: flex; + background-color: @sdcui_color_light-silver; + height: 40px; + padding: 0 10px; + align-items: center; + + .component-to-upgrade-icon { + margin-left: 26px; + } + + .component-to-upgrade-name { + margin-left: 8px; + } + + .component-to-upgrade-checkbox { + height: 24px; // Workaround can not vertical center + } + + .upgraded-component-status { + margin-left: auto; + } + } + + .vsp-data { + align-items: center; + display: flex; + border-bottom: 1px solid @sdcui_color_silver; + padding: 0 10px 0 64px; + .vsp-data-label { + color: @sdcui_color_text-black; + margin-left: 7px; + font-weight: 600; + } + } +}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item/upgrade-list-item.component.html b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item/upgrade-list-item.component.html new file mode 100644 index 0000000000..6e6af0cd1c --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item/upgrade-list-item.component.html @@ -0,0 +1,19 @@ +<div class="components-to-upgrade-list-item "> + <div class="component-to-upgrade-data"> + <sdc-checkbox class="component-to-upgrade-checkbox" + *ngIf="!componentToUpgrade.isAlreadyUpgrade && !componentToUpgrade.isLock" + [checked]="true" + [disabled]="disabled" + (checkedChange)="onComponentChecked(componentToUpgrade.uniqueId)"> + </sdc-checkbox> + <svg-icon *ngIf="componentToUpgrade.isAlreadyUpgrade" name="success-circle-o" mode="success" + size="medium"></svg-icon> + <svg-icon *ngIf="!componentToUpgrade.isAlreadyUpgrade && componentToUpgrade.isLock" name="locked" mode="info" + size="small"></svg-icon> + <div class="component-to-upgrade-icon small sprite-services-icons {{componentToUpgrade.icon}}"></div> + <span class="component-to-upgrade-name">{{componentToUpgrade.name}} ({{componentToUpgrade.version}})</span> + </div> + + <upgrade-list-item-inner-content [vspInstances]="componentToUpgrade.vspInstances"></upgrade-list-item-inner-content> + +</div>
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item/upgrade-list-item.component.ts b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item/upgrade-list-item.component.ts new file mode 100644 index 0000000000..806b83126f --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item/upgrade-list-item.component.ts @@ -0,0 +1,23 @@ +import {Component, Input, Output, EventEmitter} from "@angular/core"; +import {ServiceContainerToUpgradeUiObject, AutomatedUpgradeInstanceType} from "../../automated-upgrade-models/ui-component-to-upgrade"; + +@Component({ + selector: 'upgrade-list-item', + templateUrl: './upgrade-list-item.component.html', + styleUrls: ['./../upgrade-list-item.component.less'] +}) +export class UpgradeListItemComponent { + + @Input() componentToUpgrade:ServiceContainerToUpgradeUiObject; + @Input() disabled: boolean; + @Output() onCheckedChange:EventEmitter<any> = new EventEmitter<any>(); + + constructor() { + } + + onComponentChecked = ():void => { + this.onCheckedChange.emit(); + } + + +} diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.component.html b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.component.html new file mode 100644 index 0000000000..67e7f08436 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.component.html @@ -0,0 +1,25 @@ +<div class="automated-upgrade-component"> + + <div *ngIf="certificationStatusText" class="certification-status"> + <svg-icon-label + name="success-circle-o" + mode="success" + size="medium" + clickable="false" + disabled="false" + labelPlacement="right"> + </svg-icon-label> + <span class="certification-status-text">{{certificationStatusText}}</span> + </div> + + <div> + <span innerHTML="{{informationText}}"> </span> + <div class="components-to-upgrade-list"> + <ul> + <li *ngFor="let component of componentsToUpgrade | upgradeListItemOrderBy"> + <upgrade-list-item (onCheckedChange)= "onComponentSelected(component.uniqueId)" [disabled]="disabled" [componentToUpgrade]="component"></upgrade-list-item> + </li> + </ul> + </div> + </div> +</div>
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.component.less b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.component.less new file mode 100644 index 0000000000..2ab21303d6 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.component.less @@ -0,0 +1,23 @@ +.automated-upgrade-component { + + min-height: 280px; + .certification-status { + border: 1px solid #4ca90c; + border-left: 5px solid #4ca90c; + margin-bottom: 20px; + padding: 5px 5px 5px 10px; + font-weight: bold; + display: flex; + line-height: 21px; + + .certification-status-text { + padding-left: 5px; + } + } + .components-to-upgrade-list { + + overflow: auto; + max-height: 300px; + margin-top: 15px; + } +}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.component.ts b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.component.ts new file mode 100644 index 0000000000..9ae73497ef --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.component.ts @@ -0,0 +1,65 @@ +/** + * Created by ob0695 on 4/18/2018. + */ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import {Component, Input, Inject, forwardRef} from "@angular/core"; +import {TranslateService} from "../../shared/translator/translate.service"; +import {ServiceContainerToUpgradeUiObject} from "./automated-upgrade-models/ui-component-to-upgrade"; +import {AutomatedUpgradeService} from "./automated-upgrade.service"; + +@Component({ + selector: 'upgrade-vsp', + templateUrl: './automated-upgrade.component.html', + styleUrls: ['./automated-upgrade.component.less'], + providers: [TranslateService] +}) +export class AutomatedUpgradeComponent { + + @Input() componentsToUpgrade: Array<ServiceContainerToUpgradeUiObject>; + @Input() certificationStatusText: string; + @Input() informationText: string; + @Input() disabled: string; + private selectedComponentsToUpgrade: Array<string> = []; + + constructor (@Inject(forwardRef(() => AutomatedUpgradeService)) private automatedUpgradeService: AutomatedUpgradeService) { + } + + ngOnInit(): void { // We need to check all elements that needed upgrade as default + this.selectedComponentsToUpgrade = _.filter(this.componentsToUpgrade, (componentToUpgrade:ServiceContainerToUpgradeUiObject) => { + return !componentToUpgrade.isAlreadyUpgrade && !componentToUpgrade.isLock; + }).map(element => element.uniqueId) + } + + onComponentSelected = (uniqueId:string):void => { + + if(this.selectedComponentsToUpgrade.indexOf(uniqueId) > -1) { + this.selectedComponentsToUpgrade = _.without(this.selectedComponentsToUpgrade, uniqueId); + } else { + this.selectedComponentsToUpgrade.push(uniqueId); + } + if(this.selectedComponentsToUpgrade.length === 0) { + this.automatedUpgradeService.changeUpgradeButtonState(true); + } else { + this.automatedUpgradeService.changeUpgradeButtonState(false); + } + } +} diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.module.ts b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.module.ts new file mode 100644 index 0000000000..19f6412071 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.module.ts @@ -0,0 +1,34 @@ +/** + * Created by ob0695 on 4/18/2018. + */ +import { NgModule } from "@angular/core"; +import {SdcUiComponentsModule} from "sdc-ui/lib/angular/index"; +import {CommonModule} from "@angular/common"; +import {AutomatedUpgradeStatusComponent} from "./automated-upgrade-status/automated-upgrade-status.component"; +import {AutomatedUpgradeComponent} from "./automated-upgrade.component"; +import {UpgradeListItemComponent} from "./automated-upgrade-ui-components/upgrade-list-item/upgrade-list-item.component"; +import {UpgradeListItemStatusComponent} from "./automated-upgrade-ui-components/upgrade-list-item-status/upgrade-list-status-item.component"; +import {TranslateService} from "../../shared/translator/translate.service"; +import {UpgradeListItemInnerContent} from "./automated-upgrade-ui-components/list-item-inner-content/list-item-inner-content.component"; +import {UpgradeLineItemComponent} from "./automated-upgrade-ui-components/upgrade-line-item/upgrade-line-item.component"; +import {UpgradeListItemOrderPipe} from "./automated-upgrade-ui-components/list-item-order-pipe/list-item-order-pipe"; + +@NgModule({ + declarations: [ + AutomatedUpgradeStatusComponent, + UpgradeListItemComponent, + UpgradeListItemStatusComponent, + AutomatedUpgradeComponent, + UpgradeListItemInnerContent, + UpgradeLineItemComponent, + UpgradeListItemOrderPipe + ], + imports: [CommonModule, SdcUiComponentsModule], + exports: [], + entryComponents: [ + AutomatedUpgradeComponent, AutomatedUpgradeStatusComponent + ], + providers: [TranslateService] +}) +export class AutomatedUpgradeModule { +}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.service.ts b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.service.ts new file mode 100644 index 0000000000..0acfececaa --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.service.ts @@ -0,0 +1,279 @@ +import {SdcUiComponents} from "sdc-ui/lib/angular"; +import {Injectable, Inject} from "@angular/core"; +import {IModalConfig} from "sdc-ui/lib/angular/modals/models/modal-config"; +import {AutomatedUpgradeComponent} from "./automated-upgrade.component"; +import {Component} from "../../../models/components/component"; +import {ComponentServiceNg2} from "../../services/component-services/component.service"; +import {GeneralStatus, ComponentType} from "../../../utils/constants"; +import {IDependenciesServerResponse} from "../../services/responses/dependencies-server-response"; +import {AutomatedUpgradeStatusComponent} from "./automated-upgrade-status/automated-upgrade-status.component"; +import {AutomatedUpgradeStatusResponse} from "../../services/responses/automated-upgrade-response"; +import Dictionary = _.Dictionary; +import {TranslateService, ITranslateArgs} from "../../shared/translator/translate.service"; +import { + ServiceContainerToUpgradeUiObject, + AllottedResourceInstanceUiObject, VspInstanceUiObject +} from "./automated-upgrade-models/ui-component-to-upgrade"; + +export interface IAutomatedUpgradeRequestObj { + serviceId:string; + resourceId?:string; +} + +export enum Placement { + left = "left" +} + +@Injectable() +export class AutomatedUpgradeService { + + private vspComponent:Component; + private uiComponentsToUpgrade:Array<ServiceContainerToUpgradeUiObject>; + private componentType:string; + + constructor(private modalService:SdcUiComponents.ModalService, + private componentService:ComponentServiceNg2, + private translateService:TranslateService) { + } + + + public convertToServerRequest = (selectedServices:Array<string>):Array<IAutomatedUpgradeRequestObj> => { + + let automatedRequest:Array<IAutomatedUpgradeRequestObj> = []; + _.forEach(selectedServices, (serviceId:string) => { + let serviceToUpgrade:ServiceContainerToUpgradeUiObject = _.find(this.uiComponentsToUpgrade, (service:ServiceContainerToUpgradeUiObject) => { + return serviceId === service.uniqueId; + }); + + if (serviceToUpgrade.vspInstances[0] instanceof AllottedResourceInstanceUiObject) { // If this is allotted resource instances, we need to take the origin vf id (all the instances have the save origin vspId + automatedRequest.push({ + serviceId: serviceId, + resourceId: (<AllottedResourceInstanceUiObject> serviceToUpgrade.vspInstances[0]).originVfId + }); + } else { + automatedRequest.push({serviceId: serviceId}); + } + }); + return automatedRequest; + } + + private getStatusText = (statusMap:Dictionary<AutomatedUpgradeStatusResponse>):string => { + let failedUpgraded = _.filter(_.flatMap(statusMap), (upgradeStatus:AutomatedUpgradeStatusResponse) => { + return upgradeStatus.status !== GeneralStatus.OK + }); + + if (failedUpgraded.length > 0) { + return this.getTextByComponentType("_UPGRADE_STATUS_FAIL"); + } + return this.getTextByComponentType("_UPGRADE_STATUS_SUCCESS"); + } + + private disabledAllModalButtons = ():void => { + this.modalService.getCurrentInstance().innerModalContent.instance.disabled = true; + this.modalService.getCurrentInstance().buttons[0].show_spinner = true; + this.modalService.getCurrentInstance().buttons[1].disabled = true; + } + + public changeUpgradeButtonState = (isDisabled:boolean):void => { + if (this.modalService.getCurrentInstance().buttons[0].disabled !== isDisabled) { + this.modalService.getCurrentInstance().buttons[0].disabled = isDisabled; + } + } + + //TODO We will need to replace this function after sdc-ui modal new design, this is just a workaround + public automatedUpgrade = ():void => { + + let selectedServices = this.modalService.getCurrentInstance().innerModalContent.instance.selectedComponentsToUpgrade; + this.disabledAllModalButtons(); + this.componentService.automatedUpgrade(this.vspComponent.componentType, this.vspComponent.uniqueId, this.convertToServerRequest(selectedServices)).subscribe((automatedUpgradeStatus:any) => { + + if (automatedUpgradeStatus.status === GeneralStatus.OK) { + + let statusMap:Dictionary<AutomatedUpgradeStatusResponse> = _.keyBy(automatedUpgradeStatus.componentToUpgradeStatus, 'name'); + // In the status modal we only showing the upgraded component that the user selected, not the entire list + let upgradedComponent:Array<ServiceContainerToUpgradeUiObject> = _.filter(this.uiComponentsToUpgrade, (component:ServiceContainerToUpgradeUiObject) => { + return selectedServices.indexOf(component.uniqueId) > -1; + }); + + _.forEach(upgradedComponent, (upgradedComponent:ServiceContainerToUpgradeUiObject) => { // If upgrade success we need to upgrade the version all success + if (statusMap[upgradedComponent.name].status === GeneralStatus.OK) { + upgradedComponent.version = statusMap[upgradedComponent.name].version; + _.forEach(upgradedComponent.vspInstances, (instance:VspInstanceUiObject) => { + instance.vspVersion = this.vspComponent.version; + }); + } + }); + + let statusModalTitle = this.getTextByComponentType("_UPGRADE_STATUS_TITLE"); + this.modalService.getCurrentInstance().setTitle(statusModalTitle); + this.modalService.getCurrentInstance().getButtons().splice(0, 1); // Remove the upgrade button + this.modalService.getCurrentInstance().buttons[0].disabled = false; // enable close again + this.modalService.getCurrentInstance().innerModalContent.destroy(); + this.modalService.createInnnerComponent(AutomatedUpgradeStatusComponent, { + upgradedComponentsList: upgradedComponent, + upgradeStatusMap: statusMap, + statusText: this.getStatusText(statusMap) + }); + } + }); + } + + public isAlreadyAdded = (uniqueId:string):ServiceContainerToUpgradeUiObject => { + let componentToUpgrade = _.find(this.uiComponentsToUpgrade, (componentToUpgrade:ServiceContainerToUpgradeUiObject) => { + return componentToUpgrade.uniqueId === uniqueId; + }); + return componentToUpgrade; + } + + public initVfUpgradeData = (serviceToUpgrade:IDependenciesServerResponse, vsp:IDependenciesServerResponse) => { + + let existed = this.isAlreadyAdded(serviceToUpgrade.uniqueId); + if (existed) { // We will take the VF with the lower version existed - only one exist all the time in vf upgrade + if (vsp.version < existed.vspInstances[0].vspVersion) { + existed.vspInstances = []; + existed.addVfInstance(vsp, this.vspComponent.version); + } + } else { + let dependencyUiObj:ServiceContainerToUpgradeUiObject = new ServiceContainerToUpgradeUiObject(serviceToUpgrade); + dependencyUiObj.addVfInstance(vsp, this.vspComponent.version); + this.uiComponentsToUpgrade.push(dependencyUiObj); + } + } + + // Service data will create instances of proxy or allotted resources + public initServiceUpgradeData = (serviceToUpgrade:IDependenciesServerResponse, vsp:IDependenciesServerResponse, instanceNames:Array<string>, allottedOriginVf?:IDependenciesServerResponse) => { + + let existedService = this.isAlreadyAdded(serviceToUpgrade.uniqueId); + if (existedService) { + existedService.addMultipleInstances(vsp, this.vspComponent.version, instanceNames, allottedOriginVf); + } + else { + let dependencyUiObj:ServiceContainerToUpgradeUiObject = new ServiceContainerToUpgradeUiObject(serviceToUpgrade); + dependencyUiObj.addMultipleInstances(vsp, this.vspComponent.version, instanceNames, allottedOriginVf); + this.uiComponentsToUpgrade.push(dependencyUiObj); + } + } + + /* + The server return response of 3 level nested object + First level - Vsp data by version + Each vsp have a decencies (the services contains the vsp - By default this is vf upgrade + If instancesNames exist - this can be proxy or allotted + If we have second layer of dependencies than this is allotted + Since we display the data the opposite way the BE return, this function will order the data in order to display it + */ + public convertToComponentsToUpgradeUiObjArray = (dependenciesServerResponse:Array<IDependenciesServerResponse>):void => { + + this.uiComponentsToUpgrade = []; + + _.forEach(dependenciesServerResponse, (vsp:IDependenciesServerResponse) => { // 3 nested levels - 1 level for vf, 2 level proxy, 3 levels allotted + if (vsp.dependencies) { + _.forEach(vsp.dependencies, (dependency:IDependenciesServerResponse) => { + if (dependency.instanceNames) { // Init service upgrade data + if (dependency.dependencies) { + _.forEach(dependency.dependencies, (serviceContainer:IDependenciesServerResponse) => { // Initiate allotted_resource instances + this.initServiceUpgradeData(serviceContainer, vsp, dependency.instanceNames, dependency); + }); + } else { //Init service_proxy instances + this.initServiceUpgradeData(dependency, vsp, dependency.instanceNames); + } + } else { // Init vf upgrade data + this.initVfUpgradeData(dependency, vsp); + } + }) + } + }); + } + + public isAllComponentsUpgraded = ():boolean => { + let isAllComponentUpgrade = _.filter(this.uiComponentsToUpgrade, (component:ServiceContainerToUpgradeUiObject) => { + return !component.isAlreadyUpgrade; + }); + return isAllComponentUpgrade.length === 0; + } + + public isAllComponentsLocked = ():boolean => { + let unLockedComponents = _.filter(this.uiComponentsToUpgrade, (component:ServiceContainerToUpgradeUiObject) => { + return !component.isLock; + }); + return unLockedComponents.length === 0; + } + + public isUpgradeNeeded = ():boolean => { + let neededUpgradeList = _.filter(this.uiComponentsToUpgrade, (component:ServiceContainerToUpgradeUiObject) => { + return !component.isLock && !component.isAlreadyUpgrade; + }); + return neededUpgradeList.length > 0; + } + + private getTextByComponentType (textLabel: string, params?:ITranslateArgs) { + return this.translateService.translate(this.componentType + textLabel, params); + } + public getInformationTextToDisplay = ():string => { + + let isAllComponentsUpgraded = this.isAllComponentsUpgraded(); + let isAllComponentsLocked = this.isAllComponentsLocked(); + let params = {vspName: this.vspComponent.name, vspVersion: this.vspComponent.version}; + + if (this.uiComponentsToUpgrade.length === 0) { + return this.getTextByComponentType("_NOTHING_TO_UPGRADE", params); + } + + switch (true) { + + case this.isUpgradeNeeded(): + { + return this.getTextByComponentType("_AUTOMATED_UPGRADE_WITH_COMPONENTS_TO_UPGRADE", params); + } + case !this.isUpgradeNeeded() && isAllComponentsLocked: + { + return this.getTextByComponentType("_AUTOMATED_UPGRADE_ALL_COMPONENTS_LOCKED", params); + } + case !this.isUpgradeNeeded() && !isAllComponentsLocked && isAllComponentsUpgraded: + { + return this.getTextByComponentType("_AUTOMATED_UPGRADE_ALL_COMPONENTS_UPGRADED", params); + } + case !this.isUpgradeNeeded() && !isAllComponentsLocked && !isAllComponentsUpgraded: + { + return this.getTextByComponentType("_AUTOMATED_UPGRADE_ALL_COMPONENTS_LOCKED", params); + } + } + } + + public openAutomatedUpgradeModal = (componentsToUpgrade:Array<IDependenciesServerResponse>, component:Component, isAfterCertification?:boolean):void => { + + this.vspComponent = component; + this.componentType = this.vspComponent.isResource() ? ComponentType.RESOURCE : ComponentType.SERVICE; + + this.convertToComponentsToUpgradeUiObjArray(componentsToUpgrade); + let informationalText = this.getInformationTextToDisplay(); + let modalTitle = this.getTextByComponentType("_UPGRADE_TITLE"); + let certificationText = isAfterCertification ? this.getTextByComponentType("_CERTIFICATION_STATUS_TEXT", {resourceName: this.vspComponent.name}) : undefined; + + let upgradeVspModalConfig:IModalConfig = { + title: modalTitle, + size: "md", + type: "custom", + testId: "upgradeVspModal", + buttons: [ + { + text: this.vspComponent.isResource() ? "UPGRADE" : "UPDATE", + spinner_position: Placement.left, + size: 'sm', + callback: this.automatedUpgrade, + closeModal: false, + disabled: !this.isUpgradeNeeded(), + + }, + {text: 'CLOSE', size: 'sm', closeModal: true, type: 'secondary'} + ] + }; + + this.modalService.openCustomModal(upgradeVspModalConfig, AutomatedUpgradeComponent, { + componentsToUpgrade: this.uiComponentsToUpgrade, + informationText: informationalText, + certificationStatusText: certificationText + }); + } +} + diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.component.html new file mode 100644 index 0000000000..731d6a3855 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.component.html @@ -0,0 +1,14 @@ +<div class="component-details-panel-header" data-tests-id="w-sdc-designer-sidebar-head"> + + <div class="icon"> + <div class="large {{iconClassName}}"> + <div [ngClass]="{'non-certified': nonCertified}" tooltip="Not certified"></div> + </div> + </div> + + <div class="title" data-tests-id="selectedCompTitle" tooltip="​{{name}}">{{name}}</div> + + <svg-icon-label *ngIf="!isViewOnly" name="edit-file-o" clickable="true" size="small" class="rename-instance" data-tests-id="renameInstance" (click)="renameInstance()"></svg-icon-label> + <svg-icon-label *ngIf="!isViewOnly" name="trash-o" clickable="true" size="small" class="delete-instance" data-tests-id="deleteInstance" (click)="deleteInstance()"></svg-icon-label> + +</div>
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.component.less b/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.component.less new file mode 100644 index 0000000000..9bbc765761 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.component.less @@ -0,0 +1,34 @@ +/deep/ +.component-details-panel-header { + display: flex; + flex-direction: row; + height: 120px; + align-items: center; + + .icon { + margin: 0 20px; + } + + .title { + font-size: 16px; + text-overflow: ellipsis; + max-width: 180px; + white-space: nowrap; + overflow: hidden; + } + + .rename-instance { + position: absolute; + top: 14px; + right: 20px; + cursor: pointer; + } + + .delete-instance { + position: absolute; + top: 14px; + right: 40px; + cursor: pointer; + } + +}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.component.ts new file mode 100644 index 0000000000..ab659a3b8f --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.component.ts @@ -0,0 +1,135 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import { Component, Input, AfterViewInit, SimpleChanges, OnInit, OnChanges } from "@angular/core"; +import { SdcUiComponents } from "sdc-ui/lib/angular"; +import { IModalConfig } from 'sdc-ui/lib/angular/modals/models/modal-config'; +import { ZoneInstanceType } from 'app/models/graph/zones/zone-instance'; +import { ValueEditComponent } from './../../../../components/ui/forms/value-edit/value-edit.component'; +import { Component as TopologyTemplate, ComponentInstance, IAppMenu } from "app/models"; +import { PoliciesService } from '../../../../services/policies.service'; +import { GroupsService } from '../../../../services/groups.service'; +import {IZoneService} from "../../../../../models/graph/zones/zone"; +import { EventListenerService, LoaderService } from "../../../../../services"; +import { GRAPH_EVENTS, EVENTS } from "../../../../../utils"; +import { UIZoneInstanceObject } from "../../../../../models/ui-models/ui-zone-instance-object"; +import { ModalButtonComponent } from "sdc-ui/lib/angular/components"; + +@Component({ + selector: 'ng2-composition-panel-header', + templateUrl: './panel-header.component.html', + styleUrls: ['./panel-header.component.less'] +}) +export class CompositionPanelHeaderComponent implements OnInit, OnChanges { + + @Input() topologyTemplate: TopologyTemplate; + @Input() selectedZoneInstanceType: ZoneInstanceType; + @Input() selectedZoneInstanceId: string; + @Input() name: string; + @Input() nonCertified: boolean; + @Input() isViewOnly: boolean; + @Input() isLoading: boolean; + + constructor(private groupsService:GroupsService, private policiesService: PoliciesService, + private modalService:SdcUiComponents.ModalService, private eventListenerService:EventListenerService) { } + + private service:IZoneService; + private iconClassName: string; + + ngOnInit(): void { + this.init(); + } + + ngOnChanges (changes:SimpleChanges):void { + if(changes.selectedZoneInstanceId){ + this.init(); + } + } + + ngOnDestroy() { + + + } + private init = (): void => { + if (this.selectedZoneInstanceType === ZoneInstanceType.POLICY) { + this.iconClassName = "sprite-policy-icons policy"; + this.service = this.policiesService; + } else if (this.selectedZoneInstanceType === ZoneInstanceType.GROUP) { + this.iconClassName = "sprite-group-icons group"; + this.service = this.groupsService; + } else { + this.iconClassName = "sprite-resource-icons defaulticon"; + } + } + + private renameInstance = (): void => { + const modalConfig = { + 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} + ] as ModalButtonComponent[] + } as IModalConfig; + this.modalService.openCustomModal(modalConfig, ValueEditComponent, {name: this.name, validityChangedCallback: this.enableOrDisableSaveButton}); + }; + + private enableOrDisableSaveButton = (shouldEnable: boolean): void => { + let saveButton: ModalButtonComponent = this.modalService.getCurrentInstance().getButtonById('saveButton'); + saveButton.disabled = !shouldEnable; + } + + private saveInstanceName = ():void => { + let currentModal = this.modalService.getCurrentInstance(); + let nameFromModal:string = currentModal.innerModalContent.instance.name; + + if(nameFromModal != this.name){ + currentModal.buttons[0].disabled = true; + this.service.updateName(this.topologyTemplate.componentType, this.topologyTemplate.uniqueId, this.selectedZoneInstanceId, nameFromModal).subscribe((success)=>{ + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_ZONE_INSTANCE_NAME_CHANGED, nameFromModal); + this.modalService.closeModal(); + }, (error)=> { + currentModal.buttons[0].disabled = false; + }); + } else { + this.modalService.closeModal(); + } + }; + + private deleteInstance = (): void => { + let title:string = "Delete Confirmation"; + let message:string = "Are you sure you would like to delete "+ this.name + "?"; + this.modalService.openAlertModal(title, message, "OK", this.deleteInstanceConfirmed, "deleteInstanceModal"); + }; + + private deleteInstanceConfirmed = () => { + this.eventListenerService.notifyObservers(EVENTS.SHOW_LOADER_EVENT + 'composition-graph'); + this.service.deleteZoneInstance(this.topologyTemplate.componentType, this.topologyTemplate.uniqueId, this.selectedZoneInstanceId).finally(()=> { + this.eventListenerService.notifyObservers(EVENTS.HIDE_LOADER_EVENT + 'composition-graph'); + }).subscribe(()=> { + let deletedItem:UIZoneInstanceObject = new UIZoneInstanceObject(this.selectedZoneInstanceId, this.selectedZoneInstanceType, this.name); + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_DELETE_ZONE_INSTANCE, deletedItem); + }); + }; + +} + diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.module.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.module.ts new file mode 100644 index 0000000000..bde0a14669 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.module.ts @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +import { NgModule } from "@angular/core"; +import { HttpModule } from "@angular/http"; +import { FormsModule } from "@angular/forms"; +import { BrowserModule } from "@angular/platform-browser"; +import { CompositionPanelHeaderComponent } from "./panel-header.component"; +import { UiElementsModule } from './../../../../components/ui/ui-elements.module'; +import { ValueEditComponent } from './../../../../components/ui/forms/value-edit/value-edit.component'; +import { SdcUiComponentsModule } from "sdc-ui/lib/angular"; +import { ModalFormsModule } from "app/ng2/components/ui/forms/modal-forms.module"; + +@NgModule({ + declarations: [ + CompositionPanelHeaderComponent + ], + imports: [ + BrowserModule, + FormsModule, + HttpModule, + UiElementsModule, + SdcUiComponentsModule, + ModalFormsModule + ], + entryComponents: [ + CompositionPanelHeaderComponent, ValueEditComponent + ], + exports: [ + CompositionPanelHeaderComponent + ], +}) +export class CompositionPanelHeaderModule { + +} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/base/base-tab.component.less b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/base/base-tab.component.less new file mode 100644 index 0000000000..aa8e75115f --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/base/base-tab.component.less @@ -0,0 +1,66 @@ +@import './../../../../../../../assets/styles/mixins'; +@import "./../../../../../../../assets/styles/variables-old"; +@import './../../../../../../../assets/styles/mixins_old'; + +/deep/ +.expand-collapse-content { + padding: 20px; +} + +.component-details-panel-tab-no-data { + margin: 0 auto; + padding-top: 30px; + text-align: center; + + .component-details-panel-tab-no-data-title { + font-family: @font-opensans-bold; + } + +} + +.component-details-panel-large-item { + font-family: OpenSans-Semibold, sans-serif; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + height: 32px; + line-height: 32px; + vertical-align: middle; + + &:hover { + background-color: #f8f8f8; + margin: 0 -20px; /* to fill expand-collapse-content padding */ + padding: 0 20px; + .component-details-panel-item-delete { + visibility: visible; + } + } +} + +.component-details-panel-item { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + height: 22px; + line-height: 22px; + vertical-align: middle; + + &.description { + margin-top: 28px; + white-space: normal; + word-wrap: break-word; + .value { + max-width: none; + font-weight: normal; + font-family: @font-opensans-regular; + } + } + + .name { font-family: OpenSans-Semibold, sans-serif; } + .value { } +} + +.component-details-panel-item-delete { + cursor: pointer; + visibility: hidden; +} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-information-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-information-tab.component.html new file mode 100644 index 0000000000..3c875fd930 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-information-tab.component.html @@ -0,0 +1,30 @@ +<ng2-expand-collapse state="0"> + + <header tooltip="General Information">General Info</header> + + <content> + <!-- CATEGORY --> + <div class="component-details-panel-item"> + <span class="name" [innerHTML]="'GENERAL_LABEL_CATEGORY' | translate"></span> + <span class="value" data-tests-id="rightTab_category" tooltip="Group">Group</span> + </div> + + <!-- SUB CATEGORY --> + <div class="component-details-panel-item"> + <span class="name" [innerHTML]="'GENERAL_LABEL_SUB_CATEGORY' | translate"></span> + <span class="value" data-tests-id="rightTab_subCategory" tooltip="Group">Group</span> + </div> + + <!-- VERSION --> + <div class="component-details-panel-item"> + <span class="name" [innerHTML]="'GENERAL_LABEL_VERSION' | translate"></span> + <span class="value" data-tests-id="rightTab_version" tooltip="{{group.version}}">{{group.version}}</span> + </div> + + <!-- DESCRIPTION --> + <div class="component-details-panel-item description"> + <span class="name" [innerHTML]="'GENERAL_LABEL_DESCRIPTION' | translate"></span> + <span class="value" ellipsis="group.description" max-chars="55" data-tests-id="rightTab_description">{{group.description}}</span> + </div> + </content> +</ng2-expand-collapse> diff --git a/catalog-ui/src/app/filters/catalog-status-filter.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-information-tab.component.ts index 3c0389d57c..26602224da 100644 --- a/catalog-ui/src/app/filters/catalog-status-filter.ts +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-information-tab.component.ts @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,21 +18,22 @@ * ============LICENSE_END========================================================= */ -/** - * Created by obarda on 19/08/2015. - */ -export class CatalogStatusFilter { +import * as _ from "lodash"; +import { Component, Inject, Input, Output, EventEmitter } from "@angular/core"; +import { GroupInstance } from 'app/models/graph/zones/group-instance'; + +@Component({ + selector: 'group-information-tab', + templateUrl: './group-information-tab.component.html', + styleUrls: ['./../base/base-tab.component.less'] +}) +export class GroupInformationTabComponent { + + @Input() group: GroupInstance; + @Input() isViewOnly: boolean; constructor() { - let filter = <CatalogStatusFilter>( (statuses:any) => { - let filtered = []; - angular.forEach(statuses, function (status) { - filtered.push(status); - }); - return filtered; - }); - return filter; } -} +} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.html new file mode 100644 index 0000000000..f298a39a87 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.html @@ -0,0 +1,31 @@ +<div class="w-sdc-designer-sidebar-section-title" tooltip="Members">Members + <svg-icon-label *ngIf="!isViewOnly" + class="add-members-btn" + name="plus-circle-o" + mode="primary" + size="medium" + label="ADD" + labelPlacement="right" + (click)="openAddMembersModal()"> + </svg-icon-label> +</div> +<div class="expand-collapse-content"> + <ul> + <li *ngFor="let member of members; let i = index" class="component-details-panel-large-item" + tooltip="{{member.name}}"> + <span>{{member.name}}</span> + <svg-icon-label *ngIf="!isViewOnly" + name="trash-o" + clickable="true" + size="small" + class="component-details-panel-item-delete" + data-tests-id="delete_member" + (click)="deleteMember(member)"></svg-icon-label> + </li> + </ul> + + <div *ngIf="members.length===0" class="component-details-panel-tab-no-data"> + <div class="component-details-panel-tab-no-data-title">No data to display yet</div> + <div class="component-details-panel-tab-no-data-content">Add members to group to see members</div> + </div> +</div> diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.less b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.less new file mode 100644 index 0000000000..1006e864fa --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.less @@ -0,0 +1,13 @@ +/deep/ +.component-details-panel-tab-group-members { + .component-details-panel-large-item { + display: flex; + flex-direction: row; + justify-content: space-between; + } + + .w-sdc-designer-sidebar-section-title { + display: flex; + justify-content: space-between; + } +}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.ts new file mode 100644 index 0000000000..148f2133e8 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.ts @@ -0,0 +1,133 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import * as _ from "lodash"; +import { Component, Input, Output, EventEmitter, OnChanges, HostBinding } from "@angular/core"; +import { TranslateService } from './../../../../../shared/translator/translate.service'; +import { Component as TopologyTemplate } from "app/models"; +import { GroupInstance } from "app/models/graph/zones/group-instance"; +import { GroupsService } from "../../../../../services/groups.service"; +import { SimpleChanges } from "@angular/core/src/metadata/lifecycle_hooks"; +import { MemberUiObject } from "../../../../../../models/ui-models/ui-member-object"; +import { IModalConfig } from "sdc-ui/lib/angular/modals/models/modal-config"; +import { AddElementsComponent } from "../../../../../components/ui/modal/add-elements/add-elements.component"; +import { GRAPH_EVENTS } from 'app/utils'; +import { EventListenerService } from 'app/services/event-listener-service'; +import { ComponentInstance } from "../../../../../../models/componentsInstances/componentInstance"; +import { SdcUiComponents } from "sdc-ui/lib/angular"; + +@Component({ + selector: 'group-members-tab', + templateUrl: './group-members-tab.component.html', + styleUrls: ['./../base/base-tab.component.less', 'group-members-tab.component.less'] +}) + +export class GroupMembersTabComponent implements OnChanges { + + + private members: Array<MemberUiObject>; + + @Input() group: GroupInstance; + @Input() topologyTemplate: TopologyTemplate; + @Input() isViewOnly: boolean; + @Output() isLoading: EventEmitter<boolean> = new EventEmitter<boolean>(); + @HostBinding('class') classes = 'component-details-panel-tab-group-members'; + + constructor(private translateService: TranslateService, + private groupsService: GroupsService, + private modalService: SdcUiComponents.ModalService, + private eventListenerService: EventListenerService + ) { + this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_GROUP_INSTANCE_UPDATE, this.initMembers) + } + + ngOnChanges(changes:SimpleChanges):void { + this.initMembers(); + } + + deleteMember = (member: MemberUiObject):void => { + this.isLoading.emit(true); + this.groupsService.deleteGroupMember(this.topologyTemplate.componentType, this.topologyTemplate.uniqueId, this.group, member.uniqueId).subscribe( + (updatedMembers:Array<string>) => { + this.group.members = updatedMembers; + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_GROUP_INSTANCE_UPDATE, this.group); + }, + error => console.log("Error deleting member!"), + () => this.isLoading.emit(false) + ); + } + + private initMembers = (groupInstance?: GroupInstance) => { + this.group = groupInstance ? groupInstance : this.group; + this.members = this.group.getMembersAsUiObject(this.topologyTemplate.componentInstances); + } + + addMembers = ():void => { + var membersToAdd:Array<MemberUiObject> = this.modalService.getCurrentInstance().innerModalContent.instance.existingElements; //TODO refactor sdc-ui modal in order to return the data + if(membersToAdd.length > 0) { + this.modalService.closeModal(); + this.isLoading.emit(true); + var updatedMembers: Array<MemberUiObject> = _.union(this.members, membersToAdd); + this.groupsService.updateMembers(this.topologyTemplate.componentType, this.topologyTemplate.uniqueId, this.group.uniqueId, updatedMembers).subscribe( + (updatedMembers:Array<string>) => { + this.group.members = updatedMembers; + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_GROUP_INSTANCE_UPDATE, this.group); + }, + error => { + console.log("Error updating members!"); + }, () => + this.isLoading.emit(false) + ); + } + } + + getOptionalsMembersToAdd():Array<MemberUiObject> { + + let optionalsMembersToAdd:Array<MemberUiObject> = []; + + // adding all instances as optional members to add if not already exist + _.forEach(this.topologyTemplate.componentInstances, (instance:ComponentInstance) => { + if (!_.some(this.members, (member:MemberUiObject) => { + return member.uniqueId === instance.uniqueId + })) { + optionalsMembersToAdd.push(new MemberUiObject(instance.uniqueId, instance.name)); + } + }); + return optionalsMembersToAdd; + } + + openAddMembersModal():void { + let addMembersModalConfig:IModalConfig = { + title: this.group.name + " ADD MEMBERS", + size: "md", + type: "custom", + testId: "addMembersModal", + buttons: [ + {text: 'ADD MEMBERS', size: 'xsm', callback: this.addMembers, closeModal: false}, + {text: 'CANCEL', size: 'sm', type: "secondary", closeModal: true} + ] + }; + var optionalsMembersToAdd = this.getOptionalsMembersToAdd(); + this.modalService.openCustomModal(addMembersModalConfig, AddElementsComponent, { + elementsToAdd: optionalsMembersToAdd, + elementName: "member" + }); + } +} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.html new file mode 100644 index 0000000000..9de489e316 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.html @@ -0,0 +1,23 @@ +<ng2-expand-collapse state="0"> + <header tooltip="Properties">Properties</header> + <content> + <ul> + <li *ngFor="let property of properties; let i = index" + class="i-sdc-designer-sidebar-section-content-item-property-and-attribute" data-tests-id="propertyRow"> + <div class="i-sdc-designer-sidebar-section-content-item-property-and-attribute-label hand" + [attr.data-tests-id]="'propertyName_'+property.name" + tooltip="{{property.name}}" + (click)="!isViewOnly && editProperty(property)">{{property.name}} + </div> + <div class="i-sdc-designer-sidebar-section-content-item-property-value" + [attr.data-tests-id]="'value_'+property.name" + tooltip="{{property.value || property.defaultValue}}">{{property.value || property.defaultValue}} + </div> + </li> + </ul> + + <div *ngIf="properties.length===0" class="component-details-panel-tab-no-data"> + <div class="component-details-panel-tab-no-data-title">No properties to display</div> + </div> + </content> +</ng2-expand-collapse> diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.less b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.less new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.less diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.ts new file mode 100644 index 0000000000..69079347c4 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.ts @@ -0,0 +1,64 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import * as _ from "lodash"; +import { Component, Inject, Input, Output, EventEmitter, OnChanges, SimpleChanges } from "@angular/core"; +import { TranslateService } from './../../../../../shared/translator/translate.service'; +import { GroupInstance } from 'app/models/graph/zones/group-instance'; +import { PropertyBEModel } from 'app/models'; +import { PropertyModel } from './../../../../../../models/properties'; +import { ModalsHandler } from "app/utils"; +import { Component as TopologyTemplate, ComponentInstance, IAppMenu } from "app/models"; + +@Component({ + selector: 'group-properties-tab', + templateUrl: './group-properties-tab.component.html', + styleUrls: ['./../base/base-tab.component.less', 'group-properties-tab.component.less'], + host: {'class': 'component-details-panel-tab-group-properties'} +}) +export class GroupPropertiesTabComponent implements OnChanges { + + @Input() group:GroupInstance; + @Input() topologyTemplate:TopologyTemplate; + @Input() isViewOnly: boolean; + + private properties:Array<PropertyModel>; + + constructor(private translateService:TranslateService, private ModalsHandler:ModalsHandler) { + } + + ngOnChanges(changes: SimpleChanges): void { + console.log("GroupPropertiesTabComponent: ngAfterViewInit: "); + console.log("group: " + JSON.stringify(this.group)); + this.properties = []; + this.initProperties(); + } + + initProperties = ():void => { + this.properties= this.group.properties; + } + + editProperty = (property?:PropertyModel):void => { + this.ModalsHandler.openEditPropertyModal((property ? property : new PropertyModel()), this.topologyTemplate, this.properties, false, 'group', this.group.uniqueId).then((updatedProperty:PropertyModel) => { + console.log("ok"); + }); + } + +} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.component.html new file mode 100644 index 0000000000..94b6619500 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.component.html @@ -0,0 +1,11 @@ +<sdc-tabs> + <sdc-tab titleIcon="info-circle"> + <group-information-tab [group]="group" [isViewOnly]="isViewOnly" *ngIf="group"></group-information-tab> + </sdc-tab> + <sdc-tab titleIcon="inputs-o"> + <group-members-tab [group]="group" [topologyTemplate]="topologyTemplate" [isViewOnly]="isViewOnly" (isLoading)="setIsLoading($event)" *ngIf="group"></group-members-tab> + </sdc-tab> + <sdc-tab titleIcon="settings-o"> + <group-properties-tab [group]="group" [topologyTemplate]="topologyTemplate" [isViewOnly]="isViewOnly" *ngIf="group"></group-properties-tab> + </sdc-tab> +</sdc-tabs> diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.component.ts new file mode 100644 index 0000000000..975d5c6153 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.component.ts @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import * as _ from "lodash"; +import { Component, Inject, Input, Output, EventEmitter, SimpleChanges, OnChanges } from "@angular/core"; +import { TranslateService } from './../../../../../shared/translator/translate.service'; +import { Component as TopologyTemplate, ComponentInstance, IAppMenu } from "app/models"; +import { GroupsService } from '../../../../../services/groups.service'; +import { GroupInstance } from "app/models/graph/zones/group-instance"; + +@Component({ + selector: 'group-tabs', + templateUrl: './group-tabs.component.html' +}) +export class GroupTabsComponent implements OnChanges { + + @Input() topologyTemplate:TopologyTemplate; + @Input() selectedZoneInstanceType:string; + @Input() selectedZoneInstanceId:string; + @Input() isViewOnly: boolean; + @Output() isLoading: EventEmitter<boolean> = new EventEmitter<boolean>(); + + private group:GroupInstance; + + constructor(private translateService:TranslateService, + private groupsService:GroupsService + ) { + } + + ngOnChanges(changes: SimpleChanges): void { + this.initGroup(); + } + + private initGroup = ():void => { + this.isLoading.emit(true); + this.groupsService.getSpecificGroup(this.topologyTemplate.componentType, this.topologyTemplate.uniqueId, this.selectedZoneInstanceId).subscribe( + group => { + this.group = group; + console.log(JSON.stringify(group)); + }, + error => console.log("Error getting group!"), + () => this.isLoading.emit(false) + ); + } + + private setIsLoading = (value) :void => { + this.isLoading.emit(value); + } + +} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.module.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.module.ts new file mode 100644 index 0000000000..50797f862c --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.module.ts @@ -0,0 +1,71 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +import { NgModule } from "@angular/core"; +import { HttpModule } from "@angular/http"; +import { FormsModule } from "@angular/forms"; +import { BrowserModule } from "@angular/platform-browser"; +import { UiElementsModule } from 'app/ng2/components/ui/ui-elements.module'; +import { ExpandCollapseComponent } from 'app/ng2/components/ui/expand-collapse/expand-collapse.component'; +import { PoliciesService } from "../../../../../services/policies.service"; +import { GroupInformationTabComponent } from './group-information-tab.component'; +import { TooltipModule } from './../../../../../components/ui/tooltip/tooltip.module'; +import { GroupTabsComponent } from "./group-tabs.component"; +import { SdcUiComponentsModule } from "sdc-ui/lib/angular"; +import { GroupMembersTabComponent } from './group-members-tab.component'; +import { TranslateModule } from './../../../../../shared/translator/translate.module'; +import { GroupPropertiesTabComponent } from "./group-properties-tab.component"; + +@NgModule({ + declarations: [ + GroupInformationTabComponent, + GroupMembersTabComponent, + GroupTabsComponent, + GroupPropertiesTabComponent + ], + imports: [ + BrowserModule, + FormsModule, + HttpModule, + TooltipModule, + UiElementsModule, + SdcUiComponentsModule, + TranslateModule + ], + entryComponents: [ + GroupInformationTabComponent, + GroupMembersTabComponent, + GroupTabsComponent, + GroupPropertiesTabComponent, + ExpandCollapseComponent + ], + exports: [ + TooltipModule, + GroupInformationTabComponent, + GroupMembersTabComponent, + GroupTabsComponent, + GroupPropertiesTabComponent + ], + providers: [ + PoliciesService + ] +}) +export class GroupTabsModule { + +} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-information-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-information-tab.component.html new file mode 100644 index 0000000000..a1b942d56b --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-information-tab.component.html @@ -0,0 +1,34 @@ +<ng2-expand-collapse state="0"> + <header tooltip="General Information">General Info</header> + <content> + <!-- TYPE --> + <div class="component-details-panel-item"> + <span class="name" [innerHTML]="'GENERAL_LABEL_TYPE' | translate"></span> + <span class="value" data-tests-id="rightTab_componentType" tooltip="{{policy.policyTypeUid}}">{{policy.policyTypeUid}}</span> + </div> + + <!-- CATEGORY --> + <div class="component-details-panel-item"> + <span class="name" [innerHTML]="'GENERAL_LABEL_CATEGORY' | translate"></span> + <span class="value" data-tests-id="rightTab_category" tooltip="Policy">Policy</span> + </div> + + <!-- SUB CATEGORY --> + <div class="component-details-panel-item"> + <span class="name" [innerHTML]="'GENERAL_LABEL_SUB_CATEGORY' | translate"></span> + <span class="value" data-tests-id="rightTab_subCategory" tooltip="Policy">Policy</span> + </div> + + <!-- VERSION --> + <div class="component-details-panel-item"> + <span class="name" [innerHTML]="'GENERAL_LABEL_VERSION' | translate"></span> + <span class="value" data-tests-id="rightTab_version" tooltip="{{policy.version}}">{{policy.version}}</span> + </div> + + <!-- DESCRIPTION --> + <div class="component-details-panel-item description"> + <span class="name" [innerHTML]="'GENERAL_LABEL_DESCRIPTION' | translate"></span> + <span class="value" ellipsis="policy.description" max-chars="55" data-tests-id="rightTab_description">{{policy.description}}</span> + </div> + </content> +</ng2-expand-collapse> diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-information-tab.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-information-tab.component.ts new file mode 100644 index 0000000000..3639639c88 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-information-tab.component.ts @@ -0,0 +1,39 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import * as _ from "lodash"; +import { Component, Inject, Input, Output, EventEmitter } from "@angular/core"; +import { TranslateService } from './../../../../../shared/translator/translate.service'; +import { PolicyInstance } from 'app/models/graph/zones/policy-instance'; + +@Component({ + selector: 'policy-information-tab', + templateUrl: './policy-information-tab.component.html', + styleUrls: ['./../base/base-tab.component.less'] +}) +export class PolicyInformationTabComponent { + + @Input() policy:PolicyInstance; + @Input() isViewOnly: boolean; + + constructor(private translateService:TranslateService) { + } + +} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.html new file mode 100644 index 0000000000..9de489e316 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.html @@ -0,0 +1,23 @@ +<ng2-expand-collapse state="0"> + <header tooltip="Properties">Properties</header> + <content> + <ul> + <li *ngFor="let property of properties; let i = index" + class="i-sdc-designer-sidebar-section-content-item-property-and-attribute" data-tests-id="propertyRow"> + <div class="i-sdc-designer-sidebar-section-content-item-property-and-attribute-label hand" + [attr.data-tests-id]="'propertyName_'+property.name" + tooltip="{{property.name}}" + (click)="!isViewOnly && editProperty(property)">{{property.name}} + </div> + <div class="i-sdc-designer-sidebar-section-content-item-property-value" + [attr.data-tests-id]="'value_'+property.name" + tooltip="{{property.value || property.defaultValue}}">{{property.value || property.defaultValue}} + </div> + </li> + </ul> + + <div *ngIf="properties.length===0" class="component-details-panel-tab-no-data"> + <div class="component-details-panel-tab-no-data-title">No properties to display</div> + </div> + </content> +</ng2-expand-collapse> diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.less b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.less new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.less diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.ts new file mode 100644 index 0000000000..5862135df2 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.ts @@ -0,0 +1,64 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import * as _ from "lodash"; +import { Component, Inject, Input, Output, EventEmitter, OnChanges, SimpleChanges } from "@angular/core"; +import { TranslateService } from './../../../../../shared/translator/translate.service'; +import { PolicyInstance } from 'app/models/graph/zones/policy-instance'; +import { PropertyBEModel } from 'app/models'; +import { PropertyModel } from './../../../../../../models/properties'; +import { ModalsHandler } from "app/utils"; +import { Component as TopologyTemplate, ComponentInstance, IAppMenu } from "app/models"; + +@Component({ + selector: 'policy-properties-tab', + templateUrl: './policy-properties-tab.component.html', + styleUrls: ['./../base/base-tab.component.less', 'policy-properties-tab.component.less'], + host: {'class': 'component-details-panel-tab-policy-properties'} +}) +export class PolicyPropertiesTabComponent implements OnChanges { + + @Input() policy:PolicyInstance; + @Input() topologyTemplate:TopologyTemplate; + @Input() isViewOnly: boolean; + + private properties:Array<PropertyModel>; + + constructor(private translateService:TranslateService, private ModalsHandler:ModalsHandler) { + } + + ngOnChanges(changes: SimpleChanges): void { + console.log("PolicyPropertiesTabComponent: ngAfterViewInit: "); + console.log("policy: " + this.policy); + this.properties = []; + this.initProperties(); + } + + initProperties = ():void => { + this.properties= this.policy.properties; + } + + editProperty = (property?:PropertyModel):void => { + this.ModalsHandler.openEditPropertyModal((property ? property : new PropertyModel()), this.topologyTemplate, this.properties, false, 'policy', this.policy.uniqueId).then((updatedProperty:PropertyModel) => { + console.log("ok"); + }); + } + +} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.component.html new file mode 100644 index 0000000000..b11ad7ebf9 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.component.html @@ -0,0 +1,12 @@ +<sdc-tabs> + <sdc-tab titleIcon="info-circle"> + <policy-information-tab [policy]="policy" [isViewOnly]="isViewOnly" *ngIf="policy"></policy-information-tab> + </sdc-tab> + <sdc-tab titleIcon="inputs-o"> + <policy-targets-tab [policy]="policy" [topologyTemplate]="topologyTemplate" [isViewOnly]="isViewOnly" (isLoading)="setIsLoading($event)" *ngIf="policy"></policy-targets-tab> + </sdc-tab> + <sdc-tab titleIcon="settings-o"> + <policy-properties-tab [policy]="policy" [topologyTemplate]="topologyTemplate" [isViewOnly]="isViewOnly" *ngIf="policy"></policy-properties-tab> + </sdc-tab> +</sdc-tabs> + diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.component.ts new file mode 100644 index 0000000000..1e2739901d --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.component.ts @@ -0,0 +1,72 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import * as _ from "lodash"; +import { Component, Inject, Input, Output, EventEmitter, AfterViewInit, OnChanges } from "@angular/core"; +import { TranslateService } from './../../../../../shared/translator/translate.service'; +import { PoliciesService } from "../../../../../services/policies.service"; +import { Component as TopologyTemplate, ComponentInstance, IAppMenu } from "app/models"; +import { PolicyInstance } from 'app/models/graph/zones/policy-instance'; +import { GRAPH_EVENTS } from './../../../../../../utils/constants'; +import { EventListenerService } from 'app/services/event-listener-service'; +import { ZoneInstance } from 'app/models/graph/zones/zone-instance'; +import { SimpleChanges } from "@angular/core/src/metadata/lifecycle_hooks"; + +@Component({ + selector: 'policy-tabs', + templateUrl: './policy-tabs.component.html' +}) +export class PolicyTabsComponent implements OnChanges { + + @Input() topologyTemplate:TopologyTemplate; + @Input() selectedZoneInstanceType:string; + @Input() selectedZoneInstanceId:string; + @Input() isViewOnly: boolean; + @Output() isLoading: EventEmitter<boolean> = new EventEmitter<boolean>(); + + private policy:PolicyInstance; + + constructor(private translateService:TranslateService, + private policiesService:PoliciesService + ) { + + } + + ngOnChanges(changes: SimpleChanges): void { + this.initPolicy(); + } + + private initPolicy = ():void => { + this.isLoading.emit(true); + this.policiesService.getSpecificPolicy(this.topologyTemplate.componentType, this.topologyTemplate.uniqueId, this.selectedZoneInstanceId).subscribe( + policy => { + this.policy = policy; + console.log(JSON.stringify(policy)); + }, + error => console.log("Error getting policy!"), + () => this.isLoading.emit(false) + ); + } + + private setIsLoading = (value) :void => { + this.isLoading.emit(value); + } + +} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.module.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.module.ts new file mode 100644 index 0000000000..38dc19e1af --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.module.ts @@ -0,0 +1,68 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +import { NgModule } from "@angular/core"; +import { HttpModule } from "@angular/http"; +import { FormsModule } from "@angular/forms"; +import { BrowserModule } from "@angular/platform-browser"; +import { UiElementsModule } from 'app/ng2/components/ui/ui-elements.module'; +import { ExpandCollapseComponent } from 'app/ng2/components/ui/expand-collapse/expand-collapse.component'; +import { PoliciesService } from "../../../../../services/policies.service"; +import { PolicyInformationTabComponent } from "./policy-information-tab.component"; +import { PolicyTargetsTabComponent } from "./policy-targets-tab.component"; +import { PolicyTabsComponent } from "./policy-tabs.component"; +import { PolicyPropertiesTabComponent } from "./policy-properties-tab.component"; +import { SdcUiComponentsModule } from "sdc-ui/lib/angular"; +import { TranslateModule } from './../../../../../shared/translator/translate.module'; + +@NgModule({ + declarations: [ + PolicyInformationTabComponent, + PolicyTargetsTabComponent, + PolicyPropertiesTabComponent, + PolicyTabsComponent + ], + imports: [ + BrowserModule, + FormsModule, + HttpModule, + SdcUiComponentsModule, + TranslateModule, + UiElementsModule + ], + entryComponents: [ + PolicyInformationTabComponent, + PolicyTargetsTabComponent, + PolicyPropertiesTabComponent, + PolicyTabsComponent, + ExpandCollapseComponent + ], + exports: [ + PolicyInformationTabComponent, + PolicyTargetsTabComponent, + PolicyPropertiesTabComponent, + PolicyTabsComponent + ], + providers: [ + PoliciesService + ] +}) +export class PolicyTabsModule { + +} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.html new file mode 100644 index 0000000000..097b3a4584 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.html @@ -0,0 +1,32 @@ +<div class="w-sdc-designer-sidebar-section-title" titleTooltip="Targets">Targets + <svg-icon-label *ngIf="!isViewOnly" + class="add-policy-button" + name="plus-circle-o" + mode="primary" + size="medium" + label="ADD" + labelPlacement="right" + (click)="openAddTargetModal()"> + </svg-icon-label> +</div> +<div class="expand-collapse-content"> + <ul> + <li *ngFor="let target of targets; let i = index" class="component-details-panel-large-item" + tooltip="{{target.name}}"> + <span>{{target.name}}</span> + <svg-icon-label *ngIf="!isViewOnly" + name="trash-o" + clickable="true" + size="small" + class="component-details-panel-item-delete" + data-tests-id="delete_target" + (click)="deleteTarget(target)"></svg-icon-label> + </li> + </ul> + + <div *ngIf="targets.length===0" class="component-details-panel-tab-no-data"> + <div class="component-details-panel-tab-no-data-title">No data to display yet</div> + <div class="component-details-panel-tab-no-data-content">Add targets to policy to see targets</div> + </div> +</div> + diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.less b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.less new file mode 100644 index 0000000000..cd7ace2b6f --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.less @@ -0,0 +1,12 @@ +/deep/ +.component-details-panel-tab-policy-targets { + .component-details-panel-large-item { + display: flex; + flex-direction: row; + justify-content: space-between; + } + .w-sdc-designer-sidebar-section-title { + display: flex; + justify-content: space-between; + } +}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.ts new file mode 100644 index 0000000000..b79f4d9e07 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.ts @@ -0,0 +1,145 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import * as _ from "lodash"; +import { Component, Input, Output, EventEmitter, OnChanges, HostBinding, OnDestroy } from "@angular/core"; +import { TranslateService } from './../../../../../shared/translator/translate.service'; +import { Component as TopologyTemplate } from "app/models"; +import { PoliciesService } from "../../../../../services/policies.service"; +import { PolicyInstance, PolicyTargetsMap } from './../../../../../../models/graph/zones/policy-instance'; +import { SimpleChanges } from "@angular/core/src/metadata/lifecycle_hooks"; +import { SdcUiComponents } from "sdc-ui/lib/angular"; +import { IModalConfig } from "sdc-ui/lib/angular/modals/models/modal-config"; +import { AddElementsComponent } from "../../../../../components/ui/modal/add-elements/add-elements.component"; +import { TargetUiObject } from "../../../../../../models/ui-models/ui-target-object"; +import { ComponentInstance } from "../../../../../../models/componentsInstances/componentInstance"; +import { TargetOrMemberType } from "../../../../../../utils/constants"; +import { GRAPH_EVENTS } from 'app/utils'; +import { EventListenerService } from 'app/services/event-listener-service'; + +@Component({ + selector: 'policy-targets-tab', + templateUrl: './policy-targets-tab.component.html', + styleUrls: ['./../base/base-tab.component.less', 'policy-targets-tab.component.less'] +}) + +export class PolicyTargetsTabComponent implements OnChanges, OnDestroy { + + private targets: Array<TargetUiObject>; // UI object to hold all targets with names. + + @Input() policy: PolicyInstance; + @Input() topologyTemplate: TopologyTemplate; + @Input() isViewOnly: boolean; + @Output() isLoading: EventEmitter<boolean> = new EventEmitter<boolean>(); + @HostBinding('class') classes = 'component-details-panel-tab-policy-targets'; + + constructor(private translateService: TranslateService, + private policiesService: PoliciesService, + private modalService: SdcUiComponents.ModalService, + private eventListenerService: EventListenerService + ) { + this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_POLICY_INSTANCE_UPDATE, this.initTargets) + } + + ngOnChanges(changes:SimpleChanges):void { + this.initTargets(); + } + + ngOnDestroy() { + this.eventListenerService.unRegisterObserver(GRAPH_EVENTS.ON_POLICY_INSTANCE_UPDATE); + } + + deleteTarget(target: TargetUiObject): void { + this.isLoading.emit(true); + this.policiesService.deletePolicyTarget(this.topologyTemplate.componentType, this.topologyTemplate.uniqueId, this.policy, target.uniqueId, target.type).subscribe( + (policyInstance:PolicyInstance) => { + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_POLICY_INSTANCE_UPDATE, policyInstance); + }, + error => console.log("Error deleting target!"), + () => this.isLoading.emit(false) + ); + } + + private initTargets = (policyInstance?: PolicyInstance) => { + this.policy = policyInstance ? policyInstance : this.policy; + this.targets = this.policy.getTargetsAsUiObject(this.topologyTemplate.componentInstances, this.topologyTemplate.groupInstances); + } + + addTargets = ():void => { + + var targetsToAdd:Array<TargetUiObject> = this.modalService.getCurrentInstance().innerModalContent.instance.existingElements; //TODO refactor sdc-ui modal in order to return the data + if(targetsToAdd.length > 0) { + this.modalService.closeModal(); + this.isLoading.emit(true); + var updatedTarget: Array<TargetUiObject> = _.union(this.targets, targetsToAdd); + this.policiesService.updateTargets(this.topologyTemplate.componentType, this.topologyTemplate.uniqueId, this.policy.uniqueId, updatedTarget).subscribe( + (updatedPolicyInstance:PolicyInstance) => { + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_POLICY_INSTANCE_UPDATE, updatedPolicyInstance); + }, + error => { + console.log("Error updating targets!"); + }, + () => this.isLoading.emit(false) + ); + } + } + + getOptionalsTargetsToAdd():Array<TargetUiObject> { + let optionalsTargetsToAdd:Array<TargetUiObject> = []; + // adding all instances as optional targets to add if not already exist + _.forEach(this.topologyTemplate.componentInstances, (instance:ComponentInstance) => { + if (!_.some(this.targets, (target:TargetUiObject) => { + return target.uniqueId === instance.uniqueId + })) { + optionalsTargetsToAdd.push(new TargetUiObject(instance.uniqueId, TargetOrMemberType.COMPONENT_INSTANCES, instance.name)); + } + }); + + // adding all groups as optional targets to add if not already exist + _.forEach(this.topologyTemplate.groupInstances, (groupInstance:ComponentInstance) => { // adding all instances as optional targets to add if not already exist + if (!_.some(this.targets, (target:TargetUiObject) => { + return target.uniqueId === groupInstance.uniqueId + })) { + optionalsTargetsToAdd.push(new TargetUiObject(groupInstance.uniqueId, TargetOrMemberType.GROUPS, groupInstance.name)); + } + }); + + return optionalsTargetsToAdd; + } + + openAddTargetModal(): void { + let addTargetModalConfig: IModalConfig = { + title: this.policy.name + " ADD TARGETS", + size: "md", + type: "custom", + testId: "addTargetsModal", + buttons: [ + {text: "ADD TARGETS", size: 'xsm', callback: this.addTargets, closeModal: false}, + {text: 'CANCEL', size: 'sm', type: "secondary", closeModal: true} + ] + }; + var optionalTargetsToAdd = this.getOptionalsTargetsToAdd(); + this.modalService.openCustomModal(addTargetModalConfig, AddElementsComponent, { + elementsToAdd: optionalTargetsToAdd, + elementName: "target" + }); + + } +} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel.component.html new file mode 100644 index 0000000000..430b272ff0 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel.component.html @@ -0,0 +1,34 @@ +<ng2-composition-panel-header + [name]="selectedZoneInstanceName" + [topologyTemplate]="topologyTemplate" + [selectedZoneInstanceType]="selectedZoneInstanceType" + [selectedZoneInstanceId]="selectedZoneInstanceId" + [nonCertified]="nonCertified" + [isViewOnly]="isViewOnly" + [isLoading]="isLoading" +></ng2-composition-panel-header> + +<div class="component-details-panel-tabs"> + <loader [display]="isLoading" [size]="'large'" [relative]="true" [loaderDelay]="500"></loader> + + <div *ngIf="selectedZoneInstanceType === zoneInstanceType.POLICY"> + <policy-tabs + [topologyTemplate]="topologyTemplate" + [selectedZoneInstanceType]="selectedZoneInstanceType" + [selectedZoneInstanceId]="selectedZoneInstanceId" + [isViewOnly]="isViewOnly" + (isLoading)="setIsLoading($event)" + ></policy-tabs> + </div> + + <div *ngIf="selectedZoneInstanceType === zoneInstanceType.GROUP"> + <group-tabs + [topologyTemplate]="topologyTemplate" + [selectedZoneInstanceType]="selectedZoneInstanceType" + [selectedZoneInstanceId]="selectedZoneInstanceId" + [isViewOnly]="isViewOnly" + (isLoading)="setIsLoading($event)" + ></group-tabs> + </div> + +</div> diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel.component.less b/catalog-ui/src/app/ng2/pages/composition/panel/panel.component.less new file mode 100644 index 0000000000..1777d54486 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel.component.less @@ -0,0 +1,11 @@ +/deep/ +.component-details-panel { + + color: #666666; + font-family: OpenSans-Regular, sans-serif; + font-size: 14px; + + .component-details-panel-tabs { + + } +} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel.component.ts new file mode 100644 index 0000000000..53599d6366 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel.component.ts @@ -0,0 +1,60 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import * as _ from "lodash"; +import { Component, Inject, Input, Output, EventEmitter, AfterViewInit, SimpleChanges, HostBinding } from "@angular/core"; +import { Component as TopologyTemplate, ComponentInstance, IAppMenu } from "app/models"; +import { PolicyInstance } from 'app/models/graph/zones/policy-instance'; +import { TranslateService } from 'app/ng2/shared/translator/translate.service'; +import { ZoneInstanceType } from "app/models/graph/zones/zone-instance"; +import { GroupsService } from "../../../services/groups.service"; +import { PoliciesService } from "../../../services/policies.service"; +import { SdcUiComponents } from "sdc-ui/lib/angular"; +import { IZoneService } from "../../../../models/graph/zones/zone"; + +@Component({ + selector: 'ng2-composition-panel', + templateUrl: './panel.component.html', + styleUrls: ['./panel.component.less'], + providers: [TranslateService] +}) +export class CompositionPanelComponent { + + @Input() topologyTemplate: TopologyTemplate; + @Input() selectedZoneInstanceType: ZoneInstanceType; + @Input() selectedZoneInstanceId: string; + @Input() selectedZoneInstanceName: string; + @Input() nonCertified: boolean; + @Input() isViewOnly: boolean; + @Input() isLoading: boolean; + + + @HostBinding('class') classes = 'component-details-panel'; + + private zoneInstanceType = ZoneInstanceType; // Expose ZoneInstanceType to use in template. + + constructor(){ + } + + private setIsLoading = (value):void => { + this.isLoading = value; + } + +} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel.module.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel.module.ts new file mode 100644 index 0000000000..57f6be8b8e --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel.module.ts @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +import {NgModule} from "@angular/core"; +import {HttpModule} from "@angular/http"; +import {FormsModule} from "@angular/forms"; +import {BrowserModule} from "@angular/platform-browser"; +import {CompositionPanelComponent} from "./panel.component"; +import {CompositionPanelHeaderModule} from "app/ng2/pages/composition/panel/panel-header/panel-header.module"; +import {GroupTabsModule} from "./panel-tabs/groups/group-tabs.module"; +import {PolicyTabsModule} from "./panel-tabs/policies/policy-tabs.module"; +import {SdcUiComponents} from "sdc-ui/lib/angular"; +import {UiElementsModule} from 'app/ng2/components/ui/ui-elements.module'; +import {AddElementsModule} from "../../../components/ui/modal/add-elements/add-elements.module"; + +@NgModule({ + declarations: [ + CompositionPanelComponent + ], + imports: [ + BrowserModule, + FormsModule, + HttpModule, + CompositionPanelHeaderModule, + PolicyTabsModule, + GroupTabsModule, + UiElementsModule, + AddElementsModule + ], + entryComponents: [ + CompositionPanelComponent + ], + exports: [], + providers: [SdcUiComponents.ModalService] +}) +export class CompositionPanelModule { + +} diff --git a/catalog-ui/src/app/ng2/pages/connection-wizard/connection-wizard.service.ts b/catalog-ui/src/app/ng2/pages/connection-wizard/connection-wizard.service.ts index bf5ec4c4f6..af8dcb4956 100644 --- a/catalog-ui/src/app/ng2/pages/connection-wizard/connection-wizard.service.ts +++ b/catalog-ui/src/app/ng2/pages/connection-wizard/connection-wizard.service.ts @@ -22,19 +22,6 @@ export class ConnectionWizardService { // this.selectedCapability = rel } - - // getComponentInstanceIdOfSelectedCapability = (): string => { - // if(this.selectedMatch.capability){ - // if(this.selectedMatch.isFromTo) { - // return this.selectedMatch.toNode; - // } else { - // return this.selectedMatch.fromNode; - // } - // } - // return ''; - // - // } - getOptionalRequirementsByInstanceUniqueId = (isFromTo: boolean, matchWith?:Capability): Dictionary<Requirement[]> => { let requirements: Array<Requirement> = []; _.forEach(this.connectRelationModel.possibleRelations, (match: Match) => { diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.html b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.html index 03e9f1fa7e..5142bba383 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.html +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.html @@ -10,7 +10,7 @@ [searchTerm]="searchQuery" [selectedPropertyId]="selectedFlatProperty.path" [propertyNameSearchText]="searchPropertyName" - [readonly]="isReadonly" + [readonly]="isReadonly || resourceIsReadonly" [isLoading]="loadingProperties || savingChangedData" [hasDeclareOption]="true" (propertyChanged)="dataChanged($event)" @@ -59,7 +59,7 @@ <hierarchy-navigation class="hierarchy-nav" (updateSelected)="onInstanceSelectedUpdate($event)" [displayData]="isInputsTabSelected ? []: instancesNavigationData" - [selectedItem]="selectedInstanceData.uniqueId" + [selectedItem]="selectedInstanceData?.uniqueId" [displayOptions]="hierarchyInstancesDisplayOptions"></hierarchy-navigation> </div> </tab> @@ -79,9 +79,4 @@ </tabs> </div> </div> - <template #saveChangedDataModalContentTemplate> - <loader [display]="savingChangedData" [size]="'medium'" [relative]="true"></loader> - Your changes{{isValidChangedData ? '' : ' (invalid)'}} have not been saved.<br> - Do you want to {{isValidChangedData ? 'save' : 'discard'}} them? - </template> </div> diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts index 40818bce78..5a21e86879 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts @@ -25,7 +25,7 @@ import { PropertyFEModel, InstanceFePropertiesMap, InstanceBePropertiesMap, Inst import { ResourceType } from "app/utils"; import {ComponentServiceNg2} from "../../services/component-services/component.service"; import {ComponentInstanceServiceNg2} from "../../services/component-instance-services/component-instance.service" -import { InputBEModel, InputFEModel, ComponentInstance, PropertyBEModel, DerivedFEProperty, ResourceInstance, SimpleFlatProperty } from "app/models"; +import { InputBEModel, InputFEModel, ComponentInstance, GroupInstance, PolicyInstance, PropertyBEModel, DerivedFEProperty, SimpleFlatProperty } from "app/models"; import { KeysPipe } from 'app/ng2/pipes/keys.pipe'; import {WorkspaceMode, EVENTS} from "../../../utils/constants"; import {EventListenerService} from "app/services/event-listener-service" @@ -38,6 +38,11 @@ import {ComponentModeService} from "../../services/component-services/component- import {ModalService} from "../../services/modal.service"; import {Tabs, Tab} from "../../components/ui/tabs/tabs.component"; import {InputsUtils} from "./services/inputs.utils"; +import { InstanceFeDetails } from "../../../models/instance-fe-details"; +import { SdcUiComponents } from "sdc-ui/lib/angular"; +//import { ModalService as ModalServiceSdcUI} from "sdc-ui/lib/angular/modals/modal.service"; +import { IModalButtonComponent } from "sdc-ui/lib/angular/modals/models/modal-config"; +import { UnsavedChangesComponent } from "app/ng2/components/ui/forms/unsaved-changes/unsaved-changes.component"; @Component({ templateUrl: './properties-assignment.page.component.html', @@ -47,30 +52,30 @@ export class PropertiesAssignmentComponent { title = "Properties & Inputs"; component: ComponentData; - componentInstanceNamesMap: Map<string, string> = new Map<string, string>();//instanceUniqueId, name + componentInstanceNamesMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();//instanceUniqueId, {name, iconClass} propertiesNavigationData = []; instancesNavigationData = []; instanceFePropertiesMap:InstanceFePropertiesMap; inputs: Array<InputFEModel> = []; - instances: Array<ComponentInstance> = []; + instances: Array<ComponentInstance|GroupInstance|PolicyInstance> = []; searchQuery: string; propertyStructureHeader: string; selectedFlatProperty: SimpleFlatProperty = new SimpleFlatProperty(); - selectedInstanceType: string; - selectedInstanceData: ComponentInstance = new ComponentInstance(); + selectedInstanceData: ComponentInstance|GroupInstance|PolicyInstance = null; checkedPropertiesCount: number = 0; hierarchyPropertiesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('path', 'name', 'childrens'); - hierarchyInstancesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name'); + hierarchyInstancesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name', 'archived', null, 'iconClass'); displayClearSearch = false; searchPropertyName:string; currentMainTab:Tab; isInputsTabSelected:boolean; isPropertiesTabSelected:boolean; isReadonly:boolean; + resourceIsReadonly:boolean; loadingInstances:boolean = false; loadingInputs:boolean = false; loadingProperties:boolean = false; @@ -83,8 +88,7 @@ export class PropertiesAssignmentComponent { @ViewChild('hierarchyNavTabs') hierarchyNavTabs: Tabs; @ViewChild('propertyInputTabs') propertyInputTabs: Tabs; @ViewChild('advanceSearch') advanceSearch: FilterPropertiesAssignmentComponent; - @ViewChild('saveChangedDataModalContentTemplate') saveChangedDataModalContentTemplateRef: TemplateRef<void>; - + constructor(private propertiesService: PropertiesService, private hierarchyNavService: HierarchyNavService, private propertiesUtils:PropertiesUtils, @@ -97,14 +101,15 @@ export class PropertiesAssignmentComponent { @Inject("Notification") private Notification:any, private componentModeService:ComponentModeService, private ModalService:ModalService, - private EventListenerService:EventListenerService) { + private EventListenerService:EventListenerService, + private ModalServiceSdcUI: SdcUiComponents.ModalService) { this.instanceFePropertiesMap = new InstanceFePropertiesMap(); /* This is the way you can access the component data, please do not use any data except metadata, all other data should be received from the new api calls on the first time than if the data is already exist, no need to call the api again - Ask orit if you have any questions*/ this.component = _stateParams.component; - this.EventListenerService.registerObserverCallback(EVENTS.ON_CHECKOUT, this.onCheckout); + this.EventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE, this.onCheckout); this.updateViewMode(); this.changedData = []; @@ -129,13 +134,16 @@ export class PropertiesAssignmentComponent { }, error => {}); //ignore error this.componentServiceNg2 - .getComponentResourceInstances(this.component) + .getComponentResourcePropertiesData(this.component) .subscribe(response => { - this.instances = response.componentInstances; + this.instances = []; + this.instances.push(...response.componentInstances); + this.instances.push(...response.groupInstances); + this.instances.push(...response.policies); _.forEach(this.instances, (instance) => { this.instancesNavigationData.push(instance); - this.componentInstanceNamesMap[instance.uniqueId] = instance.name; + this.componentInstanceNamesMap[instance.uniqueId] = <InstanceFeDetails>{name: instance.name, iconClass:instance.iconClass, originArchived:instance.originArchived}; }); this.loadingInstances = false; if (this.instancesNavigationData[0] == undefined) { @@ -148,17 +156,15 @@ export class PropertiesAssignmentComponent { // stop if has changed properties if (this.hasChangedData) { event.preventDefault(); - this.openChangedDataModal().then((proceed) => { - if (proceed) { - this.$state.go(toState, toParams); - } - }); + this.showUnsavedChangesAlert().then(() => { + this.$state.go(toState, toParams); + }, () => {}); } }); }; ngOnDestroy() { - this.EventListenerService.unRegisterObserver(EVENTS.ON_CHECKOUT); + this.EventListenerService.unRegisterObserver(EVENTS.ON_LIFECYCLE_CHANGE); this.stateChangeStartUnregister(); } @@ -178,47 +184,64 @@ export class PropertiesAssignmentComponent { } - onInstanceSelectedUpdate = (resourceInstance: ResourceInstance) => { - console.log("==>" + this.constructor.name + ": onInstanceSelectedUpdate"); - + onInstanceSelectedUpdate = (instance: ComponentInstance|GroupInstance|PolicyInstance) => { // stop if has changed properties if (this.hasChangedData) { - this.openChangedDataModal().then((proceed) => { - if (proceed) { - this.onInstanceSelectedUpdate(resourceInstance); - } + this.showUnsavedChangesAlert().then((resolve)=> { + this.changeSelectedInstance(instance) + }, (reject) => { }); return; } + this.changeSelectedInstance(instance); + }; - let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap(); - this.selectedInstanceData = resourceInstance; - this.selectedInstanceType = resourceInstance.originType; - + changeSelectedInstance = (instance: ComponentInstance|GroupInstance|PolicyInstance) => { + this.selectedInstanceData = instance; this.loadingProperties = true; - if (this.isInput(resourceInstance.originType)) { + if (instance instanceof ComponentInstance) { + let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap(); + if (this.isInput(instance.originType)) { + this.componentInstanceServiceNg2 + .getComponentInstanceInputs(this.component, instance) + .subscribe(response => { + instanceBePropertiesMap[instance.uniqueId] = response; + this.processInstancePropertiesResponse(instanceBePropertiesMap, true); + this.loadingProperties = false; + }, error => { + }); //ignore error + } else { + this.componentInstanceServiceNg2 + .getComponentInstanceProperties(this.component, instance.uniqueId) + .subscribe(response => { + instanceBePropertiesMap[instance.uniqueId] = response; + this.processInstancePropertiesResponse(instanceBePropertiesMap, false); + this.loadingProperties = false; + }, error => { + }); //ignore error + } + + this.resourceIsReadonly = (instance.componentName === "vnfConfiguration"); + } else if (instance instanceof GroupInstance) { + let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap(); this.componentInstanceServiceNg2 - .getComponentInstanceInputs(this.component, resourceInstance) - .subscribe(response => { - instanceBePropertiesMap[resourceInstance.uniqueId] = response; - this.processInstancePropertiesResponse(instanceBePropertiesMap, true); + .getComponentGroupInstanceProperties(this.component, this.selectedInstanceData.uniqueId) + .subscribe((response) => { + instanceBePropertiesMap[instance.uniqueId] = response; + this.processInstancePropertiesResponse(instanceBePropertiesMap, false); this.loadingProperties = false; - - }, error => { - }); //ignore error - } else { + }); + } else if (instance instanceof PolicyInstance) { + let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap(); this.componentInstanceServiceNg2 - .getComponentInstanceProperties(this.component, resourceInstance.uniqueId) - .subscribe(response => { - instanceBePropertiesMap[resourceInstance.uniqueId] = response; + .getComponentPolicyInstanceProperties(this.component, this.selectedInstanceData.uniqueId) + .subscribe((response) => { + instanceBePropertiesMap[instance.uniqueId] = response; this.processInstancePropertiesResponse(instanceBePropertiesMap, false); this.loadingProperties = false; - }, error => { - }); //ignore error - } - - if (resourceInstance.componentName === "vnfConfiguration") { - this.isReadonly = true; + }); + } else { + this.loadingProperties = false; } if (this.searchPropertyName) { @@ -289,7 +312,7 @@ export class PropertiesAssignmentComponent { this.propertyStructureHeader = null; // Build hirarchy tree for the navigation and update propertiesNavigationData with it. - if(this.selectedInstanceData.originType !== ResourceType.VF) { + if (!(this.selectedInstanceData instanceof ComponentInstance) || this.selectedInstanceData.originType !== ResourceType.VF) { let simpleFlatProperty:Array<SimpleFlatProperty>; if (property instanceof PropertyFEModel) { simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(property, instanceName); @@ -322,14 +345,11 @@ export class PropertiesAssignmentComponent { tabChanged = (event) => { // stop if has changed properties if (this.hasChangedData) { - this.openChangedDataModal().then((proceed) => { - if (proceed) { - this.propertyInputTabs.selectTab(this.propertyInputTabs.tabs.find((tab) => tab.title === event.title)); - } - }); - - // return to show the current tab this.propertyInputTabs.triggerTabChange(this.currentMainTab.title); + this.showUnsavedChangesAlert().then((proceed) => { + this.propertyInputTabs.selectTab(this.propertyInputTabs.tabs.find((tab) => tab.title === event.title)); + }, ()=> { + }); return; } @@ -347,21 +367,28 @@ export class PropertiesAssignmentComponent { declareProperties = (): void => { console.log("==>" + this.constructor.name + ": declareProperties"); - let selectedProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap(); - let selectedInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap(); + let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap(); + let selectedGroupInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap(); + let selectedPolicyInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap(); + let selectedComponentInstancesInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap(); let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []); angular.forEach(instancesIds, (instanceId: string): void => { - let selectedInstanceData: ResourceInstance = this.instances.find(instance => instance.uniqueId == instanceId); - let originType: string = (selectedInstanceData) ? selectedInstanceData.originType : this.selectedInstanceType; - if (!this.isInput(originType)) { - selectedProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]); - } else { - selectedInputs[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]); + let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId); + if (selectedInstanceData instanceof ComponentInstance) { + if (!this.isInput(selectedInstanceData.originType)) { + selectedComponentInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]); + } else { + selectedComponentInstancesInputs[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]); + } + } else if (selectedInstanceData instanceof GroupInstance) { + selectedGroupInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]); + } else if (selectedInstanceData instanceof PolicyInstance) { + selectedPolicyInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]); } }); - let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedInputs, selectedProperties); + let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedComponentInstancesInputs, selectedComponentInstancesProperties, selectedGroupInstancesProperties, selectedPolicyInstancesProperties); this.componentServiceNg2 .createInput(this.component, inputsToCreate) @@ -399,20 +426,46 @@ export class PropertiesAssignmentComponent { return propBE; }); - if (this.isInput(this.selectedInstanceData.originType)) { + if (this.selectedInstanceData instanceof ComponentInstance) { + if (this.isInput(this.selectedInstanceData.originType)) { + request = this.componentInstanceServiceNg2 + .updateInstanceInputs(this.component, this.selectedInstanceData.uniqueId, changedProperties); + handleSuccess = (response) => { + // reset each changed property with new value and remove it from changed properties list + response.forEach((resInput) => { + const changedProp = <PropertyFEModel>this.changedData.shift(); + this.propertiesUtils.resetPropertyValue(changedProp, resInput.value); + }); + console.log('updated instance inputs:', response); + }; + } else { + request = this.componentInstanceServiceNg2 + .updateInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedProperties) + handleSuccess = (response) => { + // reset each changed property with new value and remove it from changed properties list + response.forEach((resProp) => { + const changedProp = <PropertyFEModel>this.changedData.shift(); + this.propertiesUtils.resetPropertyValue(changedProp, resProp.value); + }); + resolve(response); + console.log("updated instance properties: ", response); + }; + } + } else if (this.selectedInstanceData instanceof GroupInstance) { request = this.componentInstanceServiceNg2 - .updateInstanceInputs(this.component, this.selectedInstanceData.uniqueId, changedProperties); + .updateComponentGroupInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedProperties); handleSuccess = (response) => { // reset each changed property with new value and remove it from changed properties list - response.forEach((resInput) => { + response.forEach((resProp) => { const changedProp = <PropertyFEModel>this.changedData.shift(); - this.propertiesUtils.resetPropertyValue(changedProp, resInput.value); + this.propertiesUtils.resetPropertyValue(changedProp, resProp.value); }); - console.log('updated instance inputs:', response); + resolve(response); + console.log("updated group instance properties: ", response); }; - } else { + } else if (this.selectedInstanceData instanceof PolicyInstance) { request = this.componentInstanceServiceNg2 - .updateInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedProperties) + .updateComponentPolicyInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedProperties); handleSuccess = (response) => { // reset each changed property with new value and remove it from changed properties list response.forEach((resProp) => { @@ -420,7 +473,7 @@ export class PropertiesAssignmentComponent { this.propertiesUtils.resetPropertyValue(changedProp, resProp.value); }); resolve(response); - console.log("updated instance properties: ", response); + console.log("updated policy instance properties: ", response); }; } } else if (this.isInputsTabSelected) { @@ -484,66 +537,59 @@ export class PropertiesAssignmentComponent { const curHasChangedData:boolean = (this.changedData.length > 0); if (curHasChangedData !== this.hasChangedData) { this.hasChangedData = curHasChangedData; - this.$scope.$emit('setWorkspaceTopBarActive', !this.hasChangedData); - } + if(this.hasChangedData) { + this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, this.hasChangedData, this.showUnsavedChangesAlert); + } else { + this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, false); + } + } return this.hasChangedData; }; - doSaveChangedData = ():void => { + doSaveChangedData = (onSuccessFunction?:Function, onError?:Function):void => { this.saveChangedData().then( () => { this.Notification.success({ message: 'Successfully saved changes', title: 'Saved' }); + if(onSuccessFunction) onSuccessFunction(); }, () => { this.Notification.error({ message: 'Failed to save changes!', title: 'Failure' }); + if(onError) onError(); } ); }; - openChangedDataModal = ():Promise<boolean> => { - let modalTitle; + showUnsavedChangesAlert = ():Promise<any> => { + let modalTitle:string; if (this.isPropertiesTabSelected) { modalTitle = `Unsaved properties for ${this.selectedInstanceData.name}`; } else if (this.isInputsTabSelected) { modalTitle = `Unsaved inputs for ${this.component.name}`; } - return new Promise<boolean>((resolve) => { - const modal = this.ModalService.createCustomModal(new ModalModel( - 'sm', - modalTitle, - null, - [ - new ButtonModel('Cancel', 'outline grey', () => { - modal.instance.close(); - resolve(false); - }), - new ButtonModel('Discard', 'outline blue', () => { - this.reverseChangedData(); - modal.instance.close(); - resolve(true); - }), - new ButtonModel('Save', 'blue', () => { - this.saveChangedData().then(() => { - modal.instance.close(); - resolve(true); - }, () => { - modal.instance.close(); - resolve(false); - }); - }, () => !this.isValidChangedData) - ] - )); - this.ModalService.addDynamicTemplateToModal(modal, this.saveChangedDataModalContentTemplateRef); - modal.instance.open(); + return new Promise<any>((resolve, reject) => { + const modal = this.ModalServiceSdcUI.openCustomModal( + { + title: modalTitle, + size: 'sm', + type: 'custom', + testId: "id", + + 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.reverseChangedData(); resolve()}}, + {id: 'saveButton', text: 'Save', type: 'primary', size: 'xsm', closeModal: true, disabled: !this.isValidChangedData, callback: () => this.doSaveChangedData(resolve, reject)} + ] as IModalButtonComponent[] + }, UnsavedChangesComponent, {isValidChangedData: this.isValidChangedData}); }); - }; + + } updatePropertyValueAfterDeclare = (input: InputFEModel) => { if (this.instanceFePropertiesMap[input.instanceUniqueId]) { @@ -567,7 +613,16 @@ export class PropertiesAssignmentComponent { this.propertyInputTabs.setTabIndication('Inputs', numInputs); }; + resetUnsavedChangesForInput = (input:InputFEModel) => { + this.inputsUtils.resetInputDefaultValue(input, input.defaultValue); + this.changedData = this.changedData.filter((changedItem) => changedItem.uniqueId !== input.uniqueId); + this.updateHasChangedData(); + } + deleteInput = (input: InputFEModel) => { + //reset any unsaved changes to the input before deleting it + this.resetUnsavedChangesForInput(input); + console.log("==>" + this.constructor.name + ": deleteInput"); let inputToDelete = new InputBEModel(input); @@ -577,7 +632,7 @@ export class PropertiesAssignmentComponent { this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId); //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead! - this.onInstanceSelectedUpdate(this.selectedInstanceData); + this.changeSelectedInstance(this.selectedInstanceData); // let instanceFeProperties = this.instanceFePropertiesMap[this.getInstanceUniqueId(input.instanceName)]; // if (instanceFeProperties) { diff --git a/catalog-ui/src/app/ng2/pages/service-path-creator/link-row/link-row.component.html b/catalog-ui/src/app/ng2/pages/service-path-creator/link-row/link-row.component.html index bbbf6ae694..e029b7f1fa 100644 --- a/catalog-ui/src/app/ng2/pages/service-path-creator/link-row/link-row.component.html +++ b/catalog-ui/src/app/ng2/pages/service-path-creator/link-row/link-row.component.html @@ -1,5 +1,45 @@ -<ui-element-dropdown data-tests-id="linkSrc" [readonly]="!link.isFirst || (link.isFirst && !link.canEdit)" class="cell link-selector" [values]="source" [(value)]="link.fromNode" (valueChange)="onSourceSelected($event)"></ui-element-dropdown> -<ui-element-dropdown data-tests-id="linkSrcCP" [readonly]="!link.isFirst || (link.isFirst && !link.canEdit)" class="cell link-selector" [values]="srcCP" [(value)]="link.fromCP" (valueChange)="onSrcCPSelected($event)"></ui-element-dropdown> -<ui-element-dropdown data-tests-id="linkTarget" [readonly]="!link.canEdit" class="cell link-selector" [values]="target" [(value)]="link.toNode" (valueChange)="onTargetSelected($event)"></ui-element-dropdown> -<ui-element-dropdown data-tests-id="linkTargetCP" [readonly]="!link.canEdit" class="cell link-selector" [values]="targetCP" [(value)]="link.toCP" (valueChange)="onTargetCPSelected($event)"></ui-element-dropdown> -<div class="cell remove" data-tests-id="removeLnk"><span *ngIf="link.canRemove" class="sprite-new delete-item-icon" (click)="removeRow()"></span></div>
\ No newline at end of file +<ui-element-dropdown + data-tests-id="linkSrc" + [readonly]="!link.isFirst || (link.isFirst && !link.canEdit)" + class="cell link-selector" + [values]="source" + [(value)]="link.fromNode" + (valueChange)="onSourceSelected($event)"> +</ui-element-dropdown> + +<ui-element-dropdown + data-tests-id="linkSrcCP" + [readonly]="!link.isFirst || (link.isFirst && !link.canEdit)" + class="cell link-selector" + [values]="srcCP" + [(value)]="link.fromCP" + (valueChange)="onSrcCPSelected($event)"> +</ui-element-dropdown> + +<ui-element-dropdown + data-tests-id="linkTarget" + [readonly]="!link.canEdit" + class="cell link-selector" + [values]="target" + [(value)]="link.toNode" + (valueChange)="onTargetSelected($event)"> +</ui-element-dropdown> + +<ui-element-dropdown + data-tests-id="linkTargetCP" + [readonly]="!link.canEdit" + class="cell link-selector" + [values]="targetCP" + [(value)]="link.toCP" + (valueChange)="onTargetCPSelected($event)"> +</ui-element-dropdown> + +<div + class="cell remove" + data-tests-id="removeLnk"> + <span + *ngIf="link.canRemove" + class="sprite-new delete-item-icon" + (click)="removeRow()"> + </span> +</div> diff --git a/catalog-ui/src/app/ng2/pages/service-path-creator/link-row/link-row.component.ts b/catalog-ui/src/app/ng2/pages/service-path-creator/link-row/link-row.component.ts index 16433242d6..e4fc1d4522 100644 --- a/catalog-ui/src/app/ng2/pages/service-path-creator/link-row/link-row.component.ts +++ b/catalog-ui/src/app/ng2/pages/service-path-creator/link-row/link-row.component.ts @@ -14,7 +14,7 @@ export class LinkRowComponent { @Input() data:Array<ServicePathMapItem>; @Input() link:Link; @Input() removeRow:Function; - source:Array<DropdownValue> = []; + source: Array<DropdownValue> = []; target: Array<DropdownValue> = []; srcCP: Array<DropdownValue> = []; targetCP: Array<DropdownValue> = []; @@ -32,11 +32,9 @@ export class LinkRowComponent { if (!srcCPOptions) { return; } this.srcCP = this.convertValuesToDropDownOptions(srcCPOptions); if (this.link.fromCP) { - let targetOptions = this.findOptions(srcCPOptions, this.link.fromCP); - if (!targetOptions) { return; } - this.target = this.convertValuesToDropDownOptions(targetOptions); + this.target = this.convertValuesToDropDownOptions(data); if (this.link.toNode) { - let targetCPOptions = this.findOptions(targetOptions, this.link.toNode); + let targetCPOptions = this.findOptions(data, this.link.toNode); if (!targetCPOptions) { return; } this.targetCP = this.convertValuesToDropDownOptions(targetCPOptions); } @@ -45,7 +43,7 @@ export class LinkRowComponent { } private findOptions(items: Array<ServicePathMapItem>, nodeOrCPId: string) { - let item = items.find((dataItem)=> nodeOrCPId === dataItem.id); + let item = _.find(items, (dataItem) => nodeOrCPId === dataItem.id); if (item && item.data && item.data.options) { return item.data.options; } @@ -53,12 +51,12 @@ export class LinkRowComponent { return null; } - private convertValuesToDropDownOptions(values: Array<ServicePathMapItem>) : Array<DropdownValue> { - let result = []; + private convertValuesToDropDownOptions(values: Array<ServicePathMapItem>): Array<DropdownValue> { + let result:Array<DropdownValue> = []; for (let i = 0; i < values.length ; i++) { result[result.length] = new DropdownValue(values[i].id, values[i].data.name); } - return result; + return result.sort((a, b) => a.label.localeCompare(b.label)); } onSourceSelected(id) { @@ -75,10 +73,9 @@ export class LinkRowComponent { onSrcCPSelected (id) { if (id) { - let srcCPData = this.data.find((dataItem)=> this.link.fromNode === dataItem.id).data; - let srcCPOptions = srcCPData.options; - let targetOptions = this.findOptions(srcCPOptions, id); - this.target = this.convertValuesToDropDownOptions(targetOptions); + let srcCPOptions = this.findOptions(this.data, this.link.fromNode); + let srcCPData = srcCPOptions.find(option => id === option.id).data; + this.target = this.convertValuesToDropDownOptions(this.data); this.link.fromCPOriginId = srcCPData.ownerId; this.link.toNode = ''; this.link.toCP = ''; @@ -89,9 +86,7 @@ export class LinkRowComponent { onTargetSelected(id) { if (id) { - let srcCPOptions = this.findOptions(this.data, this.link.fromNode); - let targetOptions = this.findOptions(srcCPOptions, this.link.fromCP); - let targetCPOptions = this.findOptions(targetOptions, id); + let targetCPOptions = this.findOptions(this.data, id); this.targetCP = this.convertValuesToDropDownOptions(targetCPOptions); this.link.toCP = ''; } @@ -100,11 +95,9 @@ export class LinkRowComponent { onTargetCPSelected(id) { if (id) { - let srcCPOptions = this.findOptions(this.data, this.link.fromNode); - let targetOptions = this.findOptions(srcCPOptions, this.link.fromCP); - let targetCPOptions = this.findOptions(targetOptions, this.link.toNode); - let targetCPDataObj = targetCPOptions.find((dataItem)=> id === dataItem.id).data; + let targetCPOptions = this.findOptions(this.data, this.link.toNode); + let targetCPDataObj = targetCPOptions.find(option => id === option.id).data; this.link.toCPOriginId = targetCPDataObj.ownerId; } } -}
\ No newline at end of file +} diff --git a/catalog-ui/src/app/ng2/pages/service-path-creator/service-path-creator.component.html b/catalog-ui/src/app/ng2/pages/service-path-creator/service-path-creator.component.html index 96cd83eef6..76c5c53290 100644 --- a/catalog-ui/src/app/ng2/pages/service-path-creator/service-path-creator.component.html +++ b/catalog-ui/src/app/ng2/pages/service-path-creator/service-path-creator.component.html @@ -1,27 +1,24 @@ <div class="service-path-creator"> <form class="w-sdc-form"> <div class="i-sdc-form-item" > - <label class="i-sdc-form-label required">Path Name</label> - <!-- <ui-element-input type="text" name="pathName" [value]="pathName" ></ui-element-input> --> - <input type="text" data-tests-id="pathName" name="pathName" [(ngModel)]="forwardingPath.name" [attr.maxLength]="100" /> <!-- TODO - make unique --> + <label class="i-sdc-form-label required">Flow Name</label> + <input type="text" data-tests-id="pathName" name="pathName" [(ngModel)]="forwardingPath.name" [attr.maxLength]="200" /> </div> <div class="side-by-side"> <div class="i-sdc-form-item" > <label class="i-sdc-form-label">Protocol</label> - <!-- <ui-element-input type="text" name="protocol" [value]="protocol" ></ui-element-input> --> - <input type="text" data-tests-id="pathProtocol" name="protocol" [(ngModel)]="forwardingPath.protocol" [attr.maxLength]="100" /> + <input type="text" data-tests-id="pathProtocol" name="protocol" [(ngModel)]="forwardingPath.protocol" [attr.maxLength]="200" /> </div> <div class="i-sdc-form-item" > <label class="i-sdc-form-label">Destination Port Numbers</label> - <!-- <ui-element-input type="text" name="portNumbers" [value]="portNumbers" ></ui-element-input> --> - <input type="text" data-tests-id="pathPortNumbers" name="portNumbers" [(ngModel)]="forwardingPath.destinationPortNumber" pattern="[0-9,]*" /> <!-- TODO - validate delimiter --> + <input type="text" data-tests-id="pathPortNumbers" name="portNumbers" [(ngModel)]="forwardingPath.destinationPortNumber" pattern="[0-9,]*" /> </div> </div> <div class="separator-buttons"> <span class="based-on-title">Based On</span> - <a (click)="addRow()" [ngClass]="{'disabled':!isExtendAllowed()}" data-tests-id="extendPathlnk">Extend Path</a> + <a (click)="addRow()" [ngClass]="{'disabled':!isExtendAllowed()}" data-tests-id="extendPathlnk">Extend Flow</a> </div> <div class="generic-table"> diff --git a/catalog-ui/src/app/ng2/pages/service-path-creator/service-path-creator.component.ts b/catalog-ui/src/app/ng2/pages/service-path-creator/service-path-creator.component.ts index dac41a37bc..bffb1c5e7e 100644 --- a/catalog-ui/src/app/ng2/pages/service-path-creator/service-path-creator.component.ts +++ b/catalog-ui/src/app/ng2/pages/service-path-creator/service-path-creator.component.ts @@ -73,12 +73,11 @@ export class ServicePathCreatorComponent { this.forwardingPath.uniqueId = forwardingPath.uniqueId; this.links = []; _.forEach(forwardingPath.pathElements.listToscaDataDefinition, (link:ForwardingPathLink) => { - this.links[this.links.length] = new Link( link, false, false, false); + this.links[this.links.length] = new Link(link, false, false, false); }); - this.links[this.links.length -1].canEdit = true; - this.links[this.links.length -1].canRemove = true; + this.links[this.links.length - 1].canEdit = true; + this.links[this.links.length - 1].canRemove = true; this.links[0].isFirst = true; - } } @@ -98,7 +97,18 @@ export class ServicePathCreatorComponent { addRow() { this.disableRows(); - this.links[this.links.length] = new Link( new ForwardingPathLink(this.links[this.links.length-1].toNode,this.links[this.links.length-1].toCP,'','',this.links[this.links.length-1].toCPOriginId,''),true, true, false); + this.links[this.links.length] = new Link( + new ForwardingPathLink(this.links[this.links.length-1].toNode, + this.links[this.links.length-1].toCP, + '', + '', + this.links[this.links.length-1].toCPOriginId, + '' + ), + true, + true, + false + ); } disableRows() { diff --git a/catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.html b/catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.html index 8a31c76998..39c41916a2 100644 --- a/catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.html +++ b/catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.html @@ -1,5 +1,5 @@ <div class="service-path-list"> - <div class="add-path-link"><a (click)="onAddServicePath()" data-tests-id="add-service-path-lnk" >+ Add Path</a></div> + <div class="add-path-link" *ngIf="!isViewOnly"><a (click)="onAddServicePath()" data-tests-id="add-service-path-lnk" >+ Add Flow</a></div> <div class="generic-table table-container" > <div class="header-row"> <div class="cell header-cell" *ngFor="let header of headers"> @@ -10,11 +10,11 @@ <div class="cell" data-tests-id="path-name" >{{path.name}}</div> <div class="cell path-action-buttons"> <span class="sprite-new update-component-icon" (click)="onEditServicePath(path.uniqueId)" data-tests-id="update-service-path-btn" ></span> - <span class="sprite-new delete-item-icon" (click)="deletePath(path.uniqueId)" data-tests-id="delete-service-path-btn"></span> + <span class="sprite-new delete-item-icon" *ngIf="!isViewOnly" (click)="deletePath(path.uniqueId)" data-tests-id="delete-service-path-btn"></span> </div> </div> <div *ngIf="paths && paths.length === 0" class="no-row-text" > - No paths have been added yet. + No flows have been added yet. </div> </div> diff --git a/catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.less b/catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.less index aff597fd85..291119f58c 100644 --- a/catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.less +++ b/catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.less @@ -18,4 +18,7 @@ .sprite-new { cursor: pointer; } + & > span:only-child { + margin: auto; +} }
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.ts b/catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.ts index 04083e8685..1625ab4b66 100644 --- a/catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.ts +++ b/catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.ts @@ -38,9 +38,10 @@ export default class ServicePathsListComponent { input:any; onAddServicePath: Function; onEditServicePath: Function; + isViewOnly: boolean; constructor(private serviceService:ServiceServiceNg2) { - this.headers = ['Path Name','Actions']; + this.headers = ['Flow Name','Actions']; } ngOnInit() { @@ -52,6 +53,7 @@ export default class ServicePathsListComponent { }); this.onAddServicePath = this.input.onCreateServicePath; this.onEditServicePath = this.input.onEditServicePath; + this.isViewOnly = this.input.isViewOnly; } deletePath = (id:string):void => { diff --git a/catalog-ui/src/app/ng2/pipes/global-pipes.module.ts b/catalog-ui/src/app/ng2/pipes/global-pipes.module.ts index 3761aa808f..758a7e886c 100644 --- a/catalog-ui/src/app/ng2/pipes/global-pipes.module.ts +++ b/catalog-ui/src/app/ng2/pipes/global-pipes.module.ts @@ -2,6 +2,7 @@ import {ContentAfterLastDotPipe} from "./contentAfterLastDot.pipe"; import {SearchFilterPipe} from "./searchFilter.pipe"; import {KeysPipe} from "./keys.pipe"; import {GroupByPipe} from "./groupBy.pipe"; +import {ResourceNamePipe} from "./resource-name.pipe"; import {NgModule} from "@angular/core"; import {SafeUrlSanitizerPipe} from "./safeUrlSanitizer.pipe"; @@ -10,15 +11,17 @@ import {SafeUrlSanitizerPipe} from "./safeUrlSanitizer.pipe"; ContentAfterLastDotPipe, GroupByPipe, KeysPipe, + SafeUrlSanitizerPipe, SearchFilterPipe, - SafeUrlSanitizerPipe + ResourceNamePipe ], exports: [ ContentAfterLastDotPipe, GroupByPipe, KeysPipe, + SafeUrlSanitizerPipe, SearchFilterPipe, - SafeUrlSanitizerPipe + ResourceNamePipe ] }) diff --git a/catalog-ui/src/app/ng2/services/responses/properties.response.ts b/catalog-ui/src/app/ng2/pipes/resource-name.pipe.ts index a1c0660c0f..fdf9526375 100644 --- a/catalog-ui/src/app/ng2/services/responses/properties.response.ts +++ b/catalog-ui/src/app/ng2/pipes/resource-name.pipe.ts @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,10 +18,17 @@ * ============LICENSE_END========================================================= */ -export class PropertiesResponse { - properties: Array<Property>; -} -class Property { - name: string +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({name: 'resourceName'}) +export class ResourceNamePipe implements PipeTransform { + transform(value) : any { + if (value) { + //newName = _.last(newName.split('.')); + const newName:string = + _.last(value.split(/tosca\.nodes\..*network\..*relationships\..*org\.openecomp\..*resource\.nfv\..*nodes\.module\..*cp\..*vl\./)); + return (newName) ? newName : value; + } + } } diff --git a/catalog-ui/src/app/ng2/services/archive.service.ts b/catalog-ui/src/app/ng2/services/archive.service.ts new file mode 100644 index 0000000000..83f1c502c2 --- /dev/null +++ b/catalog-ui/src/app/ng2/services/archive.service.ts @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import { Injectable, Inject } from "@angular/core"; +import { Observable } from "rxjs/Observable"; +import { HttpService } from "./http.service"; +import { SdcConfigToken, ISdcConfig } from "../config/sdc-config.config"; +import { Component } from "../../models"; +import { ComponentFactory } from 'app/utils/component-factory'; + + +@Injectable() +export class ArchiveService { + protected baseUrl; + + constructor(private http: HttpService, @Inject(SdcConfigToken) sdcConfig:ISdcConfig, private componentFactory:ComponentFactory/*, @Inject(ComponentFactory) componentFactory */) { + this.baseUrl = sdcConfig.api.root ; + } + + public getArchiveCatalog() { + let archiveCatalogItems:Component[] = []; + let archiveCatalogResourceItems:Component[] = []; + let archiveCatalogServiceItems:Component[] = []; + + return this.http.get(this.baseUrl + '/v1/catalog/archive/', {}).map(res => { + let archiveCatalogObject = res.json(); + if (archiveCatalogObject.resources) archiveCatalogResourceItems = this.getResourceItems(archiveCatalogObject.resources); + if (archiveCatalogObject.services) archiveCatalogServiceItems = this.getServiceItems(archiveCatalogObject.services); + archiveCatalogItems = [].concat(archiveCatalogResourceItems, archiveCatalogServiceItems); + + return archiveCatalogItems; + }); + } + + + private getResourceItems(resources){ + let resourceItems = resources.map((resource)=>{ + return this.componentFactory.createResource(resource) + }) + return resourceItems; + } + + private getServiceItems(services){ + let serviceItems = services.map((service)=>{ + return this.componentFactory.createService(service) + }) + return serviceItems; + } + +}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/services/component-instance-services/component-instance.service.ts b/catalog-ui/src/app/ng2/services/component-instance-services/component-instance.service.ts index 0947b2aa7f..15750020dc 100644 --- a/catalog-ui/src/app/ng2/services/component-instance-services/component-instance.service.ts +++ b/catalog-ui/src/app/ng2/services/component-instance-services/component-instance.service.ts @@ -92,4 +92,32 @@ export class ComponentInstanceServiceNg2 { return res.json().map((resInput) => new PropertyBEModel(resInput)); }); } + + getComponentGroupInstanceProperties(component: Component, groupInstanceId: string): Observable<Array<PropertyBEModel>> { + return this.http.get(this.baseUrl + component.getTypeUrl() + component.uniqueId + '/groups/' + groupInstanceId + '/properties') + .map((res: Response) => { + return CommonUtils.initBeProperties(res.json()); + }); + } + + updateComponentGroupInstanceProperties(component: Component, groupInstanceId: string, properties: PropertyBEModel[]): Observable<Array<PropertyBEModel>> { + return this.http.put(this.baseUrl + component.getTypeUrl() + component.uniqueId + '/groups/' + groupInstanceId + '/properties', properties) + .map((res: Response) => { + return res.json().map((resProperty) => new PropertyBEModel(resProperty)); + }); + } + + getComponentPolicyInstanceProperties(component: Component, policyInstanceId: string): Observable<Array<PropertyBEModel>> { + return this.http.get(this.baseUrl + component.getTypeUrl() + component.uniqueId + '/policies/' + policyInstanceId + '/properties') + .map((res: Response) => { + return CommonUtils.initBeProperties(res.json()); + }); + } + + updateComponentPolicyInstanceProperties(component: Component, policyInstanceId: string, properties: PropertyBEModel[]): Observable<Array<PropertyBEModel>> { + return this.http.put(this.baseUrl + component.getTypeUrl() + component.uniqueId + '/policies/' + policyInstanceId + '/properties', properties) + .map((res: Response) => { + return res.json().map((resProperty) => new PropertyBEModel(resProperty)); + }); + } } diff --git a/catalog-ui/src/app/ng2/services/component-services/component.service.ts b/catalog-ui/src/app/ng2/services/component-services/component.service.ts index 381995d91c..3546ebd374 100644 --- a/catalog-ui/src/app/ng2/services/component-services/component.service.ts +++ b/catalog-ui/src/app/ng2/services/component-services/component.service.ts @@ -25,6 +25,7 @@ import 'rxjs/add/operator/map'; import 'rxjs/add/operator/toPromise'; import {Response, URLSearchParams} from '@angular/http'; import { Component, InputBEModel, InstancePropertiesAPIMap, FilterPropertiesAssignmentData, OperationModel, CreateOperationResponse} from "app/models"; +import {downgradeInjectable} from '@angular/upgrade/static'; import {COMPONENT_FIELDS} from "app/utils"; import {ComponentGenericResponse} from "../responses/component-generic-response"; import {InstanceBePropertiesMap} from "../../../models/properties-inputs/property-fe-map"; @@ -32,6 +33,9 @@ import {API_QUERY_PARAMS} from "app/utils"; import { ComponentType, ServerTypeUrl } from "../../../utils/constants"; import { HttpService } from '../http.service'; import {SdcConfigToken, ISdcConfig} from "../../config/sdc-config.config"; +import {IDependenciesServerResponse} from "../responses/dependencies-server-response"; +import {AutomatedUpgradeGenericResponse} from "../responses/automated-upgrade-response"; +import {IAutomatedUpgradeRequestObj} from "../../pages/automated-upgrade/automated-upgrade.service"; declare var angular:angular.IAngularStatic; @@ -83,7 +87,11 @@ export class ComponentServiceNg2 { } getComponentCompositionData(component:Component):Observable<ComponentGenericResponse> { - return this.getComponentDataByFieldsName(component.componentType, component.uniqueId, [COMPONENT_FIELDS.COMPONENT_INSTANCES_RELATION, COMPONENT_FIELDS.COMPONENT_INSTANCES, COMPONENT_FIELDS.COMPONENT_POLICIES, COMPONENT_FIELDS.COMPONENT_GROUPS]); + return this.getComponentDataByFieldsName(component.componentType, component.uniqueId, [COMPONENT_FIELDS.COMPONENT_INSTANCES_RELATION, COMPONENT_FIELDS.COMPONENT_INSTANCES, COMPONENT_FIELDS.COMPONENT_NON_EXCLUDED_POLICIES, COMPONENT_FIELDS.COMPONENT_NON_EXCLUDED_GROUPS]); + } + + getComponentResourcePropertiesData(component:Component):Observable<ComponentGenericResponse> { + return this.getComponentDataByFieldsName(component.componentType, component.uniqueId, [COMPONENT_FIELDS.COMPONENT_INSTANCES, COMPONENT_FIELDS.COMPONENT_POLICIES, COMPONENT_FIELDS.COMPONENT_NON_EXCLUDED_GROUPS]); } getComponentResourceInstances(component:Component):Observable<ComponentGenericResponse> { @@ -171,6 +179,15 @@ export class ComponentServiceNg2 { }) } + restoreComponent(componentType:string, componentId:string){ + return this.http.post(this.baseUrl + this.getServerTypeUrl(componentType) + componentId + '/restore', {}) + } + + archiveComponent(componentType:string, componentId:string){ + return this.http.post(this.baseUrl + this.getServerTypeUrl(componentType) + componentId + '/archive', {}) + } + + deleteInput(component:Component, input:InputBEModel):Observable<InputBEModel> { return this.http.delete(this.baseUrl + component.getTypeUrl() + component.uniqueId + '/delete/' + input.uniqueId + '/input') @@ -198,5 +215,19 @@ export class ComponentServiceNg2 { return res.json(); }); } + + getDependencies(componentType:string, componentId: string):Observable<Array<IDependenciesServerResponse>> { + return this.http.get(this.baseUrl + this.getServerTypeUrl(componentType) + componentId + '/dependencies') + .map((res:Response) => { + return res.json(); + }); + } + + automatedUpgrade(componentType:string, componentId: string, componentsIdsToUpgrade:Array<IAutomatedUpgradeRequestObj>):Observable<AutomatedUpgradeGenericResponse> { + return this.http.post(this.baseUrl + this.getServerTypeUrl(componentType) + componentId + '/automatedupgrade', componentsIdsToUpgrade) + .map((res:Response) => { + return res.json(); + }); + } } diff --git a/catalog-ui/src/app/ng2/services/component-services/service.service.ts b/catalog-ui/src/app/ng2/services/component-services/service.service.ts index 0439f2047e..15e624b81f 100644 --- a/catalog-ui/src/app/ng2/services/component-services/service.service.ts +++ b/catalog-ui/src/app/ng2/services/component-services/service.service.ts @@ -126,7 +126,7 @@ export class ServiceServiceNg2 extends ComponentServiceNg2 { } getComponentCompositionData(component:Component):Observable<ComponentGenericResponse> { - return this.getComponentDataByFieldsName(component.componentType, component.uniqueId, [COMPONENT_FIELDS.COMPONENT_INSTANCES_RELATION, COMPONENT_FIELDS.COMPONENT_INSTANCES, SERVICE_FIELDS.FORWARDING_PATHS]); + return this.getComponentDataByFieldsName(component.componentType, component.uniqueId, [COMPONENT_FIELDS.COMPONENT_INSTANCES_RELATION, COMPONENT_FIELDS.COMPONENT_INSTANCES, SERVICE_FIELDS.FORWARDING_PATHS, COMPONENT_FIELDS.COMPONENT_NON_EXCLUDED_POLICIES, COMPONENT_FIELDS.COMPONENT_NON_EXCLUDED_GROUPS]); } protected analyzeComponentDataResponse(res: Response):ComponentGenericResponse { diff --git a/catalog-ui/src/app/ng2/services/config.service.ts b/catalog-ui/src/app/ng2/services/config.service.ts index a9a4e86a55..1774a663e2 100644 --- a/catalog-ui/src/app/ng2/services/config.service.ts +++ b/catalog-ui/src/app/ng2/services/config.service.ts @@ -38,7 +38,7 @@ export class ConfigService { constructor(private http: Http, @Inject(SdcConfigToken) private sdcConfig:ISdcConfig) { this.api = this.sdcConfig.api; - this.baseUrl = this.sdcConfig.api.root + this.sdcConfig.api.component_api_root; + this.baseUrl = this.api.root + this.sdcConfig.api.component_api_root; } loadValidationConfiguration(): Promise<ValidationConfiguration> { diff --git a/catalog-ui/src/app/ng2/services/groups.service.ts b/catalog-ui/src/app/ng2/services/groups.service.ts new file mode 100644 index 0000000000..e3b3d85b50 --- /dev/null +++ b/catalog-ui/src/app/ng2/services/groups.service.ts @@ -0,0 +1,78 @@ +import {IZoneInstanceAssignment} from '../../models/graph/zones/zone-instance'; +import {Injectable, Inject} from "@angular/core"; +import {Observable} from "rxjs/Observable"; +import {HttpService} from "./http.service"; +import {SdcConfigToken, ISdcConfig} from "../config/sdc-config.config"; +import {GroupInstance} from '../../models/graph/zones/group-instance'; +import {UiBaseObject} from "../../models/ui-models/ui-base-object"; +import {IZoneService} from "../../models/graph/zones/zone"; + +@Injectable() +export class GroupsService implements IZoneService { + + protected baseUrl; + + private mapApiDirections = { + 'RESOURCE': 'resources', + 'SERVICE': 'services' + } + + constructor(private http:HttpService, @Inject(SdcConfigToken) sdcConfig:ISdcConfig) { + this.baseUrl = sdcConfig.api.root; + } + + public createGroupInstance(componentType:string, componentUniqueId:string, groupType:string) { + return this.http.post(this.baseUrl + '/v1/catalog/' + this.mapApiDirections[componentType.toUpperCase()] + '/' + componentUniqueId + '/groups/' + groupType, {}).map(resp => { + return resp.json(); + }); + }; + + public addGroupMember(topologyTemplateType:string, topologyTemplateId:string, group:GroupInstance, memberId:string) { + let members:Array<string> = Object.assign({}, group.members); + members.push(memberId); + return this.updateGroupMembers(topologyTemplateType, topologyTemplateId, group.uniqueId, members); + } + + public deleteGroupMember(topologyTemplateType:string, topologyTemplateId:string, group:GroupInstance, memberId:string) { + let _members:Array<string> = angular.copy(group.members); + _members =_.without(_members, memberId); + return this.updateGroupMembers(topologyTemplateType, topologyTemplateId, group.uniqueId, _members); + } + + public updateGroupMembers(topologyTemplateType:string, topologyTemplateId:string, groupId:string, members:Array<string>):Observable<Array<string>> { + return this.http.post(this.baseUrl + '/v1/catalog/' + this.mapApiDirections[topologyTemplateType.toUpperCase()] + '/' + topologyTemplateId + '/groups/' + groupId + '/members', members) + .map(response => response.json()); + } + + public updateMembers(topologyTemplateType:string, topologyTemplateId:string, groupId:string, members:Array<UiBaseObject>):Observable<Array<string>> { + let membersIds:Array<string> = members.map(member => member.uniqueId); + return this.updateGroupMembers(topologyTemplateType, topologyTemplateId, groupId, membersIds); + } + + public getSpecificGroup(topologyTemplateType:string, topologyTemplateId:string, groupId:string):Observable<GroupInstance> { + return this.http.get(this.baseUrl + '/v1/catalog/' + this.mapApiDirections[topologyTemplateType.toUpperCase()] + '/' + topologyTemplateId + '/groups/' + groupId) + .map(res => { + return new GroupInstance(res.json()); + }); + } + + public updateName(topologyTemplateType:string, topologyTemplateId:string, groupId:string, newName:string):Observable<GroupInstance> { + return this.http.put(this.baseUrl + '/v1/catalog/' + this.mapApiDirections[topologyTemplateType.toUpperCase()] + '/' + topologyTemplateId + '/groups/' + groupId, {name: newName}).map(resp => { + return resp.json(); + }); + }; + + public deleteGroup(topologyTemplateType:string, topologyTemplateId:string, groupId:string) { + return this.http.delete(this.baseUrl + '/v1/catalog/' + this.mapApiDirections[topologyTemplateType.toUpperCase()] + '/' + topologyTemplateId + '/groups/' + groupId).map(resp => { + return resp.json(); + }); + }; + + public updateZoneInstanceAssignments(topologyTemplateType:string, topologyTemplateId:string, policyId:string, members:Array<IZoneInstanceAssignment>):Observable<any> { + return this.updateMembers(topologyTemplateType, topologyTemplateId, policyId, members); + }; + + public deleteZoneInstance(topologyTemplateType:string, topologyTemplateId:string, policyId:string):Observable<any> { + return this.deleteGroup(topologyTemplateType, topologyTemplateId, policyId); + }; +}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/services/modal.service.ts b/catalog-ui/src/app/ng2/services/modal.service.ts index 4e86d6accf..a8f1b99ac2 100644 --- a/catalog-ui/src/app/ng2/services/modal.service.ts +++ b/catalog-ui/src/app/ng2/services/modal.service.ts @@ -24,6 +24,10 @@ export class ModalService { this.createCustomModal(modalModel).instance.open(); } + public openErrorModal = (closeButtonText?: string, errorMessage?: string):void => { + let errorModal = this.createErrorModal(closeButtonText, errorMessage); + errorModal.instance.open(); + }; /** * Shortcut method to open a basic modal with title, message, and an action button with callback, as well as close button. @@ -77,7 +81,7 @@ export class ModalService { return wizardInstance; } - + public closeCurrentModal = () => { if (!this.currentModal) return; this.currentModal.instance.close(); @@ -102,3 +106,5 @@ export class ModalService { } + + diff --git a/catalog-ui/src/app/ng2/services/policies.service.ts b/catalog-ui/src/app/ng2/services/policies.service.ts index 2b564b8915..3675a7b9ab 100644 --- a/catalog-ui/src/app/ng2/services/policies.service.ts +++ b/catalog-ui/src/app/ng2/services/policies.service.ts @@ -18,32 +18,107 @@ * ============LICENSE_END========================================================= */ -import { Injectable, Inject } from "@angular/core"; -import { Headers } from "@angular/http"; -import { Observable } from "rxjs/Observable"; -import { HttpService } from "./http.service"; -import { Cookie2Service } from "./cookie.service"; +import {Injectable, Inject} from "@angular/core"; +import {Observable} from "rxjs/Observable"; +import {HttpService} from "./http.service"; import {SdcConfigToken, ISdcConfig} from "../config/sdc-config.config"; +import {PolicyInstance, PolicyTargetsRequest} from '../../models/graph/zones/policy-instance'; +import {IZoneInstanceAssignment} from "../../models/graph/zones/zone-instance"; +import {IZoneService} from "../../models/graph/zones/zone"; +import {TargetUiObject} from "../../models/ui-models/ui-target-object"; +import {TargetOrMemberType} from "../../utils/constants"; @Injectable() -export class PoliciesService { +export class PoliciesService implements IZoneService { protected baseUrl; private mapApiDirections = { - 'RESOURCE':'resources', - 'SERVICE':'services' + 'RESOURCE': 'resources', + 'SERVICE': 'services' } - constructor(private http: HttpService, @Inject(SdcConfigToken) sdcConfig:ISdcConfig) { - this.baseUrl = sdcConfig.api.root ; + constructor(private http:HttpService, @Inject(SdcConfigToken) sdcConfig:ISdcConfig) { + this.baseUrl = sdcConfig.api.root; } - public createPolicyInstance(entityType:string, id:string, policyType:string) { - return this.http.post(this.baseUrl + '/v1/catalog/' + this.mapApiDirections[entityType] + '/' + id +'/policies/' + policyType, {}).map(resp => { - return resp.json(); + public createPolicyInstance(topologyTemplateType:string, topologyTemplateId:string, policyType:string) { + return this.http.post(this.baseUrl + '/v1/catalog/' + this.mapApiDirections[topologyTemplateType.toUpperCase()] + '/' + topologyTemplateId + '/policies/' + policyType, {}).map(resp => { + return resp.json(); }); } + public addPolicyTarget(topologyTemplateType:string, topologyTemplateId:string, policy:PolicyInstance, targetId:string, targetType:TargetOrMemberType) { + let _targets:Array<string>; + let _members:Array<string>; + + if (targetType === TargetOrMemberType.COMPONENT_INSTANCES) { + _targets = angular.copy(policy.targets.COMPONENT_INSTANCES); + _targets.push(targetId); + } else if (targetType === TargetOrMemberType.GROUPS) { + _members = angular.copy(policy.targets.GROUPS); + _members.push(targetId); + } + let policyTargetRequest:PolicyTargetsRequest = new PolicyTargetsRequest(_members, _targets); + return this.updatePolicyTargets(topologyTemplateType, topologyTemplateId, policy.uniqueId, policyTargetRequest); + } + + public deletePolicyTarget(topologyTemplateType:string, topologyTemplateId:string, policy:PolicyInstance, targetId:string, targetType:TargetOrMemberType): Observable<PolicyInstance> { + let _targets:Array<string> = angular.copy(policy.targets.COMPONENT_INSTANCES); + let _members:Array<string> = angular.copy(policy.targets.GROUPS); + if (targetType === TargetOrMemberType.COMPONENT_INSTANCES) { + _targets = _.without(_targets, targetId); + } else if (targetType === TargetOrMemberType.GROUPS) { + _members = _.without(_members, targetId); + } + let policyTargetRequest:PolicyTargetsRequest = new PolicyTargetsRequest(_members, _targets); + return this.updatePolicyTargets(topologyTemplateType, topologyTemplateId, policy.uniqueId, policyTargetRequest); + } + + public updatePolicyTargets(topologyTemplateType:string, topologyTemplateId:string, policyId:string, targets:PolicyTargetsRequest): Observable<PolicyInstance> { + return this.http.post(this.baseUrl + '/v1/catalog/' + this.mapApiDirections[topologyTemplateType.toUpperCase()] + '/' + topologyTemplateId + '/policies/' + policyId + '/targets', targets.requestItems) + .map(response => new PolicyInstance(response.json())); + } + + public updateTargets(topologyTemplateType:string, topologyTemplateId:string, policyId:string, targets:Array<TargetUiObject>):Observable<PolicyInstance> { + let instances:Array<string> = _.filter(targets, (target:TargetUiObject)=> { + return target.type === TargetOrMemberType.COMPONENT_INSTANCES; + }).map(target => target.uniqueId); + + let groups:Array<string> = _.filter(targets, (target:TargetUiObject)=> { + return target.type === TargetOrMemberType.GROUPS; + }).map(target => target.uniqueId); + + let policyTargetRequest:PolicyTargetsRequest = new PolicyTargetsRequest(groups, instances); + return this.updatePolicyTargets(topologyTemplateType, topologyTemplateId, policyId, policyTargetRequest); + } + + public getSpecificPolicy(topologyTemplateType:string, topologyTemplateId:string, policyId:string):Observable<PolicyInstance> { + return this.http.get(this.baseUrl + '/v1/catalog/' + this.mapApiDirections[topologyTemplateType.toUpperCase()] + '/' + topologyTemplateId + '/policies/' + policyId) + .map(res => { + return new PolicyInstance(res.json()); + }); + } + + public updateName(topologyTemplateType:string, topologyTemplateId:string, policyId:string, newName:string):Observable<any> { + return this.http.put(this.baseUrl + '/v1/catalog/' + this.mapApiDirections[topologyTemplateType.toUpperCase()] + '/' + topologyTemplateId + '/policies/' + policyId, {name: newName}).map(res => { + return res.json(); + }); + }; + + public deletePolicy(topologyTemplateType:string, topologyTemplateId:string, policyId:string) { + return this.http.delete(this.baseUrl + '/v1/catalog/' + this.mapApiDirections[topologyTemplateType.toUpperCase()] + '/' + topologyTemplateId + '/policies/' + policyId).map(resp => { + return resp.json(); + }); + }; + + public updateZoneInstanceAssignments(topologyTemplateType:string, topologyTemplateId:string, policyId:string, targets:Array<IZoneInstanceAssignment>):Observable<PolicyInstance>{ + return this.updateTargets(topologyTemplateType, topologyTemplateId, policyId, targets); + }; + + public deleteZoneInstance(topologyTemplateType:string, topologyTemplateId:string, policyId:string):Observable<any> { + return this.deletePolicy(topologyTemplateType, topologyTemplateId, policyId); + }; + } diff --git a/catalog-ui/src/app/ng2/services/responses/automated-upgrade-response.ts b/catalog-ui/src/app/ng2/services/responses/automated-upgrade-response.ts new file mode 100644 index 0000000000..feac8685a7 --- /dev/null +++ b/catalog-ui/src/app/ng2/services/responses/automated-upgrade-response.ts @@ -0,0 +1,16 @@ +/** + * Created by ob0695 on 4/29/2018. + */ + +export class AutomatedUpgradeStatusResponse { + name:string; + status:string; + uniqueId:string; + version:string; +} + +export class AutomatedUpgradeGenericResponse { + error:string; + status:string; + componentToUpgradeStatus:Array<AutomatedUpgradeStatusResponse>; +}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/services/responses/component-generic-response.ts b/catalog-ui/src/app/ng2/services/responses/component-generic-response.ts index 5036a10a9d..a77133e09f 100644 --- a/catalog-ui/src/app/ng2/services/responses/component-generic-response.ts +++ b/catalog-ui/src/app/ng2/services/responses/component-generic-response.ts @@ -28,6 +28,7 @@ import {CommonUtils} from "app/utils"; import {Serializable} from "../utils/serializable"; import {PropertyBEModel} from "../../../models/properties-inputs/property-be-model"; import { PolicyInstance } from "app/models/graph/zones/policy-instance"; +import { GroupInstance } from "../../../models/graph/zones/group-instance"; export class ComponentGenericResponse implements Serializable<ComponentGenericResponse> { @@ -45,7 +46,8 @@ export class ComponentGenericResponse implements Serializable<ComponentGenericR public properties:Array<PropertyModel>; public attributes:Array<AttributeModel>; public policies:Array<PolicyInstance>; - public groups:Array<Module>; + public groupInstances: Array<GroupInstance>; + public modules:Array<Module>; public interfaces:any; public interfaceOperations:Array<OperationModel>; public additionalInformation:any; @@ -96,7 +98,8 @@ export class ComponentGenericResponse implements Serializable<ComponentGenericR this.metadata = new ComponentMetadata().deserialize(response.metadata); } if(response.groups) { - this.groups = CommonUtils.initModules(response.groups); + this.modules = CommonUtils.initModules(response.groups); + this.groupInstances = CommonUtils.initGroups(response.groups) } if(response.policies) { this.policies = CommonUtils.initPolicies(response.policies); diff --git a/catalog-ui/src/app/ng2/services/responses/dependencies-server-response.ts b/catalog-ui/src/app/ng2/services/responses/dependencies-server-response.ts new file mode 100644 index 0000000000..be8aaea75d --- /dev/null +++ b/catalog-ui/src/app/ng2/services/responses/dependencies-server-response.ts @@ -0,0 +1,14 @@ +import { state } from '@angular/core'; +/** + * Created by ob0695 on 4/23/2018. + */ +export interface IDependenciesServerResponse { + icon: string; + name: string; + type: string; + uniqueId: string; + version: string; + state: string; + dependencies: Array<IDependenciesServerResponse>; + instanceNames: Array<string>; +}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/services/window.service.ts b/catalog-ui/src/app/ng2/services/window.service.ts new file mode 100644 index 0000000000..0a11166f7b --- /dev/null +++ b/catalog-ui/src/app/ng2/services/window.service.ts @@ -0,0 +1,8 @@ +import {Injectable} from "@angular/core"; + +@Injectable() +export class WindowRef { + get nativeWindow(): any { + return window; + } +} diff --git a/catalog-ui/src/app/ng2/shared/multiline-ellipsis/multiline-ellipsis.component.html b/catalog-ui/src/app/ng2/shared/multiline-ellipsis/multiline-ellipsis.component.html new file mode 100644 index 0000000000..c9f59f071c --- /dev/null +++ b/catalog-ui/src/app/ng2/shared/multiline-ellipsis/multiline-ellipsis.component.html @@ -0,0 +1,6 @@ +<div class="multiline-ellipsis-container" [ngClass]="className" [ngStyle]="stylesContainer" #multilineEllipsisContainer> + <div class="multiline-ellipsis-content" [ngStyle]="stylesContent" #multilineEllipsisContent> + <ng-content></ng-content> + <div class="multiline-ellipsis-dots" [ngStyle]="stylesDots"></div> + </div> +</div>
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/shared/multiline-ellipsis/multiline-ellipsis.component.less b/catalog-ui/src/app/ng2/shared/multiline-ellipsis/multiline-ellipsis.component.less new file mode 100644 index 0000000000..c616d37bd8 --- /dev/null +++ b/catalog-ui/src/app/ng2/shared/multiline-ellipsis/multiline-ellipsis.component.less @@ -0,0 +1,25 @@ +.multiline-ellipsis-container { + position: relative; + display: block; + overflow: hidden; + white-space: normal; + //max-height: @num_lines * @line_height; + + .multiline-ellipsis-content { + word-break: break-all; + position: relative; + //max-height: (@num_lines + 1) * @line_height; + + .multiline-ellipsis-dots { + display: block; + position: absolute; + right: 0; + //top: calc(#{@num_lines * 2} - 100%); + + &::before { + display: block; + content: '...'; + } + } + } +} diff --git a/catalog-ui/src/app/ng2/shared/multiline-ellipsis/multiline-ellipsis.component.ts b/catalog-ui/src/app/ng2/shared/multiline-ellipsis/multiline-ellipsis.component.ts new file mode 100644 index 0000000000..68cfedb32b --- /dev/null +++ b/catalog-ui/src/app/ng2/shared/multiline-ellipsis/multiline-ellipsis.component.ts @@ -0,0 +1,58 @@ +import {Component, OnChanges, AfterViewChecked, ViewChild, ElementRef, Input, Output, SimpleChanges, EventEmitter} from "@angular/core"; +import {WindowRef} from "../../services/window.service"; + +@Component({ + selector: 'multiline-ellipsis', + templateUrl: 'multiline-ellipsis.component.html', + styleUrls: ['multiline-ellipsis.component.less'] +}) +export class MultilineEllipsisComponent implements OnChanges, AfterViewChecked { + + @Input() public lines: number; + @Input() public lineHeight: string; + @Input() public className: string; + @Output() public hasEllipsisChanged: EventEmitter<boolean>; + + @ViewChild('multilineEllipsisContainer') public elmContainer: ElementRef; + @ViewChild('multilineEllipsisContent') public elmContent: ElementRef; + + public stylesContainer: {[key: string]: string}; + public stylesContent: {[key: string]: string}; + public stylesDots: {[key: string]: string}; + + private hasEllipsis: boolean; + + public constructor(private windowRef: WindowRef) { + this.hasEllipsisChanged = new EventEmitter<boolean>(); + } + + public ngOnChanges(changes: SimpleChanges) { + this.prepareStyles() + } + + public ngAfterViewChecked() { + const hasEllipsis = (this.elmContainer.nativeElement.offsetHeight < this.elmContent.nativeElement.offsetHeight); + if (hasEllipsis !== this.hasEllipsis) { + this.hasEllipsis = hasEllipsis; + this.hasEllipsisChanged.emit(this.hasEllipsis); + } + } + + private prepareStyles() { + const lineHeight = this.lineHeight || this.getLineHeight(); + this.stylesContainer = { + 'max-height': `calc(${this.lines} * ${lineHeight})` + }; + this.stylesContent = { + 'max-height': `calc(${this.lines + 1} * ${lineHeight})` + }; + this.stylesDots = { + 'top': `calc(${2 * this.lines} * ${lineHeight} - 100%)` + }; + } + + private getLineHeight() { + return this.windowRef.nativeWindow.getComputedStyle(this.elmContainer.nativeElement)['line-height']; + } + +} diff --git a/catalog-ui/src/app/ng2/shared/multiline-ellipsis/multiline-ellipsis.module.ts b/catalog-ui/src/app/ng2/shared/multiline-ellipsis/multiline-ellipsis.module.ts new file mode 100644 index 0000000000..24ed7b38af --- /dev/null +++ b/catalog-ui/src/app/ng2/shared/multiline-ellipsis/multiline-ellipsis.module.ts @@ -0,0 +1,11 @@ +import {NgModule} from '@angular/core'; +import {CommonModule} from '@angular/common'; +import {MultilineEllipsisComponent} from './multiline-ellipsis.component'; + +@NgModule({ + declarations: [MultilineEllipsisComponent], + imports: [CommonModule], + exports: [MultilineEllipsisComponent], + entryComponents: [MultilineEllipsisComponent] +}) +export class MultilineEllipsisModule {} diff --git a/catalog-ui/src/app/ng2/utils/ng1-upgraded-provider.ts b/catalog-ui/src/app/ng2/utils/ng1-upgraded-provider.ts index c005efcbe8..fcb21c0c83 100644 --- a/catalog-ui/src/app/ng2/utils/ng1-upgraded-provider.ts +++ b/catalog-ui/src/app/ng2/utils/ng1-upgraded-provider.ts @@ -21,12 +21,14 @@ /** * Created by rc2122 on 4/6/2017. */ -import {DataTypesService} from "../../services/data-types-service"; +import { DataTypesService } from "../../services/data-types-service"; import ICacheObject = angular.ICacheObject; -import {SharingService} from "../../services/sharing-service"; -import {CookieService} from "../../services/cookie-service"; -import {CacheService} from "../../services/cache-service"; -import {EventListenerService} from "app/services/event-listener-service"; +import { SharingService } from "../../services/sharing-service"; +import { CookieService } from "../../services/cookie-service"; +import { CacheService } from "../../services/cache-service"; +import {ComponentFactory} from "../../utils/component-factory" +import { EventListenerService } from "app/services/event-listener-service"; +import { ModalsHandler } from "app/utils"; import IScope = angular.IScope; /** Services we need to upgrade from angular1 to angular2 - in the future we need to rewrite them all to angular2 **/ @@ -39,6 +41,10 @@ export function sharingServiceFactory(cacheObj: ICacheObject) { return cacheObj.get('Sdc.Services.SharingService'); } +export function componentServiceFactory(cacheObj: ICacheObject) { + return cacheObj.get('Sdc.Services.ComponentFactory'); +} + export function cookieServiceFactory(cacheObj: ICacheObject) { return cacheObj.get('Sdc.Services.CookieService'); } @@ -47,14 +53,14 @@ export function stateServiceFactory(cacheObj: ICacheObject) { return cacheObj.get('$state'); } -export function scopeServiceFactory(cacheObj: ICacheObject) { - return cacheObj.get('$scope'); -} - export function stateParamsServiceFactory(cacheObj: ICacheObject) { return cacheObj.get('$stateParams'); } +export function scopeServiceFactory(cacheObj: ICacheObject) { + return cacheObj.get('$scope'); +} + export function cacheServiceFactory(cacheObj: ICacheObject) { return cacheObj.get('Sdc.Services.CacheService'); } @@ -67,6 +73,18 @@ export function notificationServiceFactory(cacheObj: ICacheObject) { return cacheObj.get('Notification'); } + +export const ComponentFactoryProvider = { + provide: ComponentFactory, + useFactory: componentServiceFactory, + deps: ['$injector'] +}; + + +export function ModalsHandlerFactory(cacheObj: ICacheObject) { + return cacheObj.get('ModalsHandler'); +} + export const DataTypesServiceProvider = { provide: DataTypesService, useFactory: dataTypesServiceFactory, @@ -93,7 +111,7 @@ export const StateServiceFactory = { deps: ['$injector'] }; -export const ScopeServiceFactory= { +export const ScopeServiceFactory = { provide: '$scope', useFactory: scopeServiceFactory, deps: ['$injector'] @@ -104,7 +122,6 @@ export const StateParamsServiceFactory = { useFactory: stateParamsServiceFactory, deps: ['$injector'] }; - export const CacheServiceProvider = { provide: CacheService, useFactory: cacheServiceFactory, @@ -122,3 +139,9 @@ export const NotificationServiceProvider = { useFactory: notificationServiceFactory, deps: ['$injector'] }; + +export const ModalsHandlerProvider = { + provide: ModalsHandler, + useFactory: ModalsHandlerFactory, + deps: ['$injector'] +} diff --git a/catalog-ui/src/app/services/components/component-service.ts b/catalog-ui/src/app/services/components/component-service.ts index 0b68c8be30..25203e7732 100644 --- a/catalog-ui/src/app/services/components/component-service.ts +++ b/catalog-ui/src/app/services/components/component-service.ts @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -107,7 +107,7 @@ export class ComponentService implements IComponentService { }; public getComponent = (id:string):ng.IPromise<Component> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Component>(); this.restangular.one(id).get().then((response:Component) => { let component:Component = this.createComponentObject(response); //console.log("Component Loaded successfully : ", component); @@ -141,7 +141,7 @@ export class ComponentService implements IComponentService { }; private updateService = (component:Component):ng.IPromise<Component> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Component>(); this.restangular.one(component.uniqueId).one("metadata").customPUT(JSON.stringify(component)).then((response:Component) => { let component:Component = this.createComponentObject(response); deferred.resolve(component); @@ -152,7 +152,7 @@ export class ComponentService implements IComponentService { }; private updateResource = (component:Component):ng.IPromise<Component> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Component>(); this.restangular.one(component.uniqueId).customPUT(JSON.stringify(component)).then((response:Component) => { let component:Component = this.createComponentObject(response); deferred.resolve(component); @@ -163,7 +163,7 @@ export class ComponentService implements IComponentService { }; private updateResourceMetadata = (component:Component):ng.IPromise<Component> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Component>(); this.restangular.one(component.uniqueId).one('metadata').customPUT(JSON.stringify(component)).then((response:Component) => { let component:Component = this.createComponentObject(response); deferred.resolve(component); @@ -179,7 +179,7 @@ export class ComponentService implements IComponentService { * @returns {IPromise<T>} */ private updateResourceWithPayload = (resource:Resource):ng.IPromise<Component> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Component>(); resource.payloadData = resource.importedFile.base64; resource.payloadName = resource.importedFile.filename; @@ -196,7 +196,7 @@ export class ComponentService implements IComponentService { }; public createComponent = (component:Component):ng.IPromise<Component> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Component>(); let headerObj = this.getHeaderMd5(component); this.restangular.customPOST(JSON.stringify(component), '', {}, headerObj).then((response:Component) => { let component:Component = this.createComponentObject(response); @@ -208,7 +208,7 @@ export class ComponentService implements IComponentService { }; public validateName = (newName:string, subtype?:string):ng.IPromise<IValidate> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<IValidate>(); this.restangular.one("validate-name").one(newName).get({'subtype': subtype}).then((response:any) => { deferred.resolve(response.plain()); }, (err)=> { @@ -218,7 +218,7 @@ export class ComponentService implements IComponentService { }; public changeLifecycleState = (component:Component, state:string, userRemarks:any):ng.IPromise<ComponentMetadata> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<ComponentMetadata>(); this.restangular.one(component.uniqueId).one(state).customPOST(userRemarks).then((response:ComponentMetadata) => { this.sharingService.addUuidValue(response.uniqueId, response.uuid); let component:ComponentMetadata = new ComponentMetadata().deserialize(response); @@ -226,13 +226,12 @@ export class ComponentService implements IComponentService { }, (err)=> { deferred.reject(err); }); - return deferred.promise; }; // ------------------------------------------------ Artifacts API --------------------------------------------------// public addOrUpdateArtifact = (componentId:string, artifact:ArtifactModel):ng.IPromise<ArtifactModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<ArtifactModel>(); let headerObj = {}; if (artifact.payloadData) { headerObj = this.getHeaderMd5(artifact); @@ -246,7 +245,7 @@ export class ComponentService implements IComponentService { }; public downloadArtifact = (componentId:string, artifactId:string):ng.IPromise<IFileDownload> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<IFileDownload>(); this.restangular.one(componentId).one("artifacts").one(artifactId).get().then((response:any) => { deferred.resolve(response.plain()); }, (err)=> { @@ -256,7 +255,7 @@ export class ComponentService implements IComponentService { }; public deleteArtifact = (componentId:string, artifactId:string, artifactLabel:string):ng.IPromise<ArtifactModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<ArtifactModel>(); this.restangular.one(componentId).one("artifacts").one(artifactId).remove({'operation': artifactLabel}).then((response:ArtifactModel) => { deferred.resolve(response); }, (err)=> { @@ -266,7 +265,7 @@ export class ComponentService implements IComponentService { }; public getArtifactByGroupType = (componentId:string, artifactGroupType:string):ng.IPromise<ArtifactGroupModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<ArtifactGroupModel>(); this.restangular.one(componentId).one("artifactsByType").one(artifactGroupType).get().then((response:any) => { var artifacts:ArtifactGroupModel = new ArtifactGroupModel(response.plain()); deferred.resolve(artifacts); @@ -277,7 +276,7 @@ export class ComponentService implements IComponentService { }; public getComponentInstanceArtifactsByGroupType = (componentId:string, componentInstanceId:string, artifactGroupType:string):ng.IPromise<ArtifactGroupModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<ArtifactGroupModel>(); this.restangular.one(componentId).one("resourceInstances").one(componentInstanceId).one("artifactsByType").one(artifactGroupType).get().then((response:any) => { var artifacts:ArtifactGroupModel = new ArtifactGroupModel(response.plain()); deferred.resolve(artifacts); @@ -290,7 +289,7 @@ export class ComponentService implements IComponentService { // ------------------------------------------------ Properties API --------------------------------------------------// public addProperty = (componentId:string, property:PropertyModel):ng.IPromise<PropertyModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<PropertyModel>(); this.restangular.one(componentId).one("properties").customPOST(property.convertToServerObject()).then((response:any) => { let property:PropertyModel = new PropertyModel(response[Object.keys(response)[0]]); deferred.resolve(property); @@ -301,7 +300,7 @@ export class ComponentService implements IComponentService { }; public updateProperty = (componentId:string, property:PropertyModel):ng.IPromise<PropertyModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<PropertyModel>(); this.restangular.one(componentId).one("properties").one(property.uniqueId).customPUT(property.convertToServerObject()).then((response:any) => { let property:PropertyModel = new PropertyModel(response[Object.keys(response)[0]]); deferred.resolve(property); @@ -312,7 +311,7 @@ export class ComponentService implements IComponentService { }; public deleteProperty = (componentId:string, propertyId:string):ng.IPromise<PropertyModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<PropertyModel>(); this.restangular.one(componentId).one("properties").one(propertyId).remove().then((response:any) => { deferred.resolve(response); }, (err)=> { @@ -323,7 +322,7 @@ export class ComponentService implements IComponentService { // ------------------------------------------------ Attributes API --------------------------------------------------// public addAttribute = (componentId:string, attribute:AttributeModel):ng.IPromise<AttributeModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<AttributeModel>(); this.restangular.one(componentId).one("attributes").customPOST(attribute.convertToServerObject()).then((response:any) => { let attribute:AttributeModel = new AttributeModel(response); deferred.resolve(attribute); @@ -334,7 +333,7 @@ export class ComponentService implements IComponentService { }; public updateAttribute = (componentId:string, attribute:AttributeModel):ng.IPromise<AttributeModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<AttributeModel>(); this.restangular.one(componentId).one("attributes").one(attribute.uniqueId).customPUT(attribute.convertToServerObject()).then((response:any) => { let attribute:AttributeModel = new AttributeModel(response); deferred.resolve(attribute); @@ -345,7 +344,7 @@ export class ComponentService implements IComponentService { }; public deleteAttribute = (componentId:string, attributeId:string):ng.IPromise<AttributeModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<AttributeModel>(); this.restangular.one(componentId).one("attributes").one(attributeId).remove().then((response:any) => { deferred.resolve(response); }, (err)=> { @@ -357,7 +356,7 @@ export class ComponentService implements IComponentService { // ------------------------------------------------ Component Instances API --------------------------------------------------// public createComponentInstance = (componentId:string, componentInstance:ComponentInstance):ng.IPromise<ComponentInstance> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<ComponentInstance>(); this.restangular.one(componentId).one("resourceInstance").customPOST(JSON.stringify(componentInstance)).then((response:any) => { let componentInstance:ComponentInstance = ComponentInstanceFactory.createComponentInstance(response); console.log("Component Instance created", componentInstance); @@ -370,7 +369,7 @@ export class ComponentService implements IComponentService { }; public updateComponentInstance = (componentId:string, componentInstance:ComponentInstance):ng.IPromise<ComponentInstance> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<ComponentInstance>(); this.restangular.one(componentId).one("resourceInstance").one(componentInstance.uniqueId).customPOST(JSON.stringify(componentInstance)).then((response:any) => { let componentInstance:ComponentInstance = ComponentInstanceFactory.createComponentInstance(response); console.log("Component Instance was updated", componentInstance); @@ -383,7 +382,7 @@ export class ComponentService implements IComponentService { }; public updateMultipleComponentInstances = (componentId:string, instances:Array<ComponentInstance>):ng.IPromise<Array<ComponentInstance>> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Array<ComponentInstance>>(); this.restangular.one(componentId).one("resourceInstance/multipleComponentInstance").customPOST(JSON.stringify(instances)).then((response:any) => { console.log("Multiple Component Instances was updated", response); let updateInstances:Array<ComponentInstance> = new Array<ComponentInstance>(); @@ -400,7 +399,7 @@ export class ComponentService implements IComponentService { }; public deleteComponentInstance = (componentId:string, componentInstanceId:string):ng.IPromise<ComponentInstance> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<ComponentInstance>(); this.restangular.one(componentId).one("resourceInstance").one(componentInstanceId).remove().then(() => { console.log("Component Instance was deleted"); deferred.resolve(); @@ -412,7 +411,7 @@ export class ComponentService implements IComponentService { }; public checkResourceInstanceVersionChange = (componentId:string, componentInstanceId:string, componentUid:string):ng.IPromise<ComponentInstance> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<ComponentInstance>(); this.restangular.one(componentId).one("resourceInstance").one(componentInstanceId).one(componentUid).one("checkForwardingPathOnVersionChange").get().then((response:any) => { deferred.resolve(response); }, err => { @@ -422,7 +421,7 @@ export class ComponentService implements IComponentService { }; public changeResourceInstanceVersion = (componentId:string, componentInstanceId:string, componentUid:string):ng.IPromise<ComponentInstance> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<ComponentInstance>(); this.restangular.one(componentId).one("resourceInstance").one(componentInstanceId).one("changeVersion").customPOST({'componentUid': componentUid}).then((response:any) => { let componentInstance:ComponentInstance = ComponentInstanceFactory.createComponentInstance(response); deferred.resolve(componentInstance); @@ -433,7 +432,7 @@ export class ComponentService implements IComponentService { }; public downloadInstanceArtifact = (componentId:string, instanceId:string, artifactId:string):ng.IPromise<IFileDownload> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<IFileDownload>(); this.restangular.one(componentId).one("resourceInstances").one(instanceId).one("artifacts").one(artifactId).get().then((response:any) => { deferred.resolve(response.plain()); }, (err)=> { @@ -443,7 +442,7 @@ export class ComponentService implements IComponentService { }; public updateInstanceArtifact = (componentId:string, instanceId:string, artifact:ArtifactModel):ng.IPromise<ArtifactModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<ArtifactModel>(); let headerObj = {}; if (artifact.payloadData) { headerObj = this.getHeaderMd5(artifact); @@ -458,7 +457,7 @@ export class ComponentService implements IComponentService { }; public addInstanceArtifact = (componentId:string, instanceId:string, artifact:ArtifactModel):ng.IPromise<ArtifactModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<ArtifactModel>(); let headerObj = {}; if (artifact.payloadData) { headerObj = this.getHeaderMd5(artifact); @@ -473,7 +472,7 @@ export class ComponentService implements IComponentService { }; public deleteInstanceArtifact = (componentId:string, instanceId:string, artifactId:string, artifactLabel:string):ng.IPromise<ArtifactModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<ArtifactModel>(); this.restangular.one(componentId).one("resourceInstance").one(instanceId).one("artifacts").one(artifactId).remove({'operation': artifactLabel}).then((response:ArtifactModel) => { deferred.resolve(response); }, (err)=> { @@ -483,7 +482,7 @@ export class ComponentService implements IComponentService { }; public uploadInstanceEnvFile = (componentId:string, instanceId:string, artifact:ArtifactModel):ng.IPromise<ArtifactModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<ArtifactModel>(); let headerObj = {}; if (artifact.payloadData) { headerObj = this.getHeaderMd5(artifact); @@ -514,7 +513,7 @@ export class ComponentService implements IComponentService { }; public updateInstanceAttribute = (componentId:string, attribute:AttributeModel):ng.IPromise<AttributeModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<AttributeModel>(); let instanceId = attribute.resourceInstanceUniqueId; this.restangular.one(componentId).one("resourceInstance").one(instanceId).one("attribute").customPOST(JSON.stringify(attribute)).then((response:any) => { let newAttribute = new AttributeModel(response); @@ -528,7 +527,7 @@ export class ComponentService implements IComponentService { }; public createRelation = (componentId:string, link:RelationshipModel):ng.IPromise<RelationshipModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<RelationshipModel>(); const linkPayload:RelationshipModel = new RelationshipModel(link); linkPayload.relationships.forEach((rel) => { delete rel.capability; @@ -546,7 +545,7 @@ export class ComponentService implements IComponentService { }; public deleteRelation = (componentId:string, link:RelationshipModel):ng.IPromise<RelationshipModel> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<RelationshipModel>(); const linkPayload:RelationshipModel = new RelationshipModel(link); linkPayload.relationships.forEach((rel) => { delete rel.capability; @@ -589,7 +588,7 @@ export class ComponentService implements IComponentService { }; public getModuleForDisplay = (componentId:string, moduleId:string):ng.IPromise<DisplayModule> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<DisplayModule>(); this.restangular.one(componentId).one("groups").one(moduleId).get().then((response:any) => { console.log("module loaded successfully: ", response); let module:DisplayModule = new DisplayModule(response); @@ -601,8 +600,8 @@ export class ComponentService implements IComponentService { return deferred.promise; }; - public getComponentInstanceModule = (componentId:string, componentInstanceId:string, moduleId:string):ng.IPromise<Module> => { - let deferred = this.$q.defer(); + public getComponentInstanceModule = (componentId:string, componentInstanceId:string, moduleId:string):ng.IPromise<DisplayModule> => { + let deferred = this.$q.defer<DisplayModule>(); this.restangular.one(componentId).one("resourceInstance").one(componentInstanceId).one("groupInstance").one(moduleId).get().then((response:any) => { console.log("module loaded successfully: ", response); let module:DisplayModule = new DisplayModule(response); @@ -615,7 +614,7 @@ export class ComponentService implements IComponentService { }; public getComponentInstancesFilteredByInputsAndProperties = (componentId:string, searchText?:string):ng.IPromise<Array<ComponentInstance>> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Array<ComponentInstance>>(); this.restangular.one(componentId).one("componentInstances").get({'searchText': searchText}).then((response:any) => { console.log("component instances return successfully: ", response); let componentInstances:Array<ComponentInstance> = CommonUtils.initComponentInstances(response); @@ -630,7 +629,7 @@ export class ComponentService implements IComponentService { public getComponentInstanceInputs = (componentId:string, instanceId:string, originComponentUid):ng.IPromise<Array<InputModel>> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Array<InputModel>>(); this.restangular.one(componentId).one("componentInstances").one(instanceId).one(originComponentUid).one("inputs").get().then((response:any) => { console.log("component instance input return successfully: ", response); let inputsArray:Array<InputModel> = new Array<InputModel>(); @@ -648,7 +647,7 @@ export class ComponentService implements IComponentService { public getComponentInputs = (componentId:string):ng.IPromise<Array<InputModel>> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Array<InputModel>>(); this.restangular.one(componentId).one("inputs").get().then((response:any) => { console.log("component inputs return successfully: ", response); let inputsArray:Array<InputModel> = new Array<InputModel>(); @@ -666,7 +665,7 @@ export class ComponentService implements IComponentService { public getComponentInstanceInputProperties = (componentId:string, instanceId:string, inputId:string):ng.IPromise<Array<PropertyModel>> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Array<PropertyModel>>(); this.restangular.one(componentId).one("componentInstances").one(instanceId).one(inputId).one("properties").get().then((response:any) => { console.log("component instance input properties return successfully: ", response); let propertiesArray:Array<PropertyModel> = new Array<PropertyModel>(); @@ -685,7 +684,7 @@ export class ComponentService implements IComponentService { public getComponentInstanceProperties = (componentId:string, instanceId:string):ng.IPromise<Array<PropertyModel>> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Array<PropertyModel>>(); this.restangular.one(componentId).one("componentInstances").one(instanceId).one("properties").get().then((response:any) => { console.log("component instance properties return successfully: ", response); let propertiesArray:Array<PropertyModel> = new Array<PropertyModel>(); @@ -703,7 +702,7 @@ export class ComponentService implements IComponentService { public updateGroupMetadata = (componentId:string, group:Module):ng.IPromise<Module> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Module>(); this.restangular.one(componentId).one("groups").one(group.uniqueId).one("metadata").customPUT(JSON.stringify(group)).then((response:Module) => { console.log("group metadata updated successfully: ", response); let updatedGroup:Module = new Module(response); @@ -718,7 +717,7 @@ export class ComponentService implements IComponentService { }; public getComponentInputInputsAndProperties = (serviceId:string, inputId:string):ng.IPromise<InputsAndProperties> => { - let defer = this.$q.defer<any>(); + let defer = this.$q.defer<InputsAndProperties>(); this.restangular.one(serviceId).one("inputs").one(inputId).get().then((response:InputsAndProperties) => { let inputsArray:Array<InputModel> = new Array<InputModel>(); @@ -740,7 +739,7 @@ export class ComponentService implements IComponentService { }; createInputsFromInstancesInputsProperties = (resourceId:string, instancePropertyMap:InstancesInputsPropertiesMap):ng.IPromise<Array<PropertyModel>> => { - let defer = this.$q.defer<any>(); + let defer = this.$q.defer<Array<PropertyModel>>(); this.restangular.one(resourceId).one("create/properties").customPOST(instancePropertyMap).then((response:any) => { let inputsArray:Array<PropertyModel> = new Array<PropertyModel>(); _.forEach(response, (inputObj:PropertyModel) => { @@ -755,7 +754,7 @@ export class ComponentService implements IComponentService { }; createInputsFromInstancesInputs = (serviceId:string, instancesMap:InstancesInputsPropertiesMap):ng.IPromise<Array<InputModel>> => { - let defer = this.$q.defer<any>(); + let defer = this.$q.defer<Array<InputModel>>(); this.restangular.one(serviceId).one("create/inputs").customPOST(instancesMap).then((response:any) => { let inputsArray:Array<InputModel> = new Array<InputModel>(); _.forEach(response, (inputObj:InputModel) => { @@ -770,7 +769,7 @@ export class ComponentService implements IComponentService { }; deleteComponentInput = (serviceId:string, inputId:string):ng.IPromise<InputModel> => { - let defer = this.$q.defer(); + let defer = this.$q.defer<InputModel>(); this.restangular.one(serviceId).one("delete").one(inputId).one("input").remove().then((response:any) => { let inputToDelete = new InputModel(response); defer.resolve(inputToDelete); diff --git a/catalog-ui/src/app/services/components/resource-service.ts b/catalog-ui/src/app/services/components/resource-service.ts index 15ef51e475..cb30107a69 100644 --- a/catalog-ui/src/app/services/components/resource-service.ts +++ b/catalog-ui/src/app/services/components/resource-service.ts @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/catalog-ui/src/app/services/components/service-service.ts b/catalog-ui/src/app/services/components/service-service.ts index cce0759613..f258c7be98 100644 --- a/catalog-ui/src/app/services/components/service-service.ts +++ b/catalog-ui/src/app/services/components/service-service.ts @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/catalog-ui/src/app/services/components/utils/composition-left-palette-service.ts b/catalog-ui/src/app/services/components/utils/composition-left-palette-service.ts index 2ed995c78c..99be788547 100644 --- a/catalog-ui/src/app/services/components/utils/composition-left-palette-service.ts +++ b/catalog-ui/src/app/services/components/utils/composition-left-palette-service.ts @@ -33,17 +33,6 @@ import {GroupMetadata, GroupTpes} from "app/models/group-metadata"; import {PolicyMetadata, PolicyTpes} from "app/models/policy-metadata"; import {Resource} from "app/models/components/resource"; -// export class LeftPaletteDataObject { -// displayLeftPanelComponents:Array<LeftPaletteComponent>; -// onFinishLoadingEvent:string; - -// constructor(onFinishEventListener:string) { - -// this.displayLeftPanelComponents = new Array<LeftPaletteComponent>(); -// this.onFinishLoadingEvent = onFinishEventListener; -// } -// } - export class LeftPaletteLoaderService { static '$inject' = [ @@ -65,56 +54,39 @@ export class LeftPaletteLoaderService { } - // private serviceLeftPaletteData:LeftPaletteDataObject; - // private resourceLeftPaletteData:LeftPaletteDataObject; - // private resourcePNFLeftPaletteData:LeftPaletteDataObject; - // private vlData:LeftPaletteDataObject; leftPanelComponents:Array<LeftPaletteComponent>; public loadLeftPanel = (component:Component):void => { - // this.serviceLeftPaletteData = new LeftPaletteDataObject(EVENTS.SERVICE_LEFT_PALETTE_UPDATE_EVENT); - // this.resourceLeftPaletteData = new LeftPaletteDataObject(EVENTS.RESOURCE_LEFT_PALETTE_UPDATE_EVENT); - // this.resourcePNFLeftPaletteData = new LeftPaletteDataObject(EVENTS.RESOURCE_PNF_LEFT_PALETTE_UPDATE_EVENT); this.leftPanelComponents = []; this.updateLeftPaletteForTopologyTemplate(component); } - // private getResourceLeftPaletteDataByResourceType = (resourceType:string):LeftPaletteDataObject => { - // if(resourceType == ResourceType.PNF) { - // return this.resourcePNFLeftPaletteData; - // } - // return this.resourceLeftPaletteData; - // } - private updateLeftPalette = (componentInternalType:string):void => { /* add components */ - this.restangular.one("resources").one('/latestversion/notabstract/metadata').get({'internalComponentType': componentInternalType}).then((leftPaletteComponentMetadata:Array<ComponentMetadata>) => { + this.restangular.one("resources").one('/latestversion/notabstract/metadata').get({'internalComponentType': componentInternalType}).then((leftPaletteComponentMetadata:Array<ComponentMetadata>) => { _.forEach(leftPaletteComponentMetadata, (componentMetadata:ComponentMetadata) => { this.leftPanelComponents.push(new LeftPaletteComponent(LeftPaletteMetadataTypes.Component, componentMetadata)); }); - this.EventListenerService.notifyObservers(EVENTS.LEFT_PALETTE_UPDATE_EVENT); - }); - - /* add groups */ - //TODO: In backend implement like this: - //this.restangular.one("groups").one('/latestversion/notabstract/metadata').get({'internalComponentType': componentInternalType}).then((leftPaletteComponentMetadata:Array<ComponentMetadata>) => { - this.restangular.one('/groupTypes').get().then((leftPaletteGroupTypes:GroupTpes) => { - _.forEach(leftPaletteGroupTypes.groupTypes, (groupMetadata: GroupMetadata) => { - this.leftPanelComponents.push(new LeftPaletteComponent(LeftPaletteMetadataTypes.Group, groupMetadata)); + + /* add groups */ + this.restangular.one('/groupTypes').get({'internalComponentType': componentInternalType}).then((leftPaletteGroupTypes:GroupTpes) => { + _.forEach(leftPaletteGroupTypes, (groupMetadata: GroupMetadata) => { + this.leftPanelComponents.push(new LeftPaletteComponent(LeftPaletteMetadataTypes.Group, groupMetadata)); + }); + this.EventListenerService.notifyObservers(EVENTS.LEFT_PALETTE_UPDATE_EVENT); }); - this.EventListenerService.notifyObservers(EVENTS.LEFT_PALETTE_UPDATE_EVENT); - }); - /* add policies */ - //TODO: In backend implement like this: - //this.restangular.one("policies").one('/latestversion/notabstract/metadata').get({'internalComponentType': componentInternalType}).then((leftPaletteComponentMetadata:Array<ComponentMetadata>) => { - this.restangular.one('/policyTypes').get().then((leftPalettePolicyTypes:PolicyTpes) => { - _.forEach(leftPalettePolicyTypes.policyTypes, (policyMetadata: PolicyMetadata) => { - this.leftPanelComponents.push(new LeftPaletteComponent(LeftPaletteMetadataTypes.Policy, policyMetadata)); + /* add policies */ + this.restangular.one('/policyTypes').get({'internalComponentType': componentInternalType}).then((leftPalettePolicyTypes:PolicyTpes) => { + _.forEach(leftPalettePolicyTypes, (policyMetadata: PolicyMetadata) => { + this.leftPanelComponents.push(new LeftPaletteComponent(LeftPaletteMetadataTypes.Policy, policyMetadata)); + }); + this.EventListenerService.notifyObservers(EVENTS.LEFT_PALETTE_UPDATE_EVENT); }); - this.EventListenerService.notifyObservers(EVENTS.LEFT_PALETTE_UPDATE_EVENT); }); + + } public getLeftPanelComponentsForDisplay = (component:Component):Array<LeftPaletteComponent> => { diff --git a/catalog-ui/src/app/services/entity-service.ts b/catalog-ui/src/app/services/entity-service.ts index b7ac8805ce..2e7b2e1eed 100644 --- a/catalog-ui/src/app/services/entity-service.ts +++ b/catalog-ui/src/app/services/entity-service.ts @@ -19,6 +19,7 @@ */ 'use strict'; +import * as _ from "lodash"; import { Service, IApi, IAppConfigurtaion, Resource, Component} from "../models"; import {SharingService} from "./sharing-service"; import {ComponentFactory} from "../utils/component-factory"; @@ -26,7 +27,7 @@ import {CacheService} from "./cache-service"; import {ResourceType} from "app/utils"; interface IEntityService { - getAllComponents():ng.IPromise<Array<Component>>; + getAllComponents(smallObjects?:boolean):ng.IPromise<Array<Component>>; } interface IComponentsArray { @@ -36,6 +37,7 @@ interface IComponentsArray { export class EntityService implements IEntityService { static '$inject' = ['$http', '$q', 'sdcConfig', 'Sdc.Services.SharingService', 'ComponentFactory', 'Sdc.Services.CacheService']; + private _smallObjectAttributes = ['uniqueId', 'name', 'componentType', 'resourceType', 'lastUpdateDate', 'lifecycleState', 'distributionStatus', 'icon', 'version']; private api:IApi; constructor(private $http:ng.IHttpService, @@ -66,7 +68,6 @@ export class EntityService implements IEntityService { this.sharingService.addUuidValue(component.uniqueId, component.uuid); }); - this.cacheService.set('breadcrumbsComponents', componentsList); defer.resolve(componentsList); },(responce) => { defer.reject(responce); @@ -74,7 +75,7 @@ export class EntityService implements IEntityService { return defer.promise; }; - getAllComponents = ():ng.IPromise<Array<Component>> => { + getAllComponents = (smallObjects?:boolean):ng.IPromise<Array<Component>> => { let defer = this.$q.defer<Array<Component>>(); this.$http.get(this.api.root + this.api.GET_element) .then((response:any) => { @@ -82,18 +83,19 @@ export class EntityService implements IEntityService { let componentsList:Array<Component> = []; componentResponse.services && componentResponse.services.forEach((serviceResponse:Service) => { + serviceResponse = (smallObjects) ? _.pick(serviceResponse, this._smallObjectAttributes) : serviceResponse; let component:Service = this.ComponentFactory.createService(serviceResponse); componentsList.push(component); this.sharingService.addUuidValue(component.uniqueId, component.uuid); }); componentResponse.resources && componentResponse.resources.forEach((resourceResponse:Resource) => { + resourceResponse = (smallObjects) ? _.pick(resourceResponse, this._smallObjectAttributes) : resourceResponse; let component:Resource = this.ComponentFactory.createResource(resourceResponse); componentsList.push(component); this.sharingService.addUuidValue(component.uniqueId, component.uuid); }); - this.cacheService.set('breadcrumbsComponents', componentsList); defer.resolve(componentsList); }); diff --git a/catalog-ui/src/app/services/http-error-interceptor.ts b/catalog-ui/src/app/services/http-error-interceptor.ts index b1aa16a2ac..cef8c30716 100644 --- a/catalog-ui/src/app/services/http-error-interceptor.ts +++ b/catalog-ui/src/app/services/http-error-interceptor.ts @@ -92,7 +92,7 @@ export class HttpErrorInterceptor { // Format the message %1 %2 text = text.format(variables); - // Need to inject the MessageService manually to prevent circular dependencies (because MessageService use $templateCache that use $http). + // Need to inject the MessageService manually to prevent circular componentsToUpgrade (because MessageService use $templateCache that use $http). data = { title: 'Error', message: text, @@ -101,7 +101,7 @@ export class HttpErrorInterceptor { severity: SEVERITY.ERROR }; } else { - // Need to inject the MessageService manually to prevent circular dependencies (because MessageService use $templateCache that use $http). + // Need to inject the MessageService manually to prevent circular componentsToUpgrade (because MessageService use $templateCache that use $http). data = { title: 'Error', message: rejection.status !== -1 ? rejection.statusText : "Error getting response from server", diff --git a/catalog-ui/src/app/utils/common-utils.ts b/catalog-ui/src/app/utils/common-utils.ts index 1868550225..d215183fa9 100644 --- a/catalog-ui/src/app/utils/common-utils.ts +++ b/catalog-ui/src/app/utils/common-utils.ts @@ -23,6 +23,7 @@ import {Module, AttributeModel, ResourceInstance, PropertyModel, InputFEModel, O import {ComponentInstanceFactory} from "./component-instance-factory"; import {InputBEModel, PropertyBEModel, RelationshipModel} from "app/models"; import { PolicyInstance } from "app/models/graph/zones/policy-instance"; +import { GroupInstance } from "../models/graph/zones/group-instance"; export class CommonUtils { @@ -126,6 +127,17 @@ export class CommonUtils { return policies; } + static initGroups = (groupsObj: Array<GroupInstance>):Array<GroupInstance> => { + let groups = new Array<GroupInstance>(); + + if(groupsObj) { + _.forEach(groupsObj, (group: GroupInstance):void => { + groups.push(new GroupInstance(group)); + }); + } + + return groups; + } static initInterfaceOperations(interfaces: any): Array<OperationModel> { diff --git a/catalog-ui/src/app/utils/component-factory.ts b/catalog-ui/src/app/utils/component-factory.ts index bf4f23b6eb..bdcfc2cc2d 100644 --- a/catalog-ui/src/app/utils/component-factory.ts +++ b/catalog-ui/src/app/utils/component-factory.ts @@ -73,9 +73,11 @@ export class ComponentFactory { public updateComponentFromCsar = (csarComponent:Resource, oldComponent:Resource):Component => { _.pull(oldComponent.tags, oldComponent.name); - oldComponent.name = csarComponent.name; - oldComponent.selectedCategory = csarComponent.selectedCategory; - oldComponent.categories = csarComponent.categories; + if (!oldComponent.isAlreadyCertified()) { + oldComponent.name = csarComponent.name; + oldComponent.categories = csarComponent.categories; + oldComponent.selectedCategory = csarComponent.selectedCategory; + } oldComponent.vendorName = csarComponent.vendorName; oldComponent.vendorRelease = csarComponent.vendorRelease; oldComponent.csarUUID = csarComponent.csarUUID; @@ -177,7 +179,7 @@ export class ComponentFactory { }; public getComponentWithMetadataFromServer = (componentType:string, componentId:string):ng.IPromise<Component> => { - let deferred = this.$q.defer(); + let deferred = this.$q.defer<Component>(); let component = this.createEmptyComponent(componentType); component.setUniqueId(componentId); this.ComponentServiceNg2.getComponentMetadata(component).subscribe((response:ComponentGenericResponse) => { diff --git a/catalog-ui/src/app/utils/constants.ts b/catalog-ui/src/app/utils/constants.ts index 9665999dcf..b0f22ac1f8 100644 --- a/catalog-ui/src/app/utils/constants.ts +++ b/catalog-ui/src/app/utils/constants.ts @@ -25,6 +25,13 @@ export let DEFAULT_ICON = 'defaulticon'; export let CP_END_POINT = 'CpEndPoint'; export let CHANGE_COMPONENT_CSAR_VERSION_FLAG = 'changeComponentCsarVersion'; +export let PREVIOUS_CSAR_COMPONENT = 'previousCsarComponent' + + +export class GeneralStatus { + static OK = 'OK'; + static GENERAL_ERROR = 'GENERAL_ERROR'; +} export class ComponentType { static SERVICE = 'SERVICE'; @@ -144,6 +151,11 @@ export enum FormState{ VIEW } +export class instantiationType { + public static MACRO = 'Macro'; + public static A_LA_CARTE = 'A-la-carte'; +} + export class WorkspaceMode { public static CREATE = 'create'; public static EDIT = 'edit'; @@ -159,6 +171,9 @@ export class ImagesUrl { public static SELECTED_CP_INSTANCE = '/assets/styles/images/resource-icons/selectedCPInstance.png'; public static SELECTED_VL_INSTANCE = '/assets/styles/images/resource-icons/selectedVLInstance.png'; public static CANVAS_PLUS_ICON = '/assets/styles/images/resource-icons/canvasPlusIcon.png'; + public static CANVAS_TAG_ICON = '/assets/styles/images/canvas-tagging-icons/indication.svg'; + public static CANVAS_POLICY_TAGGED_ICON = '/assets/styles/images/canvas-tagging-icons/policy_added.svg'; + public static CANVAS_GROUP_TAGGED_ICON = '/assets/styles/images/canvas-tagging-icons/group_added.svg'; public static MODULE_ICON = '/assets/styles/images/resource-icons/module.png'; public static OPEN_MODULE_ICON = '/assets/styles/images/resource-icons/openModule.png'; public static OPEN_MODULE_HOVER_ICON = '/assets/styles/images/resource-icons/openModuleHover.png'; @@ -166,6 +181,14 @@ export class ImagesUrl { public static CLOSE_MODULE_HOVER_ICON = '/assets/styles/images/resource-icons/closeModuleHover.png'; } + +export class CanvasHandleTypes { + public static ADD_EDGE = 'add-edge'; + public static TAG_AVAILABLE = 'tag-available'; + public static TAGGED_POLICY = 'tagged-policy'; + public static TAGGED_GROUP = 'tagged-group'; +} + export class ModalType { static STANDARD = 'standard'; static ERROR = 'error'; @@ -247,22 +270,21 @@ export class States { } export class EVENTS { - // static RESOURCE_LEFT_PALETTE_UPDATE_EVENT = "resourceLeftPanelUpdateEvent"; - // static RESOURCE_PNF_LEFT_PALETTE_UPDATE_EVENT = "resourcePNFLeftPanelUpdateEvent"; - // static SERVICE_LEFT_PALETTE_UPDATE_EVENT = "serviceLeftPanelUpdateEvent"; - //static VL_LEFT_PALETTE_UPDATE_EVENT = "vlLeftPanelUdateEvent"; static LEFT_PALETTE_UPDATE_EVENT = "leftPanelUpdateEvent"; static ON_CSAR_LOADING = "onCsarLoading"; static DOWNLOAD_ARTIFACT_FINISH_EVENT = "downloadArtifactFinishEvent"; static ON_WORKSPACE_SAVE_BUTTON_CLICK = "onWorkspaceSaveButtonClick"; static ON_WORKSPACE_SAVE_BUTTON_SUCCESS = "onWorkspaceSaveButtonSuccess"; static ON_WORKSPACE_SAVE_BUTTON_ERROR = "onWorkspaceSaveButtonError"; + static ON_WORKSPACE_UNSAVED_CHANGES = "onWorkspaceUnsavedChanges"; static ON_CHECKOUT = "onCheckout"; - static ON_REVERT = "onRevert"; + static ON_LIFECYCLE_CHANGE_WITH_SAVE = "onLifecycleChangeWithSave"; + static ON_LIFECYCLE_CHANGE = "onCheckout"; //Loader events static SHOW_LOADER_EVENT = "showLoaderEvent"; static HIDE_LOADER_EVENT = "hideLoaderEvent"; + static UPDATE_PANEL = 'updatePanel'; } @@ -282,6 +304,7 @@ export class GRAPH_EVENTS { static ON_COMPOSITION_GRAPH_DATA_LOADED = 'onCompositionGraphDataLoaded'; static ON_DEPLOYMENT_GRAPH_DATA_LOADED = 'onDeploymentGraphDataLoaded'; static ON_NODE_SELECTED = "onNodeSelected"; + static ON_ZONE_INSTANCE_SELECTED = "onZoneInstanceSelected"; static ON_GRAPH_BACKGROUND_CLICKED = "onGraphBackgroundClicked"; static ON_PALETTE_COMPONENT_HOVER_IN = 'onPaletteComponentHoverIn'; static ON_PALETTE_COMPONENT_HOVER_OUT = 'onPaletteComponentHoverOut'; @@ -290,16 +313,20 @@ export class GRAPH_EVENTS { static ON_PALETTE_COMPONENT_SHOW_POPUP_PANEL = 'onPaletteComponentShowPopupPanel'; static ON_PALETTE_COMPONENT_HIDE_POPUP_PANEL = 'onPaletteComponentHidePopupPanel'; static ON_COMPONENT_INSTANCE_NAME_CHANGED = 'onComponentInstanceNameChanged'; + static ON_ZONE_INSTANCE_NAME_CHANGED = 'onZoneInstanceNameChanged'; static ON_DELETE_COMPONENT_INSTANCE = 'onDeleteComponentInstance'; - static ON_DELETE_MULTIPLE_COMPONENTS = 'onDeleteMultipleComponents'; + static ON_DELETE_ZONE_INSTANCE = 'onDeleteZoneInstance'; + static ON_DELETE_COMPONENT_INSTANCE_SUCCESS = 'onDeleteComponentInstanceSuccess'; static ON_DELETE_EDGE = 'onDeleteEdge'; static ON_INSERT_NODE_TO_UCPE = 'onInsertNodeToUCPE'; static ON_REMOVE_NODE_FROM_UCPE = 'onRemoveNodeFromUCPE'; static ON_VERSION_CHANGED = 'onVersionChanged'; static ON_CREATE_COMPONENT_INSTANCE = 'onCreateComponentInstance'; - static ON_ADD_COMPONENT_INSTANCE_ZONE_START = 'onCreateComponentInstanceZone'; - static ON_FINISH_ANIMATION_ZONE = 'onFinishAnimationZone'; - static ON_ZONE_SIZE_CHANGE = 'onZoneSizeChange'; + static ON_ADD_ZONE_INSTANCE_FROM_PALETTE = 'onAddZoneInstanceFromPalette'; + static ON_CANVAS_TAG_START = 'onCanvasTagStart'; + static ON_CANVAS_TAG_END = 'onCanvasTagEnd'; + static ON_POLICY_INSTANCE_UPDATE = 'onPolicyInstanceUpdate'; + static ON_GROUP_INSTANCE_UPDATE = 'onGroupInstanceUpdate'; } @@ -320,6 +347,8 @@ export class COMPONENT_FIELDS { static COMPONENT_POLICIES = "policies"; static COMPONENT_GROUPS = "groups"; static COMPONENT_INTERFACE_OPERATIONS = "interfaces"; + static COMPONENT_NON_EXCLUDED_GROUPS = "nonExcludedGroups"; + static COMPONENT_NON_EXCLUDED_POLICIES = "nonExcludedPolicies"; } export class SERVICE_FIELDS { @@ -329,3 +358,15 @@ export class SERVICE_FIELDS { export class API_QUERY_PARAMS { static INCLUDE = "include"; } + +export enum TargetOrMemberType { + COMPONENT_INSTANCES, + GROUPS +} + +export class CANVAS_TAG_MODE { + static POLICY_TAGGING = "policy-tagging"; + static POLICY_TAGGING_HOVER = "policy-tagging-hover"; + static GROUP_TAGGING = "group-tagging"; + static GROUP_TAGGING_HOVER= "group-tagging-hover"; +} diff --git a/catalog-ui/src/app/utils/menu-handler.ts b/catalog-ui/src/app/utils/menu-handler.ts index fc6eb2081a..4c25a025da 100644 --- a/catalog-ui/src/app/utils/menu-handler.ts +++ b/catalog-ui/src/app/utils/menu-handler.ts @@ -65,7 +65,10 @@ export class MenuItemGroup { } public updateSelectedMenuItemText(newText:string) { - this.menuItems[this.selectedIndex].text = newText; + const selectedMenuItem = this.menuItems[this.selectedIndex]; + if (selectedMenuItem) { + this.menuItems[this.selectedIndex].text = newText; + } } } @@ -112,7 +115,7 @@ export class MenuHandler { // If not found search by name (name is unique). if (selectedItemIdx === -1) { selectedItemIdx = _.findIndex(components, (item:Component) => { - return item.name === selected.name; + return item.name === selected.name && item.componentType === selected.componentType; }); } @@ -144,6 +147,22 @@ export class MenuHandler { // menuItem.text = component.name; result.menuItems.push(menuItem); }); + + result.selectedIndex = this.findBreadcrumbComponentIndex(components, selected); + + // if component does not exist, then add a temporary menu item for the current component + if (result.selectedIndex === -1) { + let menuItem = new MenuItem( + // component.name, + selected.getComponentSubType() + ': ' + this.$filter('resourceName')(selected.name), + clickItemCallback, + null, + null, + [selected] + ); + result.menuItems.unshift(menuItem); + result.selectedIndex = 0; + } } return result; }; diff --git a/catalog-ui/src/app/utils/modals-handler.ts b/catalog-ui/src/app/utils/modals-handler.ts index 48ce487f9d..001d35d386 100644 --- a/catalog-ui/src/app/utils/modals-handler.ts +++ b/catalog-ui/src/app/utils/modals-handler.ts @@ -36,7 +36,7 @@ export interface IModalsHandler { openServerMessageModal(data:IServerMessageModalModel):ng.IPromise<any>; openClientMessageModal(data:IClientMessageModalModel):ng.IPromise<ng.ui.bootstrap.IModalServiceInstance>; openArtifactModal(artifact:ArtifactModel, component:Component):ng.IPromise<any>; - openEditPropertyModal(property:PropertyModel, component:Component, filteredProperties:Array<PropertyModel>, isPropertyOwnValue:boolean):ng.IPromise<any>; + openEditPropertyModal(property:PropertyModel, component:Component, filteredProperties:Array<PropertyModel>, isPropertyOwnValue:boolean, propertyOwnerType:string, propertyOwnerId:string):ng.IPromise<any>; } export class ModalsHandler implements IModalsHandler { @@ -166,7 +166,7 @@ export class ModalsHandler implements IModalsHandler { return deferred.promise; }; - openOnboadrdingModal = (okButtonText:string, currentCsarUUID?:string):ng.IPromise<any> => { + openOnboadrdingModal = (okButtonText:string, currentCsarUUID?:string, currentCsarVersion?:string):ng.IPromise<any> => { let deferred = this.$q.defer(); let modalOptions:ng.ui.bootstrap.IModalSettings = { templateUrl: '../view-models/modals/onboarding-modal/onboarding-modal-view.html', @@ -179,6 +179,9 @@ export class ModalsHandler implements IModalsHandler { }, currentCsarUUID: ():string=> { return currentCsarUUID || null; + }, + currentCsarVersion: ():string=> { + return currentCsarVersion || null; } } }; @@ -279,7 +282,7 @@ export class ModalsHandler implements IModalsHandler { * @param isPropertyValueOwner - boolean telling if the component is eligible of editing the property * @returns {IPromise<T>} - Promise telling if the modal has opened or not */ - openEditPropertyModal = (property:PropertyModel, component:Component, filteredProperties:Array<PropertyModel>, isPropertyValueOwner:boolean):ng.IPromise<any> => { + openEditPropertyModal = (property:PropertyModel, component:Component, filteredProperties:Array<PropertyModel>, isPropertyValueOwner:boolean, propertyOwnerType:string, propertyOwnerId:string):ng.IPromise<any> => { let deferred = this.$q.defer(); let modalOptions:ng.ui.bootstrap.IModalSettings = { @@ -300,6 +303,12 @@ export class ModalsHandler implements IModalsHandler { }, isPropertyValueOwner: ():boolean => { return isPropertyValueOwner; + }, + propertyOwnerType: ():string => { + return propertyOwnerType; + }, + propertyOwnerId: ():string => { + return propertyOwnerId; } } }; 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%; + } + } + } } } } diff --git a/catalog-ui/src/assets/languages/en_US.json b/catalog-ui/src/assets/languages/en_US.json index 042396798f..612d14e707 100644 --- a/catalog-ui/src/assets/languages/en_US.json +++ b/catalog-ui/src/assets/languages/en_US.json @@ -42,6 +42,7 @@ "GENERAL_LABEL_SYSTEM_NAME": "System Name:", "GENERAL_LABEL_SOURCE_SERVICE_NAME": "Source Service Name:", "GENERAL_LABEL_RESOURCE_CUSTOMIZATION_UUID": "Resource Customization UUID:", + "=========== GENERAL_TAB ===========": "", "GENERAL_TAB_LABEL_RESOURCE_MODEL_NUMBER":"Vendor Model Number", @@ -49,8 +50,8 @@ "GENERAL_TAB_LABEL_SERVICE_ROLE": "Service Role", "=========== GENERAL ERROR PAGES ===========": "", - "GENERAL_ERROR_403_TITLE": "SDC", - "GENERAL_ERROR_403_DESCRIPTION": "Sorry, You are not authorized to view this page, Please contact the <a data-ng-href='mailto:{{mailto}}'> Service Design and Creation administrator</a> for access permission.", + "GENERAL_ERROR_403_TITLE": "SDC Access Denied", + "GENERAL_ERROR_403_DESCRIPTION": "Sorry, you are not authorized to view this page. Please visit the Portal Application to provision a user account for SDC.", "=========== ERROR VIEW MODEL ===========": "", "ADMIN_EMAIL": "", @@ -425,6 +426,10 @@ "APPROVE_SUCCESS_MESSAGE_TITLE": "Approve", "DISTRIBUTE_SUCCESS_MESSAGE_TEXT": "Distributed successfully", "DISTRIBUTE_SUCCESS_MESSAGE_TITLE": "Distribute", + "RESTORE_SUCCESS_MESSAGE_TITLE":"Restore", + "RESTORE_SUCCESS_MESSAGE_TEXT":"successfully restored", + "ARCHIVE_SUCCESS_MESSAGE_TITLE":"Archive", + "ARCHIVE_SUCCESS_MESSAGE_TEXT":"successfully archived", "=========== ON BOARDING MODAL INFO MESSAGES ===========": "", "ON_BOARDING_GENERAL_INFO": "Displays a table of VSPs created using Onboarding.<br/> Each row displays details for a single VSP.<br/> When expanded you can either import CSAR files that are yet to be imported or update CSAR files that were previously imported.", @@ -448,7 +453,28 @@ "=========== PLUGIN NOT CONNECTED ===========": "", "PLUGIN_NOT_CONNECTED_ERROR_MAIN": "The \"{{pluginName}}\" plugin is currently unavailable.", - "PLUGIN_NOT_CONNECTED_ERROR_SUB": "Please try again later." - - + "PLUGIN_NOT_CONNECTED_ERROR_SUB": "Please try again later.", + + "=========== POLICY AND GROUPS ===========": "", + "ADD_TARGETS" : "Add Targets", + "ADD_MEMBERS" : "Add Members", + "=========== AUTOMATED UPGRADE ===========": "", + "RESOURCE_UPGRADE_TITLE" : "Upgrade Services", + "SERVICE_UPGRADE_TITLE" : "Update Service References", + "RESOURCE_UPGRADE_STATUS_TITLE" : "Upgrade Services - Status", + "SERVICE_UPGRADE_STATUS_TITLE" : "Update Service References - Status", + "RESOURCE_NOTHING_TO_UPGRADE" : "There are no services which include instance of <b>\"{{vspName}}\"</b> VF.<br/>Please close this popup window to continue your work.", + "SERVICE_NOTHING_TO_UPGRADE" : "There aren’t any services which include a reference to {{vspName}}.", + "RESOURCE_AUTOMATED_UPGRADE_WITH_COMPONENTS_TO_UPGRADE": "The following services include instance of <b>\"{{vspName}}\"</b> VF.<br/>Services eligible for upgrade are auto selected with the latest version of <b>\"{{vspName}}\" {{vspVersion}}</b>.<br/>Please de-select them if you do not want them to be upgraded", + "RESOURCE_AUTOMATED_UPGRADE_ALL_COMPONENTS_LOCKED": "The following services include instance of <b>\"{{vspName}}\"</b> VF, however they are locked and can not be automatically upgraded with <b>\"{{vspName}}\" {{vspVersion}}</b>.<br/>Please close this popup window to continue your work.", + "RESOURCE_AUTOMATED_UPGRADE_ALL_COMPONENTS_UPGRADED": "The listed services each include the <b>\"{{vspName}}\"</b> VF and have already been upgraded with the most recently certified version of the <b>{{vspName}} {{vspVersion}}</b>.<br/>Please close this popup window to continue your work.", + "RESOURCE_CERTIFICATION_STATUS_TEXT": "The \"{{resourceName}}\" VF was successfully updated and certified.", + "RESOURCE_UPGRADE_STATUS_SUCCESS": "Automated service upgrade was completed and successful.<br/>The services which are successfully upgraded are in checked-in state with version displayed below. Please close this popup window and proceed with design completion on the services", + "RESOURCE_UPGRADE_STATUS_FAIL": "Automated service upgrade failed.", + "SERVICE_UPGRADE_STATUS_SUCCESS": "Automated service upgrade was completed and successful.<br/>The services which are successfully upgraded are in checked-in state with version displayed below. Please close this popup window and proceed with design completion on the services", + "SERVICE_UPGRADE_STATUS_FAIL": "Automated service upgrade failed.", + "SERVICE_CERTIFICATION_STATUS_TEXT": "Service {{serviceName}} was successfully certified", + "SERVICE_AUTOMATED_UPGRADE_WITH_COMPONENTS_TO_UPGRADE": "The following services reference <b>{{vspName}}</b>.<br/> One or more of the services were not yet upgraded with the most recently certified version of <b>{{vspName}}</b>.</br>Select services from the list to upgrade them with <b>{{vspName}} {{vspVersion}}</b>.", + "SERVICE_AUTOMATED_UPGRADE_ALL_COMPONENTS_LOCKED": "The listed services reference <b>{{vspName}}</b>.<br/> These services were not upgraded with the most recently certified version of <b>{{vspName}}</b>. Currently they are locked from being upgraded with <b>{{vspName}} {{vspVersion}}</b>", + "SERVICE_AUTOMATED_UPGRADE_ALL_COMPONENTS_UPGRADED": "The listed services each reference <b>{{vspName}}</b> and have already been updated with the most recently certified version of the <b>{{vspName}} {{vspVersion}}</b>" } diff --git a/catalog-ui/src/assets/styles/app.less b/catalog-ui/src/assets/styles/app.less index 638b28eeb2..1b42aefd5f 100644 --- a/catalog-ui/src/assets/styles/app.less +++ b/catalog-ui/src/assets/styles/app.less @@ -9,6 +9,7 @@ @import 'mixins_old.less'; @import 'global.less'; @import '../../../node_modules/sdc-ui/css/style.css'; +/* @import '../../../node_modules/sdc-ui/css/theme_1802.css'; */ @import 'sprite-old.less'; @import 'sprite.less'; @@ -16,6 +17,7 @@ @import 'sprite-services-icons.less'; @import 'sprite-group-icons.less'; @import 'sprite-policy-icons.less'; +@import 'archive-resouce.less'; @import 'animation.less'; @import 'buttons.less'; @@ -49,7 +51,7 @@ @import '../../app/directives/graphs-v2/composition-graph/composition-graph.less'; @import '../../app/directives/graphs-v2/deployment-graph/deployment-graph.less'; @import '../../app/directives/graphs-v2/palette/palette.less'; -@import '../../app/directives/graphs-v2/relation-menu/relation-menu.less'; +// @import '../../app/directives/graphs-v2/relation-menu/relation-menu.less'; @import '../../app/directives/capabilities-and-requirements/capabilities-requirements-list.less'; // @import '../../app/directives/graphs-v2/asset-popover/asset-popover.less'; @import '../../app/directives/info-tooltip/info-tooltip.less'; @@ -120,3 +122,4 @@ @import '../../app/view-models/workspace/tabs/interface-operation/interface-operation.less'; @import '../../app/view-models/workspace/workspace.less'; @import '../../app/view-models/workspace/tabs/plugins/plugins-context.less'; +@import 'override.less'; diff --git a/catalog-ui/src/assets/styles/archive-resouce.less b/catalog-ui/src/assets/styles/archive-resouce.less new file mode 100644 index 0000000000..ec064e00f6 --- /dev/null +++ b/catalog-ui/src/assets/styles/archive-resouce.less @@ -0,0 +1,7 @@ +.archive-resource-btn { + background: url('images/archive-delete/archive.svg') top left no-repeat; + display: inline-block; + width: 24px; + height: 24px; + text-indent: 100%; +}
\ No newline at end of file diff --git a/catalog-ui/src/assets/styles/images/archive-delete/archive.png b/catalog-ui/src/assets/styles/images/archive-delete/archive.png Binary files differnew file mode 100644 index 0000000000..5284a5401e --- /dev/null +++ b/catalog-ui/src/assets/styles/images/archive-delete/archive.png diff --git a/catalog-ui/src/assets/styles/images/archive-delete/archive.svg b/catalog-ui/src/assets/styles/images/archive-delete/archive.svg new file mode 100644 index 0000000000..162e5eafe5 --- /dev/null +++ b/catalog-ui/src/assets/styles/images/archive-delete/archive.svg @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"> + <!-- Generator: Sketch 48.2 (47327) - http://www.bohemiancoding.com/sketch --> + <title>icons/versio_bar/archive</title> + <desc>Created with Sketch.</desc> + <defs></defs> + <g id="Symbols-" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <g id="icons/versio_bar/archive" fill="#5A5A5A"> + <path d="M1.96142578,9.02011447 C1.16722011,9.02011447 0,9.03344727 0,7.20846897 L0,4.06491428 C0,2.16137695 1.16722011,2 1.96142578,2 L22.0875382,2 C22.8817438,2 24.0641007,2.46750217 24.0641007,4.06491428 L24.0641007,7.20846897 C24.0641007,8.57785373 22.8817438,9.02011447 22.0875382,9.02011447 L21.0783829,9.02011447 L21.0783829,21.6395264 C21.0783829,22.4091347 20.4299479,23.0284153 19.6357422,23.0284153 L4.46949616,23.0284153 C3.67529049,23.0284153 3.02685547,22.4091347 3.02685547,21.6395264 L3.02685547,9.02011447 L1.96142578,9.02011447 Z M19,20.9406738 L19,9.00119358 L5.11112098,9.00119358 L5.11112098,20.9406738 L19,20.9406738 Z M9,13 C8.4,13 8,12.6 8,12 C8,11.4 8.4,11 9,11 L15,11 C15.6,11 16,11.4 16,12 C16,12.6 15.6,13 15,13 L9,13 Z M2.87234189,7.00119358 L21.206041,7.00119358 C21.6790502,7.00119358 22.0625,6.66540714 22.0625,6.25119358 L22.0625,4.75119358 C22.0625,4.33698001 21.6790502,4.00119358 21.206041,4.00119358 L2.87234189,4.00119358 C2.39933264,4.00119358 2.01588288,4.33698001 2.01588288,4.75119358 L2.01588288,6.25119358 C2.01588288,6.66540714 2.39933264,7.00119358 2.87234189,7.00119358 Z" id="Combined-Shape"></path> + </g> + </g> +</svg>
\ No newline at end of file diff --git a/catalog-ui/src/assets/styles/images/canvas-tagging-icons/group_1.svg b/catalog-ui/src/assets/styles/images/canvas-tagging-icons/group_1.svg new file mode 100644 index 0000000000..fa4e06c4bc --- /dev/null +++ b/catalog-ui/src/assets/styles/images/canvas-tagging-icons/group_1.svg @@ -0,0 +1,33 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="44" height="41"> + <defs> + <filter id="groups_1-a" width="145.5%" height="145.5%" x="-22.7%" y="-13.6%" filterUnits="objectBoundingBox"> + <feOffset dy="2" in="SourceAlpha" result="shadowOffsetOuter1"/> + <feGaussianBlur in="shadowOffsetOuter1" result="shadowBlurOuter1" stdDeviation="1"/> + <feColorMatrix in="shadowBlurOuter1" result="shadowMatrixOuter1" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0"/> + <feMerge> + <feMergeNode in="shadowMatrixOuter1"/> + <feMergeNode in="SourceGraphic"/> + </feMerge> + </filter> + <path id="groups_1-b" d="M6,4 L6,1 C6,0.4 5.6,0 5,0 C4.4,0 4,0.4 4,1 L4,4 L1,4 C0.4,4 0,4.4 0,5 C0,5.6 0.4,6 1,6 L4,6 L4,9 C4,9.6 4.4,10 5,10 C5.6,10 6,9.6 6,9 L6,6 L9,6 C9.6,6 10,5.6 10,5 C10,4.4 9.6,4 9,4 L6,4 Z"/> + <polygon id="groups_1-d" points="7.841 8.516 12.487 6.865 0 0 3.64 13.776 6.366 9.668 9.63 13.845 11.104 12.693"/> + <filter id="groups_1-c" width="196.1%" height="186.7%" x="-48.1%" y="-36.1%" filterUnits="objectBoundingBox"> + <feMorphology in="SourceAlpha" operator="dilate" radius="1" result="shadowSpreadOuter1"/> + <feOffset dy="1" in="shadowSpreadOuter1" result="shadowOffsetOuter1"/> + <feGaussianBlur in="shadowOffsetOuter1" result="shadowBlurOuter1" stdDeviation="1.5"/> + <feComposite in="shadowBlurOuter1" in2="SourceAlpha" operator="out" result="shadowBlurOuter1"/> + <feColorMatrix in="shadowBlurOuter1" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0"/> + </filter> + </defs> + <g fill="none" fill-rule="evenodd" transform="translate(4 3)"> + <g transform="translate(15 11)"> + <path fill="#009FDB" stroke="#FFF" d="M3,0 L19,0 C20.6568542,-3.04359188e-16 22,1.34314575 22,3 L22,19 C22,20.6568542 20.6568542,22 19,22 L3,22 C1.34314575,22 2.02906125e-16,20.6568542 0,19 L0,3 C-2.02906125e-16,1.34314575 1.34314575,3.04359188e-16 3,0 Z" filter="url(#groups_1-a)"/> + <g transform="translate(6 6)"> + <use fill="#FFF" xlink:href="#groups_1-b"/> + </g> + </g> + <use fill="#000" filter="url(#groups_1-c)" xlink:href="#groups_1-d"/> + <use fill="#FFF" xlink:href="#groups_1-d"/> + <path stroke="#000" stroke-opacity=".8" d="M8.6617598,8.75489325 L11.806255,12.7796636 L9.54386134,14.5472392 L6.39936616,10.5224689 L3.44128728,14.9806328 L-0.781456351,-1.00021852 L13.7031213,6.96320943 L8.6617598,8.75489325 Z"/> + </g> +</svg> diff --git a/catalog-ui/src/assets/styles/images/canvas-tagging-icons/group_2.svg b/catalog-ui/src/assets/styles/images/canvas-tagging-icons/group_2.svg new file mode 100644 index 0000000000..f6b1cf1eb7 --- /dev/null +++ b/catalog-ui/src/assets/styles/images/canvas-tagging-icons/group_2.svg @@ -0,0 +1,33 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="45" height="44"> + <defs> + <filter id="groups_2-a" width="145.5%" height="145.5%" x="-22.7%" y="-13.6%" filterUnits="objectBoundingBox"> + <feOffset dy="2" in="SourceAlpha" result="shadowOffsetOuter1"/> + <feGaussianBlur in="shadowOffsetOuter1" result="shadowBlurOuter1" stdDeviation="1"/> + <feColorMatrix in="shadowBlurOuter1" result="shadowMatrixOuter1" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0"/> + <feMerge> + <feMergeNode in="shadowMatrixOuter1"/> + <feMergeNode in="SourceGraphic"/> + </feMerge> + </filter> + <path id="groups_2-b" d="M6,4 L6,1 C6,0.4 5.6,0 5,0 C4.4,0 4,0.4 4,1 L4,4 L1,4 C0.4,4 0,4.4 0,5 C0,5.6 0.4,6 1,6 L4,6 L4,9 C4,9.6 4.4,10 5,10 C5.6,10 6,9.6 6,9 L6,6 L9,6 C9.6,6 10,5.6 10,5 C10,4.4 9.6,4 9,4 L6,4 Z"/> + <path id="groups_2-d" d="M3.98190975,9.99999992 L3.09529739,8.64532799 C2.48991036,7.72034561 1.20039622,7.38287755 0.214035029,7.88996475 L0.443864811,7.77180951 C0.199079509,7.89765337 0.081702931,8.21138642 0.182488604,8.47214489 L1.40976041,11.6474128 C1.60431817,12.1507837 2.10121802,12.8626937 2.51297222,13.2203156 C2.51297222,13.2203156 4.98190975,15.2638557 4.98190975,16.03003 L4.98190975,16.9999999 L8.98190975,16.9999999 L9.98190975,14.9999999 L10.9819098,16.9999999 L11.9819098,17 L11.9819098,16.0300302 C11.9819098,15.2638559 13.4907506,12.8506759 13.4907506,12.8506759 C13.7684994,12.3815967 14,11.5552351 14,11.0065899 L14,6.9718022 C13.9819097,6.07849828 13.2225759,5.35453877 12.2856231,5.35453877 C11.8168923,5.35453877 11.4372254,5.71651852 11.4372254,6.1634131 L11.4372254,6.48657465 C11.4372254,5.59327073 10.6778916,4.86931122 9.7409389,4.86931122 C9.27220806,4.86931122 8.89254117,5.23129097 8.89254117,5.67818555 L8.89254117,6.0013471 C8.89254117,5.10804318 8.13320739,4.38408367 7.19625465,4.38408367 C6.72752382,4.38408367 6.34785693,4.74606342 6.34785693,5.192958 L6.34785693,5.51611955 C6.34785693,5.37255591 6.33251267,5.25843099 6.30286699,5.16799051 L6.04408993,1.0012141 C6.00909675,0.437760917 5.53419442,0 4.98190967,0 C4.42577449,0 3.98190967,0.447629061 3.98190967,0.999807492 L3.98190967,5 L3.98190975,9.99999992 Z M11,9.00000012 L12,9 L12,12.9999999 L11,13 L11,9.00000012 L11,9.00000012 Z M9,9.00000012 L10,9 L10,12.9999999 L9,13 L9,9.00000012 L9,9.00000012 Z M7,9.00000012 L8,9 L8,12.9999999 L7,13 L7,9.00000012 L7,9.00000012 Z"/> + <filter id="groups_2-c" width="186.6%" height="170.6%" x="-43.3%" y="-29.4%" filterUnits="objectBoundingBox"> + <feMorphology in="SourceAlpha" operator="dilate" radius="1" result="shadowSpreadOuter1"/> + <feOffset dy="1" in="shadowSpreadOuter1" result="shadowOffsetOuter1"/> + <feGaussianBlur in="shadowOffsetOuter1" result="shadowBlurOuter1" stdDeviation="1.5"/> + <feComposite in="shadowBlurOuter1" in2="SourceAlpha" operator="out" result="shadowBlurOuter1"/> + <feColorMatrix in="shadowBlurOuter1" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0"/> + </filter> + </defs> + <g fill="none" fill-rule="evenodd" transform="translate(4 3)"> + <g transform="translate(16 14)"> + <path fill="#009FDB" stroke="#FFF" d="M3,0 L19,0 C20.6568542,-3.04359188e-16 22,1.34314575 22,3 L22,19 C22,20.6568542 20.6568542,22 19,22 L3,22 C1.34314575,22 2.02906125e-16,20.6568542 0,19 L0,3 C-2.02906125e-16,1.34314575 1.34314575,3.04359188e-16 3,0 Z" filter="url(#groups_2-a)"/> + <g transform="translate(6 6)"> + <use fill="#FFF" xlink:href="#groups_2-b"/> + </g> + </g> + <use fill="#000" filter="url(#groups_2-c)" xlink:href="#groups_2-d"/> + <use fill="#FFF" xlink:href="#groups_2-d"/> + <path stroke="#000" stroke-opacity=".8" d="M3.48190972,8.32416496 L3.48190967,5 L3.48190967,0.999807491 C3.48190967,0.170429729 4.15068503,-0.5 4.98190967,-0.5 C5.80152555,-0.5 6.49196322,0.146369011 6.54312845,0.970221378 L6.729109,3.96484284 C6.87493261,3.91257008 7.03237962,3.88408367 7.19625465,3.88408367 C7.87883467,3.88408367 8.49131623,4.18500488 8.89495329,4.65876818 C9.12697419,4.47737206 9.42176446,4.36931122 9.7409389,4.36931122 C10.4235189,4.36931122 11.0360005,4.67023243 11.4396375,5.14399573 C11.6716584,4.96259961 11.9664487,4.85453877 12.2856231,4.85453877 C13.4881886,4.85453877 14.4761616,5.78959763 14.5,6.9718022 L14.5,11.0065899 C14.5,11.6413376 14.2462612,12.556081 13.9147021,13.1157516 C13.8694672,13.1880985 13.788913,13.3198554 13.6849071,13.4950007 C13.511352,13.7872659 13.3378324,14.0912197 13.1763581,14.3904728 C13.1037538,14.5250271 13.0351585,14.6557806 12.9712321,14.7818029 C12.6639479,15.3875721 12.4819098,15.8603735 12.4819098,16.0300302 L12.4819098,17.5000001 L10.6728927,17.4999999 L9.98190975,16.1180339 L9.29092675,17.4999999 L4.48190975,17.4999999 L4.48190975,16.03003 C4.48190975,15.9441015 4.22664544,15.5664829 3.80083171,15.1083367 C3.6777582,14.9759181 3.54245432,14.8374578 3.39695629,14.6944531 C3.13416835,14.4361686 2.85142222,14.1758166 2.56855227,13.9270547 C2.39897253,13.7779227 2.26768741,13.6663479 2.1851049,13.5978113 C1.71375103,13.1884251 1.16828661,12.409552 0.943384241,11.8276717 L-0.28388756,8.65240379 C-0.444283002,8.23741952 -0.319449182,7.76260422 0.000730716832,7.47505565 L-0.0145732772,7.44528707 C0.0327844808,7.42094049 0.0806824543,7.39816945 0.129050684,7.37695571 C0.156751662,7.359073 0.18549978,7.34242973 0.215256505,7.32713183 L0.221175841,7.33864583 C1.37808265,6.88340881 2.77316135,7.29220176 3.48190972,8.32416496 Z M0.000730716832,7.47505565 C0.0405415491,7.43930216 0.0833724658,7.40644385 0.129050684,7.37695571 C0.159577614,7.36356695 0.190291862,7.35079852 0.221175841,7.33864583 L0.672473117,8.2164872 L0.442643335,8.33464243 L0.000730716832,7.47505565 Z M11.5,11 L11.5,12.9999999 L11.9999999,12.4999999 L10.9999999,12.5 L11.5,13 L11.5,11 Z M11.5,11 L11.5,9.00000012 L11.0000001,9.50000012 L12.0000001,9.5 L11.5,9 L11.5,11 Z M9.5,11 L9.5,12.9999999 L9.99999994,12.4999999 L8.99999994,12.5 L9.5,13 L9.5,11 Z M9.5,11 L9.5,9.00000012 L9.00000006,9.50000012 L10.0000001,9.5 L9.5,9 L9.5,11 Z M7.5,11 L7.5,12.9999999 L7.99999994,12.4999999 L6.99999994,12.5 L7.5,13 L7.5,11 Z M7.5,11 L7.5,9.00000012 L7.00000006,9.50000012 L8.00000006,9.5 L7.5,9 L7.5,11 Z"/> + </g> +</svg> diff --git a/catalog-ui/src/assets/styles/images/canvas-tagging-icons/policy_1.svg b/catalog-ui/src/assets/styles/images/canvas-tagging-icons/policy_1.svg new file mode 100644 index 0000000000..c7f83e89d6 --- /dev/null +++ b/catalog-ui/src/assets/styles/images/canvas-tagging-icons/policy_1.svg @@ -0,0 +1,33 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="44" height="41"> + <defs> + <filter id="policies_1-a" width="145.5%" height="145.5%" x="-22.7%" y="-13.6%" filterUnits="objectBoundingBox"> + <feOffset dy="2" in="SourceAlpha" result="shadowOffsetOuter1"/> + <feGaussianBlur in="shadowOffsetOuter1" result="shadowBlurOuter1" stdDeviation="1"/> + <feColorMatrix in="shadowBlurOuter1" result="shadowMatrixOuter1" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0"/> + <feMerge> + <feMergeNode in="shadowMatrixOuter1"/> + <feMergeNode in="SourceGraphic"/> + </feMerge> + </filter> + <path id="policies_1-b" d="M6,4 L6,1 C6,0.4 5.6,0 5,0 C4.4,0 4,0.4 4,1 L4,4 L1,4 C0.4,4 0,4.4 0,5 C0,5.6 0.4,6 1,6 L4,6 L4,9 C4,9.6 4.4,10 5,10 C5.6,10 6,9.6 6,9 L6,6 L9,6 C9.6,6 10,5.6 10,5 C10,4.4 9.6,4 9,4 L6,4 Z"/> + <polygon id="policies_1-d" points="7.841 8.516 12.487 6.865 0 0 3.64 13.776 6.366 9.668 9.63 13.845 11.104 12.693"/> + <filter id="policies_1-c" width="196.1%" height="186.7%" x="-48.1%" y="-36.1%" filterUnits="objectBoundingBox"> + <feMorphology in="SourceAlpha" operator="dilate" radius="1" result="shadowSpreadOuter1"/> + <feOffset dy="1" in="shadowSpreadOuter1" result="shadowOffsetOuter1"/> + <feGaussianBlur in="shadowOffsetOuter1" result="shadowBlurOuter1" stdDeviation="1.5"/> + <feComposite in="shadowBlurOuter1" in2="SourceAlpha" operator="out" result="shadowBlurOuter1"/> + <feColorMatrix in="shadowBlurOuter1" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0"/> + </filter> + </defs> + <g fill="none" fill-rule="evenodd" transform="translate(4 3)"> + <g transform="translate(15 11)"> + <path fill="#162F90" stroke="#FFF" d="M3,0 L19,0 C20.6568542,-3.04359188e-16 22,1.34314575 22,3 L22,19 C22,20.6568542 20.6568542,22 19,22 L3,22 C1.34314575,22 2.02906125e-16,20.6568542 0,19 L0,3 C-2.02906125e-16,1.34314575 1.34314575,3.04359188e-16 3,0 Z" filter="url(#policies_1-a)"/> + <g transform="translate(6 6)"> + <use fill="#FFF" xlink:href="#policies_1-b"/> + </g> + </g> + <use fill="#000" filter="url(#policies_1-c)" xlink:href="#policies_1-d"/> + <use fill="#FFF" xlink:href="#policies_1-d"/> + <path stroke="#000" stroke-opacity=".8" d="M8.6617598,8.75489325 L11.806255,12.7796636 L9.54386134,14.5472392 L6.39936616,10.5224689 L3.44128728,14.9806328 L-0.781456351,-1.00021852 L13.7031213,6.96320943 L8.6617598,8.75489325 Z"/> + </g> +</svg> diff --git a/catalog-ui/src/assets/styles/images/canvas-tagging-icons/policy_2.svg b/catalog-ui/src/assets/styles/images/canvas-tagging-icons/policy_2.svg new file mode 100644 index 0000000000..0b5217727f --- /dev/null +++ b/catalog-ui/src/assets/styles/images/canvas-tagging-icons/policy_2.svg @@ -0,0 +1,33 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="45" height="44"> + <defs> + <filter id="policies_2-a" width="145.5%" height="145.5%" x="-22.7%" y="-13.6%" filterUnits="objectBoundingBox"> + <feOffset dy="2" in="SourceAlpha" result="shadowOffsetOuter1"/> + <feGaussianBlur in="shadowOffsetOuter1" result="shadowBlurOuter1" stdDeviation="1"/> + <feColorMatrix in="shadowBlurOuter1" result="shadowMatrixOuter1" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0"/> + <feMerge> + <feMergeNode in="shadowMatrixOuter1"/> + <feMergeNode in="SourceGraphic"/> + </feMerge> + </filter> + <path id="policies_2-b" d="M6,4 L6,1 C6,0.4 5.6,0 5,0 C4.4,0 4,0.4 4,1 L4,4 L1,4 C0.4,4 0,4.4 0,5 C0,5.6 0.4,6 1,6 L4,6 L4,9 C4,9.6 4.4,10 5,10 C5.6,10 6,9.6 6,9 L6,6 L9,6 C9.6,6 10,5.6 10,5 C10,4.4 9.6,4 9,4 L6,4 Z"/> + <path id="policies_2-d" d="M3.98190975,9.99999992 L3.09529739,8.64532799 C2.48991036,7.72034561 1.20039622,7.38287755 0.214035029,7.88996475 L0.443864811,7.77180951 C0.199079509,7.89765337 0.081702931,8.21138642 0.182488604,8.47214489 L1.40976041,11.6474128 C1.60431817,12.1507837 2.10121802,12.8626937 2.51297222,13.2203156 C2.51297222,13.2203156 4.98190975,15.2638557 4.98190975,16.03003 L4.98190975,16.9999999 L8.98190975,16.9999999 L9.98190975,14.9999999 L10.9819098,16.9999999 L11.9819098,17 L11.9819098,16.0300302 C11.9819098,15.2638559 13.4907506,12.8506759 13.4907506,12.8506759 C13.7684994,12.3815967 14,11.5552351 14,11.0065899 L14,6.9718022 C13.9819097,6.07849828 13.2225759,5.35453877 12.2856231,5.35453877 C11.8168923,5.35453877 11.4372254,5.71651852 11.4372254,6.1634131 L11.4372254,6.48657465 C11.4372254,5.59327073 10.6778916,4.86931122 9.7409389,4.86931122 C9.27220806,4.86931122 8.89254117,5.23129097 8.89254117,5.67818555 L8.89254117,6.0013471 C8.89254117,5.10804318 8.13320739,4.38408367 7.19625465,4.38408367 C6.72752382,4.38408367 6.34785693,4.74606342 6.34785693,5.192958 L6.34785693,5.51611955 C6.34785693,5.37255591 6.33251267,5.25843099 6.30286699,5.16799051 L6.04408993,1.0012141 C6.00909675,0.437760917 5.53419442,0 4.98190967,0 C4.42577449,0 3.98190967,0.447629061 3.98190967,0.999807492 L3.98190967,5 L3.98190975,9.99999992 Z M11,9.00000012 L12,9 L12,12.9999999 L11,13 L11,9.00000012 L11,9.00000012 Z M9,9.00000012 L10,9 L10,12.9999999 L9,13 L9,9.00000012 L9,9.00000012 Z M7,9.00000012 L8,9 L8,12.9999999 L7,13 L7,9.00000012 L7,9.00000012 Z"/> + <filter id="policies_2-c" width="186.6%" height="170.6%" x="-43.3%" y="-29.4%" filterUnits="objectBoundingBox"> + <feMorphology in="SourceAlpha" operator="dilate" radius="1" result="shadowSpreadOuter1"/> + <feOffset dy="1" in="shadowSpreadOuter1" result="shadowOffsetOuter1"/> + <feGaussianBlur in="shadowOffsetOuter1" result="shadowBlurOuter1" stdDeviation="1.5"/> + <feComposite in="shadowBlurOuter1" in2="SourceAlpha" operator="out" result="shadowBlurOuter1"/> + <feColorMatrix in="shadowBlurOuter1" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0"/> + </filter> + </defs> + <g fill="none" fill-rule="evenodd" transform="translate(4 3)"> + <g transform="translate(16 14)"> + <path fill="#162F90" stroke="#FFF" d="M3,0 L19,0 C20.6568542,-3.04359188e-16 22,1.34314575 22,3 L22,19 C22,20.6568542 20.6568542,22 19,22 L3,22 C1.34314575,22 2.02906125e-16,20.6568542 0,19 L0,3 C-2.02906125e-16,1.34314575 1.34314575,3.04359188e-16 3,0 Z" filter="url(#policies_2-a)"/> + <g transform="translate(6 6)"> + <use fill="#FFF" xlink:href="#policies_2-b"/> + </g> + </g> + <use fill="#000" filter="url(#policies_2-c)" xlink:href="#policies_2-d"/> + <use fill="#FFF" xlink:href="#policies_2-d"/> + <path stroke="#000" stroke-opacity=".8" d="M3.48190972,8.32416496 L3.48190967,5 L3.48190967,0.999807491 C3.48190967,0.170429729 4.15068503,-0.5 4.98190967,-0.5 C5.80152555,-0.5 6.49196322,0.146369011 6.54312845,0.970221378 L6.729109,3.96484284 C6.87493261,3.91257008 7.03237962,3.88408367 7.19625465,3.88408367 C7.87883467,3.88408367 8.49131623,4.18500488 8.89495329,4.65876818 C9.12697419,4.47737206 9.42176446,4.36931122 9.7409389,4.36931122 C10.4235189,4.36931122 11.0360005,4.67023243 11.4396375,5.14399573 C11.6716584,4.96259961 11.9664487,4.85453877 12.2856231,4.85453877 C13.4881886,4.85453877 14.4761616,5.78959763 14.5,6.9718022 L14.5,11.0065899 C14.5,11.6413376 14.2462612,12.556081 13.9147021,13.1157516 C13.8694672,13.1880985 13.788913,13.3198554 13.6849071,13.4950007 C13.511352,13.7872659 13.3378324,14.0912197 13.1763581,14.3904728 C13.1037538,14.5250271 13.0351585,14.6557806 12.9712321,14.7818029 C12.6639479,15.3875721 12.4819098,15.8603735 12.4819098,16.0300302 L12.4819098,17.5000001 L10.6728927,17.4999999 L9.98190975,16.1180339 L9.29092675,17.4999999 L4.48190975,17.4999999 L4.48190975,16.03003 C4.48190975,15.9441015 4.22664544,15.5664829 3.80083171,15.1083367 C3.6777582,14.9759181 3.54245432,14.8374578 3.39695629,14.6944531 C3.13416835,14.4361686 2.85142222,14.1758166 2.56855227,13.9270547 C2.39897253,13.7779227 2.26768741,13.6663479 2.1851049,13.5978113 C1.71375103,13.1884251 1.16828661,12.409552 0.943384241,11.8276717 L-0.28388756,8.65240379 C-0.444283002,8.23741952 -0.319449182,7.76260422 0.000730716832,7.47505565 L-0.0145732772,7.44528707 C0.0327844808,7.42094049 0.0806824543,7.39816945 0.129050684,7.37695571 C0.156751662,7.359073 0.18549978,7.34242973 0.215256505,7.32713183 L0.221175841,7.33864583 C1.37808265,6.88340881 2.77316135,7.29220176 3.48190972,8.32416496 Z M0.000730716832,7.47505565 C0.0405415491,7.43930216 0.0833724658,7.40644385 0.129050684,7.37695571 C0.159577614,7.36356695 0.190291862,7.35079852 0.221175841,7.33864583 L0.672473117,8.2164872 L0.442643335,8.33464243 L0.000730716832,7.47505565 Z M11.5,11 L11.5,12.9999999 L11.9999999,12.4999999 L10.9999999,12.5 L11.5,13 L11.5,11 Z M11.5,11 L11.5,9.00000012 L11.0000001,9.50000012 L12.0000001,9.5 L11.5,9 L11.5,11 Z M9.5,11 L9.5,12.9999999 L9.99999994,12.4999999 L8.99999994,12.5 L9.5,13 L9.5,11 Z M9.5,11 L9.5,9.00000012 L9.00000006,9.50000012 L10.0000001,9.5 L9.5,9 L9.5,11 Z M7.5,11 L7.5,12.9999999 L7.99999994,12.4999999 L6.99999994,12.5 L7.5,13 L7.5,11 Z M7.5,11 L7.5,9.00000012 L7.00000006,9.50000012 L8.00000006,9.5 L7.5,9 L7.5,11 Z"/> + </g> +</svg> diff --git a/catalog-ui/src/assets/styles/images/canvas-tagging-icons/policy_added.svg b/catalog-ui/src/assets/styles/images/canvas-tagging-icons/policy_added.svg index 9ff39019c7..269f437636 100644 --- a/catalog-ui/src/assets/styles/images/canvas-tagging-icons/policy_added.svg +++ b/catalog-ui/src/assets/styles/images/canvas-tagging-icons/policy_added.svg @@ -1,33 +1,18 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> - <!-- Generator: Sketch 48.2 (47327) - http://www.bohemiancoding.com/sketch --> - <title>Group 13 Copy</title> - <desc>Created with Sketch.</desc> - <defs> - <path d="M3,0 L15,0 C16.6568542,-3.04359188e-16 18,1.34314575 18,3 L18,15 C18,16.6568542 16.6568542,18 15,18 L3,18 C1.34314575,18 -6.85272294e-16,16.6568542 -8.8817842e-16,15 L0,3 C-2.02906125e-16,1.34314575 1.34314575,-5.83819232e-16 3,-8.8817842e-16 Z" id="path-1"></path> - <filter x="-25.0%" y="-13.9%" width="150.0%" height="150.0%" filterUnits="objectBoundingBox" id="filter-2"> - <feMorphology radius="0.5" operator="dilate" in="SourceAlpha" result="shadowSpreadOuter1"></feMorphology> - <feOffset dx="0" dy="2" in="shadowSpreadOuter1" result="shadowOffsetOuter1"></feOffset> - <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur> - <feComposite in="shadowBlurOuter1" in2="SourceAlpha" operator="out" result="shadowBlurOuter1"></feComposite> - <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix> - </filter> - <path d="M12.6603086,4.57405469 L8.30209375,11.5833406 L5.57568359,9.20957266 C5.13068359,8.77957266 4.46368359,8.77957266 4.01968359,9.20957266 C3.57568359,9.64057266 3.57568359,10.2865727 4.01968359,10.7175727 L7.52409375,13.8453406 C7.74609375,14.0603406 7.96809375,14.1683406 8.30209375,14.1683406 C8.63509375,14.1683406 8.85809375,14.0603406 9.07909375,13.8453406 L14.2163086,6.08105469 C14.6603086,5.65105469 14.6603086,5.00505469 14.2163086,4.57405469 C13.7723086,4.14305469 13.1053086,4.14305469 12.6603086,4.57405469 Z" id="path-3"></path> - </defs> - <g id="sdc" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> - <g id="Group-13-Copy" transform="translate(3.000000, 1.000000)"> - <g id="Group-4-Copy-9"> - <g id="Group-3"> - <g id="Rectangle-15-Copy-5"> - <use fill="black" fill-opacity="1" filter="url(#filter-2)" xlink:href="#path-1"></use> - <use stroke="#FFFFFF" stroke-width="1" fill="#0568AE" fill-rule="evenodd" xlink:href="#path-1"></use> - </g> - </g> - </g> - <mask id="mask-4" fill="white"> - <use xlink:href="#path-3"></use> - </mask> - <use id="Mask" fill="#FFFFFF" xlink:href="#path-3"></use> - </g> - </g> -</svg>
\ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24"> + <defs> + <path id="group-13-copy-b" d="M3,0 L15,0 C16.6568542,-3.04359188e-16 18,1.34314575 18,3 L18,15 C18,16.6568542 16.6568542,18 15,18 L3,18 C1.34314575,18 -6.85272294e-16,16.6568542 -8.8817842e-16,15 L0,3 C-2.02906125e-16,1.34314575 1.34314575,-5.83819232e-16 3,-8.8817842e-16 Z"/> + <filter id="group-13-copy-a" width="150%" height="150%" x="-25%" y="-13.9%" filterUnits="objectBoundingBox"> + <feMorphology in="SourceAlpha" operator="dilate" radius=".5" result="shadowSpreadOuter1"/> + <feOffset dy="2" in="shadowSpreadOuter1" result="shadowOffsetOuter1"/> + <feGaussianBlur in="shadowOffsetOuter1" result="shadowBlurOuter1" stdDeviation="1"/> + <feComposite in="shadowBlurOuter1" in2="SourceAlpha" operator="out" result="shadowBlurOuter1"/> + <feColorMatrix in="shadowBlurOuter1" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0"/> + </filter> + <path id="group-13-copy-c" d="M12.6603086,4.57405469 L8.30209375,11.5833406 L5.57568359,9.20957266 C5.13068359,8.77957266 4.46368359,8.77957266 4.01968359,9.20957266 C3.57568359,9.64057266 3.57568359,10.2865727 4.01968359,10.7175727 L7.52409375,13.8453406 C7.74609375,14.0603406 7.96809375,14.1683406 8.30209375,14.1683406 C8.63509375,14.1683406 8.85809375,14.0603406 9.07909375,13.8453406 L14.2163086,6.08105469 C14.6603086,5.65105469 14.6603086,5.00505469 14.2163086,4.57405469 C13.7723086,4.14305469 13.1053086,4.14305469 12.6603086,4.57405469 Z"/> + </defs> + <g fill="none" fill-rule="evenodd" transform="translate(3 1)"> + <use fill="#000" filter="url(#group-13-copy-a)" xlink:href="#group-13-copy-b"/> + <use fill="#162F90" stroke="#FFF" xlink:href="#group-13-copy-b"/> + <use fill="#FFF" xlink:href="#group-13-copy-c"/> + </g> +</svg> diff --git a/catalog-ui/src/assets/styles/images/relationship-icons/BindsTo.svg b/catalog-ui/src/assets/styles/images/relationship-icons/BindsTo.svg index ae5647dda9..e19fc4cb64 100644 --- a/catalog-ui/src/assets/styles/images/relationship-icons/BindsTo.svg +++ b/catalog-ui/src/assets/styles/images/relationship-icons/BindsTo.svg @@ -1,4 +1,4 @@ -<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid" width="25" height="25" viewBox="0 0 25 25"> +<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" width="25" height="25" viewBox="0 0 25 25"> <defs> <style> .cls-1 { diff --git a/catalog-ui/src/assets/styles/images/relationship-icons/ConnectedTo.svg b/catalog-ui/src/assets/styles/images/relationship-icons/ConnectedTo.svg index 4ee7672305..9f7a75b6f2 100644 --- a/catalog-ui/src/assets/styles/images/relationship-icons/ConnectedTo.svg +++ b/catalog-ui/src/assets/styles/images/relationship-icons/ConnectedTo.svg @@ -1,4 +1,4 @@ -<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid" width="25" height="25" viewBox="0 0 25 25"> +<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" width="25" height="25" viewBox="0 0 25 25"> <defs> <style> .cls-1 { diff --git a/catalog-ui/src/assets/styles/images/relationship-icons/DependsOn.svg b/catalog-ui/src/assets/styles/images/relationship-icons/DependsOn.svg index e38808e2df..39d613b25e 100644 --- a/catalog-ui/src/assets/styles/images/relationship-icons/DependsOn.svg +++ b/catalog-ui/src/assets/styles/images/relationship-icons/DependsOn.svg @@ -1,4 +1,4 @@ -<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid" width="25" height="25" viewBox="0 0 25 25"> +<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" width="25" height="25" viewBox="0 0 25 25"> <defs> <style> .cls-1, .cls-2 { diff --git a/catalog-ui/src/assets/styles/images/relationship-icons/HostedOn.svg b/catalog-ui/src/assets/styles/images/relationship-icons/HostedOn.svg index 5daf84a334..22df67c4c3 100644 --- a/catalog-ui/src/assets/styles/images/relationship-icons/HostedOn.svg +++ b/catalog-ui/src/assets/styles/images/relationship-icons/HostedOn.svg @@ -1,4 +1,4 @@ -<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid" width="25" height="25" viewBox="0 0 25 25"> +<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" width="25" height="25" viewBox="0 0 25 25"> <defs> <style> .cls-1 { diff --git a/catalog-ui/src/assets/styles/images/relationship-icons/LinksTo.svg b/catalog-ui/src/assets/styles/images/relationship-icons/LinksTo.svg index fb4c687774..3299595503 100644 --- a/catalog-ui/src/assets/styles/images/relationship-icons/LinksTo.svg +++ b/catalog-ui/src/assets/styles/images/relationship-icons/LinksTo.svg @@ -1,4 +1,4 @@ -<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid" width="25" height="25" viewBox="0 0 25 25"> +<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" width="25" height="25" viewBox="0 0 25 25"> <defs> <style> .cls-1 { diff --git a/catalog-ui/src/assets/styles/images/relationship-icons/RoutesTo.svg b/catalog-ui/src/assets/styles/images/relationship-icons/RoutesTo.svg index 4c3caf5886..3a79cff034 100644 --- a/catalog-ui/src/assets/styles/images/relationship-icons/RoutesTo.svg +++ b/catalog-ui/src/assets/styles/images/relationship-icons/RoutesTo.svg @@ -1,4 +1,4 @@ -<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid" width="25" height="25" viewBox="0 0 25 25"> +<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" width="25" height="25" viewBox="0 0 25 25"> <defs> <style> .cls-1 { diff --git a/catalog-ui/src/assets/styles/images/relationship-icons/arrow.svg b/catalog-ui/src/assets/styles/images/relationship-icons/arrow.svg index 4696e50d57..02ec817db7 100644 --- a/catalog-ui/src/assets/styles/images/relationship-icons/arrow.svg +++ b/catalog-ui/src/assets/styles/images/relationship-icons/arrow.svg @@ -1,4 +1,4 @@ -<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid" width="7" height="9" viewBox="0 0 7 9"> +<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" width="7" height="9" viewBox="0 0 7 9"> <defs> <style> .cls-1 { diff --git a/catalog-ui/src/assets/styles/images/relationship-icons/arrow_connection_right.svg b/catalog-ui/src/assets/styles/images/relationship-icons/arrow_connection_right.svg index ea2d9f258d..bfb7be51d6 100644 --- a/catalog-ui/src/assets/styles/images/relationship-icons/arrow_connection_right.svg +++ b/catalog-ui/src/assets/styles/images/relationship-icons/arrow_connection_right.svg @@ -1,4 +1,4 @@ -<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid" width="7" height="9" viewBox="0 0 7 9"> +<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" width="7" height="9" viewBox="0 0 7 9"> <defs> <style> .cls-1 { diff --git a/catalog-ui/src/assets/styles/images/relationship-icons/conected.svg b/catalog-ui/src/assets/styles/images/relationship-icons/conected.svg index 4ee7672305..9f7a75b6f2 100644 --- a/catalog-ui/src/assets/styles/images/relationship-icons/conected.svg +++ b/catalog-ui/src/assets/styles/images/relationship-icons/conected.svg @@ -1,4 +1,4 @@ -<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid" width="25" height="25" viewBox="0 0 25 25"> +<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" width="25" height="25" viewBox="0 0 25 25"> <defs> <style> .cls-1 { diff --git a/catalog-ui/src/assets/styles/images/resource-icons/archive_big.png b/catalog-ui/src/assets/styles/images/resource-icons/archive_big.png Binary files differnew file mode 100644 index 0000000000..fd5ae3d08f --- /dev/null +++ b/catalog-ui/src/assets/styles/images/resource-icons/archive_big.png diff --git a/catalog-ui/src/assets/styles/images/resource-icons/archive_small.png b/catalog-ui/src/assets/styles/images/resource-icons/archive_small.png Binary files differnew file mode 100644 index 0000000000..207cc41e4b --- /dev/null +++ b/catalog-ui/src/assets/styles/images/resource-icons/archive_small.png diff --git a/catalog-ui/src/assets/styles/images/sprites/sprite-global.png b/catalog-ui/src/assets/styles/images/sprites/sprite-global.png Binary files differindex 2cf0bd7757..ca628a2a30 100644 --- a/catalog-ui/src/assets/styles/images/sprites/sprite-global.png +++ b/catalog-ui/src/assets/styles/images/sprites/sprite-global.png diff --git a/catalog-ui/src/assets/styles/images/sprites/sprite-global.png-orig b/catalog-ui/src/assets/styles/images/sprites/sprite-global.png-orig Binary files differnew file mode 100644 index 0000000000..51cfefab6f --- /dev/null +++ b/catalog-ui/src/assets/styles/images/sprites/sprite-global.png-orig diff --git a/catalog-ui/src/assets/styles/images/sprites/sprite-policy-groups-icons.png b/catalog-ui/src/assets/styles/images/sprites/sprite-policy-groups-icons.png Binary files differindex fe1723e2fa..57da9e285c 100644 --- a/catalog-ui/src/assets/styles/images/sprites/sprite-policy-groups-icons.png +++ b/catalog-ui/src/assets/styles/images/sprites/sprite-policy-groups-icons.png diff --git a/catalog-ui/src/assets/styles/images/sprites/sprite-resource-icons.png b/catalog-ui/src/assets/styles/images/sprites/sprite-resource-icons.png Binary files differindex 7f21e24223..dc63954694 100644 --- a/catalog-ui/src/assets/styles/images/sprites/sprite-resource-icons.png +++ b/catalog-ui/src/assets/styles/images/sprites/sprite-resource-icons.png diff --git a/catalog-ui/src/assets/styles/layout/main.less b/catalog-ui/src/assets/styles/layout/main.less index 2992b1d9d0..4dfeb8b46d 100644 --- a/catalog-ui/src/assets/styles/layout/main.less +++ b/catalog-ui/src/assets/styles/layout/main.less @@ -27,9 +27,22 @@ .sdc-tile { margin: 10px; .sdc-tile-content { + overflow: visible; + + .sdc-tile-content-icon { + width: 100%; + margin-top: -1em; + text-align: right; + } + .sdc-tile-content-info { .sdc-tile-info-line { display: inline-block; + + &.title { + line-height: 1.4em; + height: auto; + } } } } @@ -38,6 +51,13 @@ } } +.w-sdc-tile-multiline-ellipsis { + .multiline-ellipsis-dots { + background: linear-gradient(to right, transparent 0%, #ffffff 80%); + padding-left: 1em; + } +} + .w-sdc-row-flex-items { display: flex; flex-wrap: wrap; diff --git a/catalog-ui/src/assets/styles/mixins.less b/catalog-ui/src/assets/styles/mixins.less index b55d4fd794..e71f3444aa 100644 --- a/catalog-ui/src/assets/styles/mixins.less +++ b/catalog-ui/src/assets/styles/mixins.less @@ -219,3 +219,37 @@ -ms-user-select: text; user-select: text; } + + +.square-icon() { + display: inline-block; + background-color: @main_color_a; + padding: 0; + margin: 0; + margin-right: 7px; + width: 2em; + height: 2em; + border-radius: 1px; + + &::before { + display: block; + content: ""; + color: @main_color_p; + text-align: center; + line-height: 2em; + width: calc(100% - 2px); + height: calc(100% - 2px); + } + + &.small { + font-size: 14px; + } + + &.medium { + font-size: 20px; + } + + &.large { + font-size: 30px; + } +} diff --git a/catalog-ui/src/assets/styles/override.less b/catalog-ui/src/assets/styles/override.less new file mode 100644 index 0000000000..960be234f9 --- /dev/null +++ b/catalog-ui/src/assets/styles/override.less @@ -0,0 +1,72 @@ +@sdcui_color_white: #ffffff; +@sdcui_color_dark-blue: #0568ae; +@sdcui_color_blue: #009fdb; +@sdcui_color_light-blue: #1eb9f3; +@sdcui_color_blue-disabled: #9dd9ef; +@sdcui_color_lighter-blue: #e6f6fb; +@sdcui_color_black: #000000; +@sdcui_color_text-black: #191919; +@sdcui_color_rich-black: #323943; +@sdcui_color_dark-gray: #5a5a5a; +@sdcui_color_gray: #959595; +@sdcui_color_light-gray: #d2d2d2; +@sdcui_color_silver: #eaeaea; +@sdcui_color_light-silver: #f2f2f2; +@sdcui_color_lighter-silver: #f8f8f8; +@sdcui_color_green: #4ca90c; +@sdcui_color_red: #cf2a2a; +@sdcui_color_light-red: #ed4141; +@sdcui_color_disabled-red: #f4adad; +@sdcui_color_yellow: #ffb81c; +@sdcui_color_dark-purple: #702f8a; +@sdcui_color_purple: #9063cd; +@sdcui_color_light-purple: #caa2dd; + +/* override sdc-ui library tabs */ +body.composition { + + .sdc-tabs { + .sdc-tab { + background-color: @sdcui_color_white; + border: 1px solid @sdcui_color_silver; + border-left: none; + display: inline-block; + height: 36px; + text-align: center; + cursor: pointer; + padding: 2px 10px 0 10px; + margin: 0; + + + &:first-child { + border-left: 1px solid @sdcui_color_silver; + } + &.sdc-tab-active { + background-color: @sdcui_color_silver; + } + &[disabled] { + opacity: 0.3; + cursor: default; + } + } + &.sdc-tabs-header { + .sdc-tab { + font-size: 24px; + } + } + &.sdc-tabs-menu { + .sdc-tab { + font-size: 14px; + padding: 0px 10px 4px 10px; + } + } + .sdc-tab-content { + margin-top: 0; + } + } + +} +//override sdc-ui version 53 css, used by onboarding. This can be removed after we update past version 42 +sdc-modal { + position: static !important; +} diff --git a/catalog-ui/src/assets/styles/sprite-group-icons.less b/catalog-ui/src/assets/styles/sprite-group-icons.less index 47340adbb3..363f7a9d09 100644 --- a/catalog-ui/src/assets/styles/sprite-group-icons.less +++ b/catalog-ui/src/assets/styles/sprite-group-icons.less @@ -4,7 +4,7 @@ } .sprite-group-icons.disable { opacity:0.5;} -.sprite-group-icons.group { background-position: -43px -42px; width: 40px; height: 40px;} +.sprite-group-icons.group { background-position: -239px -43px; width: 40px; height: 40px;} .sprite-group-icons.group-border { background-position: -123px -36px; width: 55px; height: 55px;} sprite-group-icons.group-empty { background-position: -40px -274px; width: 47px; height: 47px;} diff --git a/catalog-ui/src/assets/styles/sprite-policy-icons.less b/catalog-ui/src/assets/styles/sprite-policy-icons.less index 154cf0b6a3..40f4f7e4e2 100644 --- a/catalog-ui/src/assets/styles/sprite-policy-icons.less +++ b/catalog-ui/src/assets/styles/sprite-policy-icons.less @@ -5,7 +5,7 @@ .sprite-policy-icons.disable { opacity:0.5;} -.sprite-policy-icons.policy { background-position: -42px -130px; width: 40px; height: 40px;} +.sprite-policy-icons.policy { background-position: -239px -130px; width: 40px; height: 40px;} .sprite-policy-icons.policy-border { background-position: -123px -123px; width: 55px; height: 55px;} .sprite-policy-icons.policy-empty { background-position: -40px -546px; width: 47px; height: 47px;} diff --git a/catalog-ui/src/assets/styles/sprite-resource-icons.less b/catalog-ui/src/assets/styles/sprite-resource-icons.less index 2f542d661c..0ada1c8711 100644 --- a/catalog-ui/src/assets/styles/sprite-resource-icons.less +++ b/catalog-ui/src/assets/styles/sprite-resource-icons.less @@ -96,7 +96,7 @@ .sprite-resource-icons.oracle.large { background-position: -70px -1229px; width: 60px; height: 60px;} .sprite-resource-icons.defaulticon { background-position: -282px -2069px; width: 60px; height: 60px;} -.sprite-resource-icons.defaulticon.small { background-position: -210px -2101px; width: 28px; height: 28px;} +.sprite-resource-icons.defaulticon.small { background-position: -211px -2101px; width: 28px; height: 28px;} .sprite-resource-icons.defaulticon.medium { background-position: -141px -2089px; width: 40px; height: 40px;} .sprite-resource-icons.defaulticon.large { background-position: -70px -2069px; width: 61px; height: 60px;} diff --git a/catalog-ui/src/assets/styles/sprite.less b/catalog-ui/src/assets/styles/sprite.less index aaf4f5529a..3e56a0163b 100644 --- a/catalog-ui/src/assets/styles/sprite.less +++ b/catalog-ui/src/assets/styles/sprite.less @@ -1,3 +1,5 @@ +@import "variables"; +@import '../../assets/styles/mixins'; .sprite-new { background-image: url('images/sprites/sprite-global.png'); display: inline-block; @@ -140,7 +142,7 @@ .Deployed { background-position: -573px -718px; width: 16px; height: 16px;} .error-icon { background-position: -51px -751px; width: 13px; height: 11px;} -.asdc-warning { background-position: -100px -748px; width: 17px; height: 15px;} +.asdc-warning, .sdc-warning { background-position: -100px -748px; width: 17px; height: 15px;} .link-btn { background-position: -636px -424px; width: 19px; height: 19px;} .link-btn:hover { background-position: -636px -453px; width: 19px; height: 19px;} @@ -291,3 +293,43 @@ .white-arrow-back{ background-position: -767px -918px; width: 23px; height: 23px;} .link-tooltip-arrow{background-position:-746px -961px; width: 20px; height: 14px;} + +.archive-btn { background-position: -110px -419px; width: 24px; height: 24px;} +.archive-btn:hover { background-position: -110px -447px; width: 24px; height: 24px;} + +.archive-component { + position:relative; + &::after { + content: ""; + display: block; + background: url('images/sprites/sprite-global.png') no-repeat -739px -1044px; + width: 61px; + height: 61px; + position: absolute; + top: 0; + left: 0; + } + &.active-component-static { + &::after { + position: static; + } + } +} + +.archive-label { background-position: -739px -1136px; width: 67px; height: 18px;} + +.icon-group { + .square-icon(); + + &::before { + content: "G"; + } +} +.icon-policy { + .square-icon(); + background-color: @main_color_b; + + &::before { + content: "P"; + } +}
\ No newline at end of file diff --git a/catalog-ui/src/assets/styles/svg/source/fit-all.svg b/catalog-ui/src/assets/styles/svg/source/fit-all.svg index dbea90963f..03834f8f17 100644 --- a/catalog-ui/src/assets/styles/svg/source/fit-all.svg +++ b/catalog-ui/src/assets/styles/svg/source/fit-all.svg @@ -1,5 +1,4 @@ <?xml version="1.0" encoding="utf-8"?> <svg xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - width="18px" height="19px" viewBox="0 0 18 19"> + width="18px" height="19px" viewBox="0 0 18 19"> <path fillRule="evenodd" d="M 17.94 18.86C 17.77 18.92 17.63 19 17.4 18.94 16.03 18.93 12.86 19 12.86 19 12.5 19 11.92 18.85 12 18 12.08 17.07 12.5 17 12.86 17 12.86 17 14.79 17 14.79 17 14.79 17 10.44 11.98 10.44 11.98 10.44 11.98 11.77 10.51 11.77 10.51 11.77 10.51 16.33 15.76 16.33 15.76 16.33 15.76 16.33 12.99 16.33 12.99 16.23 12.09 17.03 11.99 17.4 11.99 17.77 11.99 18.01 12.27 18.01 12.69 18.01 12.69 18.01 18.23 18.01 18.23 18.01 17.81 18 18.55 17.94 18.86ZM 17.33 7.36C 16.92 7.36 16.04 7.25 16.15 6.31 16.15 6.31 16.15 3.62 16.15 3.62 16.15 3.62 11.37 9 11.37 9 11.37 9 10.01 7.53 10.01 7.53 10.01 7.53 14.82 2.1 14.82 2.1 14.82 2.1 12.33 2.1 12.33 2.1 11.92 2.1 11.47 2.02 11.37 1.05 11.29 0.16 11.92-0 12.33-0 12.33-0 15.82 0.07 17.33 0.06 17.59 0 17.74 0.08 17.93 0.15 17.99 0.47 18 1.25 18 0.8 18 0.8 18 6.62 18 6.62 18 7.06 17.73 7.36 17.33 7.36ZM 5.67 16.9C 6.08 16.9 6.53 16.98 6.63 17.95 6.71 18.84 6.08 19 5.67 19 5.67 19 2.18 18.93 0.67 18.94 0.41 19 0.26 18.92 0.07 18.85 0.01 18.53-0 17.75-0 18.2-0 18.2-0 12.38-0 12.38-0 11.94 0.27 11.64 0.67 11.64 1.08 11.64 1.96 11.75 1.85 12.69 1.85 12.69 1.85 15.38 1.85 15.38 1.85 15.38 6.63 10 6.63 10 6.63 10 7.99 11.47 7.99 11.47 7.99 11.47 3.18 16.9 3.18 16.9 3.18 16.9 5.67 16.9 5.67 16.9ZM 6.63 9C 6.63 9 1.85 3.62 1.85 3.62 1.85 3.62 1.85 6.31 1.85 6.31 1.96 7.25 1.08 7.36 0.67 7.36 0.27 7.36-0 7.06-0 6.62-0 6.62-0 0.8-0 0.8-0 1.25 0.01 0.47 0.07 0.15 0.26 0.08 0.41 0 0.67 0.06 2.18 0.07 5.67-0 5.67-0 6.08-0 6.71 0.16 6.63 1.05 6.53 2.02 6.08 2.1 5.67 2.1 5.67 2.1 3.18 2.1 3.18 2.1 3.18 2.1 7.99 7.53 7.99 7.53 7.99 7.53 6.63 9 6.63 9Z" fill="rgb(89,89,89)"/></svg>
\ No newline at end of file diff --git a/catalog-ui/src/assets/styles/svg/source/minus.svg b/catalog-ui/src/assets/styles/svg/source/minus.svg index 4ced110098..7e204f19b6 100644 --- a/catalog-ui/src/assets/styles/svg/source/minus.svg +++ b/catalog-ui/src/assets/styles/svg/source/minus.svg @@ -1,5 +1,4 @@ <?xml version="1.0" encoding="utf-8"?> <svg xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - width="16px" height="2px" viewBox="0 0 16 2"> + width="16px" height="2px" viewBox="0 0 16 2"> <path fillRule="evenodd" d="M 1-0C 1-0 15-0 15-0 15.55-0 16 0.45 16 1 16 1.55 15.55 2 15 2 15 2 1 2 1 2 0.45 2 0 1.55 0 1 0 0.45 0.45-0 1-0Z" fill="rgb(99,99,99)"/></svg>
\ No newline at end of file diff --git a/catalog-ui/src/assets/styles/svg/source/plus.svg b/catalog-ui/src/assets/styles/svg/source/plus.svg index dff172c54d..34670eda20 100644 --- a/catalog-ui/src/assets/styles/svg/source/plus.svg +++ b/catalog-ui/src/assets/styles/svg/source/plus.svg @@ -1,5 +1,4 @@ <?xml version="1.0" encoding="utf-8"?> <svg xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - width="18px" height="18px" viewBox="0 0 18 18"> + width="18px" height="18px" viewBox="0 0 18 18"> <path fillRule="evenodd" d="M 17 10C 17 10 10 10 10 10 10 10 10 17 10 17 10 17.55 9.55 18 9 18 8.45 18 8 17.55 8 17 8 17 8 10 8 10 8 10 1 10 1 10 0.45 10 0 9.55 0 9 0 8.45 0.45 8 1 8 1 8 8 8 8 8 8 8 8 1 8 1 8 0.45 8.45 0 9 0 9.55 0 10 0.45 10 1 10 1 10 8 10 8 10 8 17 8 17 8 17.55 8 18 8.45 18 9 18 9.55 17.55 10 17 10Z" fill="rgb(99,99,99)"/></svg>
\ No newline at end of file diff --git a/catalog-ui/src/assets/styles/svg/source/search-magnify.svg b/catalog-ui/src/assets/styles/svg/source/search-magnify.svg index 279c13fd52..f5483a5087 100644 --- a/catalog-ui/src/assets/styles/svg/source/search-magnify.svg +++ b/catalog-ui/src/assets/styles/svg/source/search-magnify.svg @@ -1,5 +1,4 @@ <?xml version="1.0" encoding="utf-8"?> <svg xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - width="23px" height="26px" viewBox="0 0 23 26"> + width="23px" height="26px" viewBox="0 0 23 26"> <path fillRule="evenodd" d="M 17.53 4.53C 14.5 0.28 8.55-0.71 4.3 2.32 0.05 5.36-0.94 11.31 2.09 15.56 3.56 17.63 5.74 18.99 8.25 19.41 10.42 19.77 12.58 19.38 14.48 18.32 14.48 18.32 20.28 25.23 20.28 25.23 20.44 25.47 20.7 25.61 20.93 25.65 21.16 25.69 21.45 25.64 21.68 25.47 22.15 25.13 22.26 24.5 21.92 24.06 21.92 24.06 16.11 17.15 16.11 17.15 17.73 15.7 18.81 13.79 19.17 11.61 19.58 9.14 19.01 6.6 17.53 4.53ZM 3.76 14.4C 1.37 11.04 2.14 6.4 5.5 4 7.18 2.8 9.16 2.41 11.07 2.73 12.97 3.05 14.73 4.07 15.92 5.74 17.09 7.38 17.52 9.34 17.19 11.32 16.86 13.29 15.79 15 14.18 16.17 12.58 17.35 10.58 17.77 8.61 17.44 6.65 17.08 4.9 16.03 3.76 14.4Z" fill="rgb(99,99,99)"/></svg>
\ No newline at end of file diff --git a/catalog-ui/src/assets/styles/variables.less b/catalog-ui/src/assets/styles/variables.less index 163737466e..e800da9166 100644 --- a/catalog-ui/src/assets/styles/variables.less +++ b/catalog-ui/src/assets/styles/variables.less @@ -26,7 +26,9 @@ @main_color_o: #d2d2d2; @main_color_p: #ffffff; @main_color_q: #999999; - +@main_color_r: #162F90; +@main_color_s: #666666; +@main_color_t: #979797; /* Functional Colors */ @func_color_q: #cf2a2a; @func_color_r: #f2f2f2; diff --git a/catalog-ui/src/third-party/cytoscape.js-edge-editation/CytoscapeEdgeEditation.js b/catalog-ui/src/third-party/cytoscape.js-edge-editation/CytoscapeEdgeEditation.js index 0e6ca8b3c2..ca88b3d73f 100644 --- a/catalog-ui/src/third-party/cytoscape.js-edge-editation/CytoscapeEdgeEditation.js +++ b/catalog-ui/src/third-party/cytoscape.js-edge-editation/CytoscapeEdgeEditation.js @@ -123,110 +123,123 @@ exports.CytoscapeEdgeEditation = Class({ - init: function (cy, handleSize) { + init: function (cy) { this.DOUBLE_CLICK_INTERVAL = 300; - this.HANDLE_SIZE = handleSize ? handleSize : 5; + this.HANDLE_SIZE = 18; this.ARROW_END_ID = "ARROW_END_ID"; this._handles = {}; this._dragging = false; this._hover = null; - + this._tagMode = false; this._cy = cy; this._$container = $(cy.container()); - this._cy.on('mouseover tap', 'node', this._mouseOver.bind(this)); - this._cy.on('mouseout', 'node', this._mouseOut.bind(this)); - - this._$container.on('mouseout', function (e) { - if (this.permanentHandle) { - return; - } + this._$canvas = $('<canvas></canvas>'); + this._$canvas.css("top", 0); - this._clear(); - }.bind(this)); + this._ctx = this._$canvas[0].getContext('2d'); + this._$container.children("div").append(this._$canvas); - this._$container.on('mouseover', function (e) { - if (this._hover) { - this._mouseOver({cyTarget: this._hover}); - } - }.bind(this)); + this._resizeCanvas(); - this._cy.on("select", "node", this._redraw.bind(this)) + this.initContainerEvents(); - this._cy.on("mousedown", "node", function () { - this._nodeClicked = true; - }.bind(this)); + }, + initContainerEvents: function () { + this._cy.on("resize", this._resizeCanvas.bind(this)); + /*$(window).bind('resize', this._resizeCanvas.bind(this)); + $(window).bind('resize', this._resizeCanvas.bind(this));*/ - this._cy.on("mouseup", "node", function () { - this._nodeClicked = false; + this._$container.bind('resize', function () { + this._resizeCanvas(); }.bind(this)); - this._cy.on("remove", "node", function () { - this._hover = false; - this._clear(); - }.bind(this)); + this._cy.bind('zoom pan', this._redraw.bind(this)); - this._cy.on('showhandle', function (cy, target) { + this._cy.on('showhandle', function (cy, target, customHandle) { this.permanentHandle = true; - this._showHandles(target); + this._showHandles(target, customHandle); }.bind(this)); this._cy.on('hidehandles', this._hideHandles.bind(this)); - this._cy.bind('zoom pan', this._redraw.bind(this)); + this._$container.on('mouseout', function (e) { + if (this.permanentHandle) { + return; + } + + this._clear(); + }.bind(this)); - this._$canvas = $('<canvas></canvas>'); - this._$canvas.css("top", 0); + }, + initNodeEvents: function (){ + this._$canvas.on("mousedown", this._mouseDown.bind(this)); this._$canvas.on("mousemove", this._mouseMove.bind(this)); + this._$canvas.on('mouseup', this._mouseUp.bind(this)); - this._ctx = this._$canvas[0].getContext('2d'); - this._$container.children("div").append(this._$canvas); + this._cy.on('tapdragover', 'node', this._mouseOver.bind(this)); + this._cy.on('tapdragout', 'node', this._mouseOut.bind(this)); - $(window).bind('mouseup', this._mouseUp.bind(this)); + - /*$(window).bind('resize', this._resizeCanvas.bind(this)); - $(window).bind('resize', this._resizeCanvas.bind(this));*/ + //this._cy.on("select", "node", this._redraw.bind(this)) - this._cy.on("resize", this._resizeCanvas.bind(this)); + this._cy.on("mousedown", "node", function () { + if(!this._tagMode) { + this._nodeClicked = true; + } + }.bind(this)); - this._$container.bind('resize', function () { - this._resizeCanvas(); + this._cy.on("mouseup", "node", function () { + this._nodeClicked = false; }.bind(this)); - this._resizeCanvas(); + this._cy.on("remove", "node", function () { + this._hover = false; + this._clear(); + }.bind(this)); + // this._$container.on('mouseover', function (e) { + // if (this._hover) { + // this._mouseOver({cyTarget: this._hover}); + // } + // }.bind(this)); + this._cy.on('tagstart', function(){ + this._tagMode = true; + }.bind(this)); + + this._cy.on('tagend', function(){ + this._tagMode = false; + }.bind(this)) }, registerHandle: function (handle) { - if (handle.nodeTypeNames) { - for (var i in handle.nodeTypeNames) { - var nodeTypeName = handle.nodeTypeNames[i]; - this._handles[nodeTypeName] = this._handles[nodeTypeName] || []; - this._handles[nodeTypeName].push(handle); - } - } else { - this._handles["*"] = this._handles["*"] || []; - this._handles["*"].push(handle); + + if (handle.imageUrl) { + + var base_image = new Image(); + base_image.src = handle.imageUrl; + base_image.onload = function() { + handle.image = base_image; + }; } + + this._handles[handle.type] = this._handles[handle.type] || []; + this._handles[handle.type] = handle; - }, - _showHandles: function (target) { - var nodeTypeName = target.data().type; - if (nodeTypeName) { - var handles = this._handles[nodeTypeName] ? this._handles[nodeTypeName] : this._handles["*"]; + }, + _showHandles: function (target, handleType) { - for (var i in handles) { - if (handles[i].type != null) { - this._drawHandle(handles[i], target); - } - } + if(!handleType){ + handleType = 'add-edge'; //ie, CanvasHandleTypes.ADD_EDGE, which is the default } + this._drawHandle(this._handles[handleType], target); }, _clear: function () { @@ -237,24 +250,14 @@ }, _drawHandle: function (handle, target) { - var position = this._getHandlePosition(handle, target); + target.data().handleType = handle.type; + var position = this._getHandlePosition(target); var handleSize = this.HANDLE_SIZE * this._cy.zoom(); + this._ctx.clearRect(position.x, position.y, handleSize, handleSize); - this._ctx.beginPath(); - - if (handle.imageUrl) { - var base_image = new Image(); - base_image.src = handle.imageUrl; - this._ctx.drawImage(base_image, position.x, position.y, handleSize, handleSize); - } else { - this._ctx.arc(position.x, position.y, this.HANDLE_SIZE, 0, 2 * Math.PI, false); - this._ctx.fillStyle = handle.color; - this._ctx.strokeStyle = "white"; - this._ctx.lineWidth = 0; - this._ctx.fill(); - this._ctx.stroke(); + if (handle.image) { + this._ctx.drawImage(handle.image, position.x, position.y, handleSize, handleSize); } - }, _drawArrow: function (fromNode, toPosition, handle) { var toNode; @@ -322,7 +325,10 @@ }); }, _mouseDown: function (e) { - this._hit = this._hitTestHandles(e); + if(this._tagMode){ + return; + } + //this._hit = this._hitTestHandles(e); if (this._hit) { this._lastClick = Date.now(); @@ -330,18 +336,22 @@ this._hover = null; e.stopImmediatePropagation(); } + }, _hideHandles: function () { this.permanentHandle = false; this._clear(); - if(this._hover){ - this._showHandles(this._hover); - } }, - _mouseUp: function () { + _mouseUp: function (e) { if (this._hover) { - if (this._hit) { + if(this._tagMode){ + if(this._hitTestHandles(e)) + this._cy.trigger('handletagclick', { + nodeId: this._hover.data().id + }); + //this._hover = null; + } else if (this._hit && this._dragging) { //check if custom listener was passed, if so trigger it and do not add edge var listeners = this._cy._private.listeners; for (var i = 0; i < listeners.length; i++) { @@ -371,7 +381,7 @@ data: { source: this._dragging.id(), target: this._hover.id(), - type: this._hit.handle.type + type: "default" } }); this._initEdgeEvents(edge); @@ -387,22 +397,22 @@ _mouseMove: function (e) { if (this._hover) { if (!this._dragging) { - var hit = this._hitTestHandles(e); - if (hit) { + this._hit = this._hitTestHandles(e); + if (this._hit) { this._cy.trigger('handlemouseover', { node: this._hover }); $("body").css("cursor", "pointer"); - } else { this._cy.trigger('handlemouseout', { node: this._hover }); + if(!this._tagMode){ + this._showHandles(this._hover); + } $("body").css("cursor", "inherit"); } } - } else { - $("body").css("cursor", "inherit"); } if (this._dragging && this._hit.handle) { @@ -416,21 +426,24 @@ _mouseOver: function (e) { if (this._dragging) { - if ( (e.cyTarget.id() != this._dragging.id()) && e.cyTarget.data().allowConnection || this._hit.handle.allowLoop) { + if ( (e.cyTarget.id() != this._dragging.id()) && e.cyTarget.data().allowConnection) { this._hover = e.cyTarget; } } else { this._hover = e.cyTarget; - this._showHandles(this._hover); + if (!this._tagMode) { + this._showHandles(this._hover); + } } }, _mouseOut: function (e) { if(!this._dragging) { - if (this.permanentHandle) { - return; + if (!this.permanentHandle) { + this._clear(); } - - this._clear(); + this._cy.trigger('handlemouseout', { + node: this._hover + }); } this._hover = null; }, @@ -450,63 +463,26 @@ _hitTestHandles: function (e) { var mousePoisition = this._getRelativePosition(e); - if (this._hover) { - var nodeTypeName = this._hover.data().type; - if (nodeTypeName) { - var handles = this._handles[nodeTypeName] ? this._handles[nodeTypeName] : this._handles["*"]; - - for (var i in handles) { - var handle = handles[i]; - - var position = this._getHandlePosition(handle, this._hover); - var renderedHandleSize = this.HANDLE_SIZE * this._cy.zoom(); //actual number of pixels that handle uses. - if (VectorMath.distance(position, mousePoisition) < renderedHandleSize) { - return { - handle: handle, - position: position - }; - } - } + //if (this._hover) { + var position = this._getHandlePosition(this._hover); + var renderedHandleSize = this.HANDLE_SIZE * this._cy.zoom(); //actual number of pixels that handle uses. + if (VectorMath.distance(position, mousePoisition) < renderedHandleSize) { + var handleType = this._hover.data().handleType; + return { + handle: this._handles[handleType] + }; } - } + //} }, - _getHandlePosition: function (handle, target) { //returns the upper left point at which to begin drawing the handle + _getHandlePosition: function (target) { //returns the upper left point at which to begin drawing the handle var position = target.renderedPosition(); var width = target.renderedWidth(); var height = target.renderedHeight(); var renderedHandleSize = this.HANDLE_SIZE * this._cy.zoom(); //actual number of pixels that handle will use. - var xpos = null; - var ypos = null; - - switch (handle.positionX) { - case "left": - xpos = position.x - width / 2; - break; - case "right": //position.x is the exact center of the node. Need to add half the width to get to the right edge. Then, subtract renderedHandleSize to get handle position - xpos = position.x + width / 2 - renderedHandleSize; - break; - case "center": - xpos = position.x; - break; - } + var xpos = position.x + width / 2 - renderedHandleSize; + var ypos = position.y - height / 2; - switch (handle.positionY) { - case "top": - ypos = position.y - height / 2; - break; - case "center": - ypos = position.y; - break; - case "bottom": - ypos = position.y + height / 2; - break; - } - - //Determine if handle will be too big and require offset to prevent it from covering too much of the node icon (in which case, move it over by 1/2 the renderedHandleSize, so half the handle overlaps). - //Need to use target.width(), which is the size of the node, unrelated to rendered size/zoom - var offsetX = (target.width() < 30) ? renderedHandleSize / 2 : 0; - var offsetY = (target.height() < 30) ? renderedHandleSize /2 : 0; - return {x: xpos + offsetX, y: ypos - offsetY}; + return {x: xpos, y: ypos}; }, _getEdgeCSSByHandle: function (handle) { var color = handle.lineColor ? handle.lineColor : handle.color; @@ -517,17 +493,6 @@ "width": handle.width? handle.width : 3 }; }, - _getHandleByType: function (type) { - for (var i in this._handles) { - var byNodeType = this._handles[i]; - for (var i2 in byNodeType) { - var handle = byNodeType[i2]; - if (handle.type == type) { - return handle; - } - } - } - }, _getRelativePosition: function (e) { var containerPosition = this._$container.offset(); return { @@ -559,8 +524,8 @@ }, _redraw: function () { this._clear(); - if (this._hover) { - this._showHandles(this._hover); + if(this._tagMode) { + this._cy.trigger('canvasredraw'); } } }); diff --git a/catalog-ui/src/typings/angularjs/angular.d.ts b/catalog-ui/src/typings/angularjs/angular.d.ts index a5f56c0ccd..36d68e18a2 100644 --- a/catalog-ui/src/typings/angularjs/angular.d.ts +++ b/catalog-ui/src/typings/angularjs/angular.d.ts @@ -1305,7 +1305,6 @@ declare module angular { interface IHttpPromise<T> extends IPromise<IHttpPromiseCallbackArg<T>> { success(callback: IHttpPromiseCallback<T>): IHttpPromise<T>; error(callback: IHttpPromiseCallback<any>): IHttpPromise<T>; - then<TResult>(successCallback: (response: IHttpPromiseCallbackArg<T>) => IPromise<TResult>|TResult, errorCallback?: (response: IHttpPromiseCallbackArg<any>) => any): IPromise<TResult>; } /** |