diff options
author | Michael Lando <ml636r@att.com> | 2018-07-29 16:13:45 +0300 |
---|---|---|
committer | Michael Lando <ml636r@att.com> | 2018-07-29 16:20:34 +0300 |
commit | 5b593496b8f1b8e8be8d7d2dbcc223332e65a49b (patch) | |
tree | 2f9dfc45191e723da69cf74be7829784e9741b94 /catalog-ui/src/app/directives | |
parent | 9200382f2ce7b4bb729aa287d0878004b2d2b4f9 (diff) |
re base code
Change-Id: I12a5ca14a6d8a87e9316b9ff362eb131105f98a5
Issue-ID: SDC-1566
Signed-off-by: Michael Lando <ml636r@att.com>
Diffstat (limited to 'catalog-ui/src/app/directives')
24 files changed, 726 insertions, 597 deletions
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 |