Add support for directives on VFC 84/107984/6
authoraribeiro <anderson.ribeiro@est.tech>
Wed, 13 May 2020 12:49:31 +0000 (13:49 +0100)
committerOfir Sonsino <ofir.sonsino@intl.att.com>
Sun, 14 Jun 2020 14:49:56 +0000 (14:49 +0000)
This change also updates the directives values according to Tosca 1.3 spec

Issue-ID: SDC-3074
Change-Id: Ia6a68c9a23a71a2c17ba2c006990342811aa7b4e
Signed-off-by: aribeiro <anderson.ribeiro@est.tech>
23 files changed:
catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInstanceServlet.java
catalog-ui/src/app/models/componentsInstances/componentInstance.ts
catalog-ui/src/app/models/componentsInstances/fullComponentInstance.ts
catalog-ui/src/app/models/graph/nodes/composition-graph-nodes/composition-ci-node-vfc.ts
catalog-ui/src/app/models/graph/nodes/nodes-factory.ts
catalog-ui/src/app/ng2/components/logic/service-dependencies/directive-option.ts [new file with mode: 0644]
catalog-ui/src/app/ng2/components/logic/service-dependencies/service-dependencies.component.html
catalog-ui/src/app/ng2/components/logic/service-dependencies/service-dependencies.component.less
catalog-ui/src/app/ng2/components/logic/service-dependencies/service-dependencies.component.ts
catalog-ui/src/app/ng2/components/logic/service-dependencies/service-dependencies.module.ts
catalog-ui/src/app/ng2/components/ui/sdc-element-icon/sdc-element-icon.component.ts
catalog-ui/src/app/ng2/pages/composition/common/store/graph.state.ts
catalog-ui/src/app/ng2/pages/composition/graph/common/style/component-instances-nodes-style.ts
catalog-ui/src/app/ng2/pages/composition/graph/service-paths-list/service-paths-list.component.ts
catalog-ui/src/app/ng2/pages/composition/panel/__snapshots__/composition-panel.component.spec.ts.snap
catalog-ui/src/app/ng2/pages/composition/panel/composition-panel.component.html
catalog-ui/src/app/ng2/pages/composition/panel/composition-panel.component.less
catalog-ui/src/app/ng2/pages/composition/panel/composition-panel.component.ts
catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/panel-tabs.less
catalog-ui/src/app/ng2/services/component-services/topology-template.service.ts
catalog-ui/src/assets/languages/en_US.json
catalog-ui/src/assets/styles/images/resource-icons/dependent.png [new file with mode: 0644]
catalog-ui/src/assets/styles/images/resource-icons/uncertified_dependent.png [new file with mode: 0644]

index d8580e8..d9a890d 100644 (file)
@@ -38,6 +38,7 @@ import io.swagger.v3.oas.annotations.servers.Server;
 import io.swagger.v3.oas.annotations.servers.Servers;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import io.swagger.v3.oas.annotations.tags.Tags;
+import org.apache.commons.collections.CollectionUtils;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.reflect.Type;
index d3a99e5..e311589 100644 (file)
@@ -34,6 +34,7 @@ import {
 import {ResourceType, ComponentType} from "../../utils/constants";
 import {Capability} from "../capability";
 import {Requirement} from "../requirement";
+import {DirectivesEnum} from "../../ng2/components/logic/service-dependencies/directive-option";
 
 export interface IComponentInstance {
 
@@ -104,10 +105,6 @@ export class ComponentInstance implements IComponentInstance{
     public originArchived:boolean;
     public directives: string[];
 
-    DIRECTIVES_TYPES = {
-        SELECTABLE: 'selectable'
-    };
-
     constructor(componentInstance?:ComponentInstance) {
 
         if (componentInstance) {
@@ -161,6 +158,10 @@ export class ComponentInstance implements IComponentInstance{
         return this.originType === ComponentType.SERVICE_PROXY;
     }
 
+    public isVFC = ():boolean => {
+        return this.originType === ResourceType.VFC;
+    }
+
     public getComponentUid = ():string => {
         return this.isServiceProxy()? this.sourceModelUid : this.componentUid;
     }
@@ -229,17 +230,23 @@ export class ComponentInstance implements IComponentInstance{
         return this.iconSprite + ' ' + this.icon;
     }
     public isDependent = () : boolean => {
-        return this.directives && this.directives.indexOf(this.DIRECTIVES_TYPES.SELECTABLE) !== -1;
+       return Array.isArray(this.directives) && this.directives.length > 0;
+    }
+
+    public markAsSelect = () : void => {
+        this.directives.push(DirectivesEnum.SELECT);
     }
 
-    public markAsDependent = () : void => {
-        this.directives.push(this.DIRECTIVES_TYPES.SELECTABLE);
+    public markAsSubstitute = () : void => {
+        this.directives.push(DirectivesEnum.SUBSTITUTE);
     }
 
-    public unmarkAsDependent = () : void => {
-        let index = this.directives.indexOf(this.DIRECTIVES_TYPES.SELECTABLE);
+    public unmarkAsDependent = (actualDirectiveValue: string) : void => {
+        console.info("[START] this.directives: ", this.directives)
+        let index = this.directives.indexOf(actualDirectiveValue);
         if(index >= 0) {
             this.directives.splice(index, 1);
         }
+        console.info("[STOP] this.directives: ", this.directives)
     }
 }
index ce5aa1d..ab9015d 100644 (file)
@@ -25,10 +25,6 @@ export class FullComponentInstance extends ComponentInstance {
     public isResourceInstance: boolean;
     public directives: string[];
 
-    DIRECTIVES_TYPES = {
-        SELECTABLE: 'selectable'
-    };
-
     //service
     public serviceApiArtifacts:ArtifactGroupModel;
     public serviceType:string;
@@ -92,19 +88,5 @@ export class FullComponentInstance extends ComponentInstance {
     public isService = ():boolean => {
         return this.isServiceInstance;
     }
-    public isDependent = () : boolean => {
-        return this.directives && this.directives.indexOf(this.DIRECTIVES_TYPES.SELECTABLE) !== -1;
-    }
-
-    public markAsDependent = () : void => {
-        this.directives.push(this.DIRECTIVES_TYPES.SELECTABLE);
-    }
-
-    public unmarkAsDependent = () : void => {
-        const index = this.directives.indexOf(this.DIRECTIVES_TYPES.SELECTABLE);
-        if(index >= 0) {
-            this.directives.splice(index, 1);
-        }
-    }
 
 }
\ No newline at end of file
index 4c16661..ce95486 100644 (file)
  * limitations under the License.
  * ============LICENSE_END=========================================================
  */
-import {CompositionCiNodeBase} from "./composition-ci-node-base";
+import {ImagesUrl, GraphUIObjects} from "../../../../utils/constants";
+import {ComponentInstance, CompositionCiNodeBase} from "../../../../models";
 import {ImageCreatorService} from "app/ng2/pages/composition/graph/common/image-creator.service";
-import {ComponentInstance} from "../../../componentsInstances/componentInstance";
-import {ImagesUrl} from "../../../../utils/constants";
 
 export class CompositionCiNodeVfc extends CompositionCiNodeBase {
-    constructor(instance:ComponentInstance, imageCreator:ImageCreatorService) {
-        super(instance, imageCreator);
-        this.initVfc();
-    }
+  private isDependent: boolean;
+  private originalImg: string;
+
+  constructor(instance: ComponentInstance, imageCreator: ImageCreatorService) {
+    super(instance, imageCreator);
+    this.isDependent = instance.isDependent();
+    this.initVfc();
+  }
 
-    private initVfc():void {
-        this.imagesPath = this.imagesPath + ImagesUrl.RESOURCE_ICONS;
-        this.img = this.imagesPath + this.componentInstance.icon + '.png';
+  private initVfc(): void {
+    this.imagesPath = this.imagesPath + ImagesUrl.RESOURCE_ICONS;
+    this.img = this.imagesPath + this.componentInstance.icon + '.png';
+    this.originalImg = this.img;
+    this.imgWidth = GraphUIObjects.DEFAULT_RESOURCE_WIDTH;
+    this.classes = 'vfc-node';
+    if (this.archived) {
+      this.classes = this.classes + ' archived';
+      return;
+    }
+    if (this.isDependent) {
+      this.classes += ' dependent';
+    }
+    if (!this.certified) {
+      this.classes = this.classes + ' not-certified';
     }
+  }
+
+  public initUncertifiedDependentImage(node:Cy.Collection, nodeMinSize:number):string {
+    return this.enhanceImage(node, nodeMinSize, this.imagesPath + 'uncertified_dependent.png');
+  }
+
+  public initDependentImage(node:Cy.Collection, nodeMinSize:number):string {
+    return this.enhanceImage(node, nodeMinSize, this.imagesPath + 'dependent.png');
+  }
+
 }
index bcd2f7e..fbcd479 100644 (file)
  */
 'use strict';
 
-import {CompositionCiNodeUcpeCp, Module, ModuleNodeBase, CompositionCiNodeVf, CompositionCiNodeVl, CompositionCiNodeCp, CompositionCiNodeConfiguration,
-    NodeUcpe, CompositionCiNodeService,CompositionCiNodeServiceProxy, CompositionCiNodeBase, ComponentInstance} from "./../../../models";
+import {
+    CompositionCiNodeUcpeCp,
+    Module,
+    ModuleNodeBase,
+    CompositionCiNodeVf,
+    CompositionCiNodeVl,
+    CompositionCiNodeCp,
+    CompositionCiNodeConfiguration,
+    NodeUcpe,
+    CompositionCiNodeService,
+    CompositionCiNodeServiceProxy,
+    CompositionCiNodeBase,
+    ComponentInstance,
+    CompositionCiNodeVfc
+} from "./../../../models";
 import {ComponentType, ResourceType} from "../../../utils/constants";
 import {ImageCreatorService} from "app/ng2/pages/composition/graph/common/image-creator.service";
 import {Injectable} from "@angular/core";
@@ -42,6 +55,9 @@ export class NodesFactory {
         if (instance.originType === ComponentType.SERVICE_PROXY) {
             return new CompositionCiNodeServiceProxy(instance, this.imageCreator);
         }
+        if (instance.originType == ResourceType.VFC) {
+            return new CompositionCiNodeVfc(instance, this.imageCreator);
+        }
         if (instance.originType === ResourceType.CP) {
             return new CompositionCiNodeCp(instance, this.imageCreator);
         }
diff --git a/catalog-ui/src/app/ng2/components/logic/service-dependencies/directive-option.ts b/catalog-ui/src/app/ng2/components/logic/service-dependencies/directive-option.ts
new file mode 100644 (file)
index 0000000..f2c4b1f
--- /dev/null
@@ -0,0 +1,15 @@
+export enum DirectivesEnum {
+    SELECT = 'select',
+    SELECTABLE = 'selectable',
+    SUBSTITUTE = 'substitute',
+    SUBSTITUTABLE = 'substitutable',
+}
+
+export namespace DirectiveValue {
+
+  export function values() {
+    return Object.keys(DirectivesEnum).filter(
+        (type) => isNaN(<any>type) && type !== 'values'
+    );
+  }
+}
index d71a4fb..833f6f3 100644 (file)
@@ -1,35 +1,44 @@
 <div class="service-dependencies">
-    <loader [display]="isLoading" [size]="'medium'" [relative]="true"></loader>
-    <div class="checkbox-label-mark-as-dependent">
-            <checkbox
-                    class="checkbox-label"
-                    data-tests-id="checkbox-mark-as-dependent"
-                    [label]="'Mark as Dependent'"
-                    (checkedChange)="onMarkAsDependent()"
-                    [(checked)]="isDependent"
-                    [disabled]="readonly">
-            </checkbox>
-    </div>
-    <div class="i-sdc-designer-sidebar-section-content-item-rules-section" *ngIf="isDependent">
+  <loader [display]="isLoading" [size]="'medium'" [relative]="true"></loader>
+  <div *ngIf="!isDependent"  class="checkbox-label-mark-as-dependent">
+    <select name="singleSelect" id="singleSelect" ng-model="data.singleSelect"
+            (change)='onOptionsSelected($event)'>
+      <option>Select Directive</option>
+      <option *ngFor="let item of directiveValues.values()">{{item}}</option>
+    </select>
+  </div>
 
-        <div class="i-sdc-designer-sidebar-section-content-item-rule" [ngClass]="{'hand': !readonly}"
-             *ngFor="let rule of rulesList; let i = index">
-            <div class="rule-details" [ngClass]="{'readonly': readonly}">
-                <div class="rule-desc" (click)="!readonly && onSelectRule(i)" tooltips tooltip="{{rule.servicePropertyName + ' ' + getSymbol(rule.constraintOperator) + ' ' + (rule.sourceName ? rule.sourceName + ':' : '') + rule.value}}">
-                    {{rule.servicePropertyName + ' ' + getSymbol(rule.constraintOperator) + ' ' + (rule.sourceName ? rule.sourceName + ':' : '') + rule.value}}
-                </div>
-                <span *ngIf="!readonly" class="sprite-new delete-btn delete-icon" (click)="openDeleteModal(i)" data-tests-id="delete-input-button"></span>
-            </div>
-        </div>
+  <div *ngIf="isDependent" class="checkbox-label-mark-as-dependent">
+    <label class="i-sdc-form-label">Directive: {{getActualDirectiveValue().toUpperCase()}}</label>
+    <span class="sprite-new delete-btn delete-icon"
+         (click)="onRemoveDirective()" data-tests-id="delete-input-button">
+    </span>
+  </div>
+
+  <div class="i-sdc-designer-sidebar-section-content-item-rules-section" *ngIf="isDependent && isServiceProxy()">
 
-        <div class="w-sdc-designer-sidebar-section-footer" >
-            <button
-                    class="w-sdc-designer-sidebar-section-footer-action add-rule-btn tlv-btn blue"
-                    data-tests-id="add-rule-button"
-                    (click)="onAddRule()"
-                    [disabled]="readonly">
-                {{'SERVICE_DEPENDENCY_ADD_RULE' | translate}}
-            </button>
+    <div class="i-sdc-designer-sidebar-section-content-item-rule" [ngClass]="{'hand': !readonly}"
+         *ngFor="let rule of rulesList; let i = index">
+      <div class="rule-details" [ngClass]="{'readonly': readonly}">
+        <div class="rule-desc" (click)="!readonly && onSelectRule(i)" tooltips
+             tooltip="{{rule.servicePropertyName + ' ' + getSymbol(rule.constraintOperator) + ' '
+             + (rule.sourceName ? rule.sourceName + ':' : '') + rule.value}}">
+          {{rule.servicePropertyName + ' ' + getSymbol(rule.constraintOperator) + ' '
+        + (rule.sourceName ? rule.sourceName + ':' : '') + rule.value}}
         </div>
+        <span *ngIf="!readonly" class="sprite-new delete-btn delete-icon"
+              (click)="openDeleteModal(i)" data-tests-id="delete-input-button"></span>
+      </div>
+    </div>
+
+    <div class="w-sdc-designer-sidebar-section-footer">
+      <button
+          class="w-sdc-designer-sidebar-section-footer-action add-rule-btn tlv-btn blue"
+          data-tests-id="add-rule-button"
+          (click)="onAddRule()"
+          [disabled]="readonly">
+        {{'DIRECTIVES_AND_NODE_FILTER_ADD_NODE_FILTER' | translate}}
+      </button>
     </div>
+  </div>
 </div>
\ No newline at end of file
index 2fccfb4..21c2b3a 100644 (file)
     .checkbox-container input[type=checkbox].checkbox-hidden[disabled] ~ .checkbox-label-content {
       opacity: 0.5;
     }
+    .delete-btn {
+      background-position: -137px -415px;
+      width: 24px;
+      height: 24px
+    }
 
     loader {
       top: 20px;
     }
   }
 
+
   .i-sdc-designer-sidebar-section-content-item-rules-section {
     .i-sdc-designer-sidebar-section-content-item-rule {
       border-bottom: 1px solid @main_color_o;
index fa75a27..f3fd363 100644 (file)
@@ -29,6 +29,7 @@ import { TranslateService } from 'app/ng2/shared/translator/translate.service';
 import { ComponentMetadata } from '../../../../models/component-metadata';
 import { ServiceInstanceObject } from '../../../../models/service-instance-properties-and-interfaces';
 import { TopologyTemplateService } from '../../../services/component-services/topology-template.service';
+import {DirectivesEnum, DirectiveValue} from "./directive-option";
 
 export class ConstraintObject {
     servicePropertyName: string;
@@ -78,30 +79,34 @@ export const OPERATOR_TYPES = {
 
 // tslint:disable-next-line:max-classes-per-file
 class I18nTexts {
-    static uncheckModalTitle: string;
-    static uncheckModalText: string;
+    static removeDirectiveModalTitle: string;
+    static removeDirectiveModalText: string;
+    static updateDirectiveModalTitle: string;
+    static updateDirectiveModalText: string;
     static modalApprove: string;
     static modalCancel: string;
     static modalCreate: string;
     static modalSave: string;
     static modalDelete: string;
-    static addRuleTxt: string;
-    static updateRuleTxt: string;
-    static deleteRuleTxt: string;
-    static deleteRuleMsg: string;
+    static addNodeFilterTxt: string;
+    static updateNodeFilterTxt: string;
+    static deleteNodeFilterTxt: string;
+    static deleteNodeFilterMsg: string;
 
     public static translateTexts(translateService) {
-            I18nTexts.uncheckModalTitle = translateService.translate('SERVICE_DEPENDENCY_UNCHECK_TITLE');
-            I18nTexts.uncheckModalText = translateService.translate('SERVICE_DEPENDENCY_UNCHECK_TEXT');
+            I18nTexts.removeDirectiveModalTitle = translateService.translate('DIRECTIVES_AND_NODE_FILTER_REMOVE_TITLE');
+            I18nTexts.removeDirectiveModalText = translateService.translate('DIRECTIVES_AND_NODE_FILTER_REMOVE_TEXT');
+            I18nTexts.updateDirectiveModalTitle = translateService.translate('DIRECTIVES_AND_NODE_FILTER_UPDATE_TITLE');
+            I18nTexts.updateDirectiveModalText = translateService.translate('DIRECTIVES_AND_NODE_FILTER_UPDATE_TEXT');
             I18nTexts.modalApprove = translateService.translate('MODAL_APPROVE');
             I18nTexts.modalCancel = translateService.translate('MODAL_CANCEL');
             I18nTexts.modalCreate = translateService.translate('MODAL_CREATE');
             I18nTexts.modalSave = translateService.translate('MODAL_SAVE');
             I18nTexts.modalDelete = translateService.translate('MODAL_DELETE');
-            I18nTexts.addRuleTxt = translateService.translate('SERVICE_DEPENDENCY_ADD_RULE');
-            I18nTexts.updateRuleTxt = translateService.translate('SERVICE_DEPENDENCY_UPDATE_RULE');
-            I18nTexts.deleteRuleTxt = translateService.translate('SERVICE_DEPENDENCY_DELETE_RULE');
-            I18nTexts.deleteRuleMsg = translateService.translate('SERVICE_DEPENDENCY_DELETE_RULE_MSG');
+            I18nTexts.addNodeFilterTxt = translateService.translate('DIRECTIVES_AND_NODE_FILTER_ADD_NODE_FILTER');
+            I18nTexts.updateNodeFilterTxt = translateService.translate('DIRECTIVES_AND_NODE_FILTER_UPDATE_NODE_FILTER');
+            I18nTexts.deleteNodeFilterTxt = translateService.translate('DIRECTIVES_AND_NODE_FILTER_DELETE_NODE_FILTER');
+            I18nTexts.deleteNodeFilterMsg = translateService.translate('DIRECTIVES_AND_NODE_FILTER_DELETE_NODE_FILTER_MSG');
     }
 }
 
@@ -127,6 +132,7 @@ export class ServiceDependenciesComponent {
     @Input() selectedInstanceSiblings: ServiceInstanceObject[];
     @Input() selectedInstanceConstraints: ConstraintObject[] = [];
     @Input() selectedInstanceProperties: PropertyBEModel[] = [];
+    @Input() directiveValues: any = DirectiveValue;
     @Output() updateRulesListEvent: EventEmitter<ConstraintObject[]> = new EventEmitter<ConstraintObject[]>();
     @Output() loadRulesListEvent:EventEmitter<any> = new EventEmitter();
     @Output() dependencyStatus = new EventEmitter<boolean>();
@@ -161,10 +167,27 @@ export class ServiceDependenciesComponent {
         }
     }
 
+    private getActualDirectiveValue = (): string => {
+        return this.currentServiceInstance.directives.length > 0 ? this.currentServiceInstance.directives[0] : "";
+    }
+
+    private isServiceProxy = (): boolean => {
+        return this.currentServiceInstance.isServiceProxy();
+    }
+
     public openRemoveDependencyModal = (): ComponentRef<ModalComponent> => {
         const actionButton: ButtonModel = new ButtonModel(I18nTexts.modalApprove, 'blue', this.onUncheckDependency);
         const cancelButton: ButtonModel = new ButtonModel(I18nTexts.modalCancel, 'grey', this.onCloseRemoveDependencyModal);
-        const modalModel: ModalModel = new ModalModel('sm', I18nTexts.uncheckModalTitle, I18nTexts.uncheckModalText, [actionButton, cancelButton]);
+        const modalModel: ModalModel = new ModalModel('sm', I18nTexts.removeDirectiveModalTitle,
+            I18nTexts.removeDirectiveModalText, [actionButton, cancelButton]);
+        return this.modalServiceNg2.createCustomModal(modalModel);
+    }
+
+    public openUpdateDependencyModal = (): ComponentRef<ModalComponent> => {
+        const actionButton: ButtonModel = new ButtonModel(I18nTexts.modalApprove, 'blue', this.onUncheckDependency);
+        const cancelButton: ButtonModel = new ButtonModel(I18nTexts.modalCancel, 'grey', this.onCloseRemoveDependencyModal);
+        const modalModel: ModalModel = new ModalModel('sm', I18nTexts.updateDirectiveModalTitle,
+            I18nTexts.updateDirectiveModalText, [actionButton, cancelButton]);
         return this.modalServiceNg2.createCustomModal(modalModel);
     }
 
@@ -183,7 +206,7 @@ export class ServiceDependenciesComponent {
         this.isLoading = true;
         const isDepOrig = this.isDependent;
         const rulesListOrig = this.rulesList;
-        this.currentServiceInstance.unmarkAsDependent();
+        this.currentServiceInstance.unmarkAsDependent(this.getActualDirectiveValue());
         this.updateComponentInstance(isDepOrig, rulesListOrig);
     }
 
@@ -192,25 +215,39 @@ export class ServiceDependenciesComponent {
         this.modalServiceNg2.closeCurrentModal();
     }
 
-    onCheckDependency = () => {
-        const isDepOrig = this.isDependent;
-        const rulesListOrig = this.rulesList;
-        this.currentServiceInstance.markAsDependent();
+    onOptionsSelected(event: any) {
+        const newDirectiveValue = event.target.value;
+        if (newDirectiveValue.toLowerCase() !== this.getActualDirectiveValue()) {
+            const rulesListOrig = this.rulesList;
+            this.setDirectiveValue(newDirectiveValue);
+            this.rulesList = [];
+            this.updateComponentInstance(this.isDependent, rulesListOrig);
+        }
+    }
+
+    private onRemoveDirective() {
+        this.openRemoveDependencyModal().instance.open();
         this.rulesList = [];
-        this.updateComponentInstance(isDepOrig, rulesListOrig);
     }
 
-    onMarkAsDependent() {
-        if (!this.currentServiceInstance.isDependent()) {
-            this.onCheckDependency();
+    private setDirectiveValue(newDirectiveValue: string) {
+        if (this.isDependent) {
+            this.openUpdateDependencyModal().instance.open();
+        }
+        if (DirectivesEnum.SELECT == newDirectiveValue.toLowerCase() ||
+            DirectivesEnum.SELECTABLE == newDirectiveValue.toLowerCase()) {
+            this.currentServiceInstance.markAsSelect();
         } else {
-            this.openRemoveDependencyModal().instance.open();
+            this.currentServiceInstance.markAsSubstitute();
         }
     }
 
     updateComponentInstance(isDependentOrigVal: boolean, rulesListOrig: ConstraintObject[]) {
         this.isLoading = true;
-        this.topologyTemplateService.updateComponentInstance(this.compositeService.uniqueId, this.currentServiceInstance).subscribe((updatedServiceIns: ComponentInstance) => {
+        this.topologyTemplateService.updateComponentInstance(this.compositeService.uniqueId,
+                                                             this.compositeService.componentType,
+                                                             this.currentServiceInstance)
+                                                             .subscribe((updatedServiceIns: ComponentInstance) => {
             this.currentServiceInstance = new ComponentInstance(updatedServiceIns);
             this.isDependent = this.currentServiceInstance.isDependent();
             this.dependencyStatus.emit(this.isDependent);
@@ -229,7 +266,7 @@ export class ServiceDependenciesComponent {
     onAddRule() {
         const cancelButton: ButtonModel = new ButtonModel(I18nTexts.modalCancel, 'outline white', this.modalServiceNg2.closeCurrentModal);
         const saveButton: ButtonModel = new ButtonModel(I18nTexts.modalCreate, 'blue', this.createRule, this.getDisabled);
-        const modalModel: ModalModel = new ModalModel('l', I18nTexts.addRuleTxt, '', [saveButton, cancelButton], 'standard');
+        const modalModel: ModalModel = new ModalModel('l', I18nTexts.addNodeFilterTxt, '', [saveButton, cancelButton], 'standard');
         this.modalInstance = this.modalServiceNg2.createCustomModal(modalModel);
         this.modalServiceNg2.addDynamicContentToModal(
             this.modalInstance,
@@ -249,7 +286,7 @@ export class ServiceDependenciesComponent {
     onSelectRule(index: number) {
         const cancelButton: ButtonModel = new ButtonModel(I18nTexts.modalCancel, 'outline white', this.modalServiceNg2.closeCurrentModal);
         const saveButton: ButtonModel = new ButtonModel(I18nTexts.modalSave, 'blue', () => this.updateRules(), this.getDisabled);
-        const modalModel: ModalModel = new ModalModel('l', I18nTexts.updateRuleTxt, '', [saveButton, cancelButton], 'standard');
+        const modalModel: ModalModel = new ModalModel('l', I18nTexts.updateNodeFilterTxt, '', [saveButton, cancelButton], 'standard');
         this.modalInstance = this.modalServiceNg2.createCustomModal(modalModel);
         this.modalServiceNg2.addDynamicContentToModal(
             this.modalInstance,
@@ -328,7 +365,8 @@ export class ServiceDependenciesComponent {
     }
 
     openDeleteModal = (index: number) => {
-        this.modalServiceNg2.createActionModal(I18nTexts.deleteRuleTxt, I18nTexts.deleteRuleMsg,
+        this.modalServiceNg2.createActionModal(I18nTexts.deleteNodeFilterTxt, I18nTexts.deleteNodeFilterMsg,
             I18nTexts.modalDelete, () => this.onDeleteRule(index), I18nTexts.modalCancel).instance.open();
     }
+
 }
index baadbd8..dd48af2 100644 (file)
@@ -51,6 +51,7 @@ export class SdcElementIconComponent {
             case SdcElementType.POLICY:
                 this.elementIcon = new ElementIcon("policy", "resources_24", "darkBlue2", 'white', 'rectangle');
                 break;
+            case ResourceType.VFC:
             case ResourceType.CP:
             case ResourceType.VL:
                 this.elementIcon = new ElementIcon(this.iconName, "resources_24", "purple", '', '', 'medium');
index d58bb44..7c352a6 100644 (file)
@@ -39,7 +39,7 @@ export class GraphState {
     setSelectedComponent({dispatch, getState, patchState}:StateContext<CompositionStateModel>, action: SetSelectedComponentAction) {
         
         const state:CompositionStateModel = getState();
-        
+
         patchState({ panelLoading: true });
 
         if(action.payload.component instanceof ComponentInstance){
index cc9cac1..4a975da 100644 (file)
@@ -134,6 +134,21 @@ export class ComponentInstanceNodesStyle {
                     'overlay-opacity': 0
                 }
             },
+            {
+                selector: '.vfc-node',
+                css: {
+                    'background-color': 'transparent',
+                    'label': 'data(displayName)',
+                    'background-image': 'data(img)',
+                    'width': 64,
+                    'height': 64,
+                    'text-valign': 'bottom',
+                    'text-halign': 'center',
+                    'background-opacity': 0,
+                    'overlay-color': GraphColors.NODE_BACKGROUND_COLOR,
+                    'overlay-opacity': 0
+                }
+            },
             {
                 selector: '.ucpe-cp',
                 css: {
index 81abe42..fc31cd9 100644 (file)
@@ -55,7 +55,7 @@ export class ServicePathsListComponent {
         });
         this.onAddServicePath = this.input.onCreateServicePath;
         this.onEditServicePath = this.input.onEditServicePath;
-        this.isViewOnly =  this.input.isViewOnly;
+        this.isViewOnly = this.input.isViewOnly;
     }
 
     deletePath = (id:string):void =>   {
index 5f10806..fdede9d 100644 (file)
@@ -9,6 +9,7 @@ exports[`composition-panel component should match current snapshot of compositio
   isConfiguration={[Function Function]}
   isPNF={[Function Function]}
   selectedComponentIsServiceProxyInstance={[Function Function]}
+  selectedComponentIsVfcInstance={[Function Function]}
   setActive={[Function Function]}
   store={[Function Store]}
   toggleSidebarDisplay={[Function Function]}
index bd90b9a..5511dc0 100644 (file)
@@ -1,17 +1,26 @@
 <panel-wrapper-component *ngIf="compositionState$ | async as state">   <!-- HEADER -->
 
-    <ng2-composition-panel-header [isViewOnly]="state.isViewOnly"
-                                    [selectedComponent]="state.selectedComponent"></ng2-composition-panel-header>
+    <ng2-composition-panel-header
+        [isViewOnly]="state.isViewOnly"
+        [selectedComponent]="state.selectedComponent">
+    </ng2-composition-panel-header>
 
     <!-- TABS -->
     <div class="component-details-panel-tabs">
         <sdc-loader [global]="false" name="panel" testId="panel-loader" [active]="state.panelLoading"></sdc-loader>
         <sdc-tabs (selectedTab)="setActive($event)" [iconsSize]="'large'">
-            <sdc-tab *ngFor="let tab of tabs" [titleIcon]="tab.titleIcon" [active]="tab.isActive"
-                        [tooltipText]="tab.tooltipText">
-                <panel-tab [isActive]="tab.isActive" [component]="selectedComponent"
-                            [componentType]="state.selectedComponentType" [isViewOnly]="isViewOnly$ | async"
-                            [input]="tab.input" [panelTabType]="tab.component"></panel-tab>
+            <sdc-tab *ngFor="let tab of tabs"
+                     [titleIcon]="tab.titleIcon"
+                     [active]="tab.isActive"
+                     [tooltipText]="tab.tooltipText">
+
+                <panel-tab [isActive]="tab.isActive"
+                           [component]="selectedComponent"
+                           [componentType]="state.selectedComponentType"
+                           [isViewOnly]="isViewOnly$ | async"
+                           [input]="tab.input"
+                           [panelTabType]="tab.component">
+                </panel-tab>
             </sdc-tab>
         </sdc-tabs>
     </div>
index 776ef68..124d606 100644 (file)
@@ -14,6 +14,7 @@
 .component-details-panel-tabs /deep/ sdc-tabs {
     display:flex;
     flex-direction:column;
+    width: 100%;
 
     /deep/ sdc-tab {
         display: flex;
index c5ea41b..348dc9f 100644 (file)
@@ -53,7 +53,7 @@ const tabs = {
     inputs: {titleIcon: 'inputs-o', component: PropertiesTabComponent, input: {title: 'Inputs'}, isActive: false, tooltipText: 'Inputs'},
     settings: {titleIcon: 'settings-o', component: PropertiesTabComponent, input: {}, isActive: false, tooltipText: 'Settings'},
     consumption: {titleIcon: 'api-o', component: ServiceConsumptionTabComponent, input: {title: 'OPERATION CONSUMPTION'}, isActive: false, tooltipText: 'Service Consumption'},
-    dependencies: {titleIcon: 'archive', component: ServiceDependenciesTabComponent, input: {title: 'SERVICE DEPENDENCIES'}, isActive: false, tooltipText: 'Service Dependencies'}
+    dependencies: {titleIcon: 'archive', component: ServiceDependenciesTabComponent, input: {title: 'DIRECTIVES AND NODE FILTER'}, isActive: false, tooltipText: 'Service Dependencies'}
 };
 
 @Component({
@@ -144,6 +144,8 @@ export class CompositionPanelComponent {
         if (component.isService() && this.selectedComponentIsServiceProxyInstance()) {
             this.tabs.push(tabs.consumption);
             this.tabs.push(tabs.dependencies);
+        } else if (component.isResource() && this.selectedComponentIsVfcInstance()) {
+            this.tabs.push(tabs.dependencies);
         }
 
     }
@@ -168,4 +170,8 @@ export class CompositionPanelComponent {
     private selectedComponentIsServiceProxyInstance = (): boolean => {
         return this.isComponentInstanceSelected() && this.selectedComponent.isServiceProxy();
     }
+
+    private selectedComponentIsVfcInstance = (): boolean => {
+        return this.isComponentInstanceSelected() && this.selectedComponent.isVFC();
+    }
 }
index b3c03f8..16767c2 100644 (file)
@@ -20,7 +20,7 @@
         border-left: none;
         border-bottom: none;
         height: 36px;
-        width: 60px;
+        width: 100%;
         display: flex;
         align-content: center;
         justify-content: center;
index 0abb163..6d19ed8 100644 (file)
@@ -233,8 +233,8 @@ export class TopologyTemplateService {
         return this.http.post<AutomatedUpgradeGenericResponse>(this.baseUrl + this.getServerTypeUrl(componentType) + componentId + '/automatedupgrade', componentsIdsToUpgrade);
     }
 
-    updateComponentInstance(componentMetaDataId: string, componentInstance:ComponentInstance): Observable<ComponentInstance> {
-        return this.http.post<ComponentInstance>(this.baseUrl + 'services/' + componentMetaDataId + '/resourceInstance/' + componentInstance.uniqueId, componentInstance);
+    updateComponentInstance(componentMetaDataId: string, componentType: string, componentInstance:ComponentInstance): Observable<ComponentInstance> {
+        return this.http.post<ComponentInstance>(this.baseUrl + this.getServerTypeUrl(componentType) + componentMetaDataId + '/resourceInstance/' + componentInstance.uniqueId, componentInstance);
     }
 
     updateMultipleComponentInstances(componentId: string, componentType: string, instances: ComponentInstance[]): Observable<ComponentInstance[]> {
index 6a17080..adf5ebe 100644 (file)
     "CONSUMPTION_NO_INPUTS_TO_SHOW": "NO INPUTS TO SHOW",
     "CONSUMPTION_NO_OPERATIONS_TO_SHOW": "NO OPERATIONS TO SHOW",
 
-    "============= SERVICE DEPENDENCY ============" : "",
-    "SERVICE_DEPENDENCY_ADD_RULE": "Add Rule",
-    "SERVICE_DEPENDENCY_UPDATE_RULE": "Update Rule",
-    "SERVICE_DEPENDENCY_DELETE_RULE": "Delete Rule",
-    "SERVICE_DEPENDENCY_DELETE_RULE_MSG": "Are you sure you want to delete this rule?",
-    "SERVICE_DEPENDENCY_UNCHECK_TITLE": "Remove Dependency",
-    "SERVICE_DEPENDENCY_UNCHECK_TEXT": "Unchecking \"Mark as Dependent\" will remove dependency and erase all the dependency rules. Are you sure you want to remove dependency?",
+    "============= DIRECTIVES AND NODE FILTER DEPENDENCY ============" : "",
+    "DIRECTIVES_AND_NODE_FILTER_ADD_NODE_FILTER": "Add Node Filter",
+    "DIRECTIVES_AND_NODE_FILTER_UPDATE_NODE_FILTER": "Update Node Filter",
+    "DIRECTIVES_AND_NODE_FILTER_DELETE_NODE_FILTER": "Delete Node Filter",
+    "DIRECTIVES_AND_NODE_FILTER_DELETE_NODE_FILTER_MSG": "Are you sure you want to delete this node filter?",
+    "DIRECTIVES_AND_NODE_FILTER_REMOVE_TITLE": "Remove Directives",
+    "DIRECTIVES_AND_NODE_FILTER_REMOVE_TEXT": "Removing \"Directive Option\" will remove directives value and erase all the node filter. Are you sure you want to remove directives?",
+    "DIRECTIVES_AND_NODE_FILTER_UPDATE_TITLE": "Update Directives",
+    "DIRECTIVES_AND_NODE_FILTER_UPDATE_TEXT": "Changing \"Directive Option\" will remove directives value and erase all the node filter. Are you sure you want to update directives?",
 
     "============= COMPOSITION DETAILS TAB ======" : "",
     "DETAILS_TAB_CHANGE_VERSION_MODAL_TITLE": "Change Version",
diff --git a/catalog-ui/src/assets/styles/images/resource-icons/dependent.png b/catalog-ui/src/assets/styles/images/resource-icons/dependent.png
new file mode 100644 (file)
index 0000000..603093e
Binary files /dev/null and b/catalog-ui/src/assets/styles/images/resource-icons/dependent.png differ
diff --git a/catalog-ui/src/assets/styles/images/resource-icons/uncertified_dependent.png b/catalog-ui/src/assets/styles/images/resource-icons/uncertified_dependent.png
new file mode 100644 (file)
index 0000000..26ebe60
Binary files /dev/null and b/catalog-ui/src/assets/styles/images/resource-icons/uncertified_dependent.png differ