Provide user to specify the ouput name while declaring the atrributes 10/135910/6
authorimamSidero <imam.hussain@est.tech>
Tue, 5 Sep 2023 10:06:25 +0000 (11:06 +0100)
committerVasyl Razinkov <vasyl.razinkov@est.tech>
Wed, 6 Sep 2023 14:58:12 +0000 (14:58 +0000)
User specified output name is provided on declare output functionality

Issue-ID: SDC-4616
Signed-off-by: Imam hussain <imam.hussain@est.tech>
Change-Id: Ic0cd50f9dde2482f5fbb2363cdc83d8fcf09f48f

catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml
catalog-be/src/main/java/org/openecomp/sdc/be/components/attribute/DefaultAttributeDeclarator.java
catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/OutputsBusinessLogic.java
catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/ComponentInstanceAttribOutput.java
catalog-ui/src/app/models/attributes-outputs/attribute-be-model.ts
catalog-ui/src/app/ng2/pages/attributes-outputs/attributes-outputs.page.component.html
catalog-ui/src/app/ng2/pages/attributes-outputs/attributes-outputs.page.component.ts
integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/AttributesTabComponent.java

index c5b417d..4d26e08 100644 (file)
@@ -2926,3 +2926,11 @@ errors:
         message: "Error: The following properties:\n%1\nused in the substitution mapping node type in CSAR are missing from the system. Please add these to the node in the SDC catalog prior to importing the template",
         messageId: "SVC4021"
     }
+
+    # %1 - Output name
+    #---------SVC4022-----------------------------
+    OUTPUT_NAME_ALREADY_EXIST: {
+        code: 400,
+        message: "Output name '%1' already exist.",
+        messageId: "SVC4022"
+    }
index 394d6b3..e494934 100644 (file)
@@ -119,7 +119,13 @@ public abstract class DefaultAttributeDeclarator<PROPERTYOWNER extends Propertie
             //Creating input from property create on self using add property..Do not add the prefix
             generatedInputPrefix = null;
         }
-        final String generatedOutputName = generateOutputName(generatedInputPrefix, attribOutput);
+        String generatedOutputName = null;
+        if (StringUtils.isNotEmpty(attribOutput.getOutputName())) {
+            generatedOutputName = attribOutput.getOutputName();
+        } else {
+            generatedOutputName = generateOutputName(generatedInputPrefix, attribOutput);
+        }
+
         log.debug("createInput: propOwner.uniqueId={}, attribOutput.parentUniqueId={}", propertiesOwner.getUniqueId(),
             attribOutput.getParentUniqueId());
         return createOutputFromAttribute(component.getUniqueId(), propertiesOwner, generatedOutputName, attribOutput, attributeDataDefinition);
index 62ef98b..58baad1 100644 (file)
@@ -23,10 +23,14 @@ package org.openecomp.sdc.be.components.impl;
 import fj.data.Either;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import org.apache.commons.collections.MapUtils;
 import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.jetbrains.annotations.NotNull;
 import org.openecomp.sdc.be.components.attribute.AttributeDeclarationOrchestrator;
 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
@@ -130,6 +134,10 @@ public class OutputsBusinessLogic extends BaseBusinessLogic {
         try {
             validateUserExists(userId);
             component = getAndValidateComponentForCreate(userId, componentId, componentType, shouldLockComp);
+            ImmutablePair<StorageOperationStatus, String> status = validateOutputName(component, componentInstOutputsMapUi);
+            if (status.getLeft() != StorageOperationStatus.OK) {
+                throw new ByResponseFormatComponentException(componentsUtils.getResponseFormat(ActionStatus.OUTPUT_NAME_ALREADY_EXIST, status.getRight()));
+            }
             result = attributeDeclarationOrchestrator.declareAttributesToOutputs(component, componentInstOutputsMapUi).left()
                 .bind(outputsToCreate -> prepareOutputsForCreation(userId, componentId, outputsToCreate)).right()
                 .map(componentsUtils::getResponseFormat);
@@ -155,6 +163,29 @@ public class OutputsBusinessLogic extends BaseBusinessLogic {
         }
     }
 
+    private ImmutablePair<StorageOperationStatus, String> validateOutputName(final Component component,
+                                                                            final ComponentInstOutputsMap componentInstOutputsMapUi) {
+        final Map<String, List<ComponentInstanceAttribOutput>> outputDeclaredProperties = new HashMap<>();
+        if (MapUtils.isNotEmpty(componentInstOutputsMapUi.getComponentInstanceOutputsMap())) {
+            outputDeclaredProperties.putAll(componentInstOutputsMapUi.getComponentInstanceOutputsMap());
+        } else if (MapUtils.isNotEmpty(componentInstOutputsMapUi.getComponentInstanceAttributes())) {
+            outputDeclaredProperties.putAll(componentInstOutputsMapUi.getComponentInstanceAttributes());
+        }
+        if (MapUtils.isNotEmpty(outputDeclaredProperties) && CollectionUtils.isNotEmpty(component.getOutputs())) {
+            for (final List<ComponentInstanceAttribOutput> componentInstancePropOutputs : outputDeclaredProperties.values()) {
+                for (final ComponentInstanceAttribOutput componentInstancePropOutput : componentInstancePropOutputs) {
+                    final Optional<OutputDefinition> outputDefinition = component.getOutputs().stream()
+                        .filter(output -> output.getName().equals(componentInstancePropOutput.getOutputName())
+                            || output.getName().equals(componentInstancePropOutput.getName())).findAny();
+                    if (outputDefinition.isPresent()) {
+                        return new ImmutablePair<>(StorageOperationStatus.INVALID_VALUE, outputDefinition.get().getName());
+                    }
+                }
+            }
+        }
+        return new ImmutablePair<>(StorageOperationStatus.OK, StringUtils.EMPTY);
+    }
+
     private Component getAndValidateComponentForCreate(final String userId, final String componentId,
                                                        final ComponentTypeEnum componentType,
                                                        final boolean shouldLockComp) {
index 52162fc..fbe1c2e 100644 (file)
@@ -94,7 +94,7 @@ public enum ActionStatus {
     // Inputs
     INPUT_IS_NOT_CHILD_OF_COMPONENT, CFVC_LOOP_DETECTED, INPUT_ALREADY_EXIST, INPUT_NAME_ALREADY_EXIST,
     // Outputs
-    OUTPUT_IS_NOT_CHILD_OF_COMPONENT, OUTPUT_ALREADY_EXIST,
+    OUTPUT_IS_NOT_CHILD_OF_COMPONENT, OUTPUT_ALREADY_EXIST, OUTPUT_NAME_ALREADY_EXIST,
     //Forwarding Path related
     FORWARDING_PATH_NAME_MAXIMUM_LENGTH, FORWARDING_PATH_NAME_ALREADY_IN_USE, FORWARDING_PATH_NAME_EMPTY, FORWARDING_PATH_PROTOCOL_MAXIMUM_LENGTH, FORWARDING_PATH_DESTINATION_PORT_MAXIMUM_LENGTH, MISSING_OLD_COMPONENT_INSTANCE, MISSING_NEW_COMPONENT_INSTANCE,
     //policies
index 8531a36..42ff192 100644 (file)
@@ -28,6 +28,7 @@ public class ComponentInstanceAttribOutput extends ComponentInstanceAttribute {
 
     private String attributesName;
     private AttributeDefinition output;
+    private String outputName;
 
     public ComponentInstanceAttribOutput() {
         super();
index a6966cd..3ec03c5 100644 (file)
@@ -51,6 +51,7 @@ export class AttributeBEModel {
   subAttributeOutputPath: string;
   outputPath: string;
   toscaPresentation: ToscaPresentationData;
+  outputName: string;
 
   constructor(attribute?: AttributeBEModel) {
     if (attribute) {
@@ -77,6 +78,7 @@ export class AttributeBEModel {
       this.subAttributeOutputPath = attribute.subAttributeOutputPath;
       this.toscaPresentation = attribute.toscaPresentation;
       this.outputPath = attribute.outputPath;
+      this.outputName = attribute.outputName;
     }
 
     if (!this.schema || !this.schema.property) {
index e4f672c..e55fc47 100644 (file)
@@ -57,7 +57,7 @@
           </div>
         </tabs>
         <div class="header">
-          <button class="tlv-btn blue declare-button" [disabled]="!checkedAttributesCount || isReadonly || hasChangedData" (click)="declareAttributes()" data-tests-id="declare-button declare-output">Declare Output</button>
+          <button class="tlv-btn blue declare-button" [disabled]="!checkedAttributesCount || isReadonly || hasChangedData" (click)="declareOutput()" data-tests-id="declare-button declare-output">Declare Output</button>
         </div>
       </div>
     </div>
index 85d2756..48700f2 100644 (file)
@@ -60,6 +60,7 @@ import {DerivedFEAttribute} from "../../../models/attributes-outputs/derived-fe-
 import {AttributeBEModel} from "../../../models/attributes-outputs/attribute-be-model";
 import {AttributeCreatorComponent} from "app/ng2/pages/attributes-outputs/attribute-creator/attribute-creator.component";
 import {AttributeRowSelectedEvent} from "app/ng2/components/logic/attributes-table/attributes-table.component";
+import { DeclareInputComponent } from '../properties-assignment/declare-input/declare-input.component';
 
 const SERVICE_SELF_TITLE = "SELF";
 
@@ -432,9 +433,62 @@ export class AttributesOutputsComponent {
     this.searchQuery = '';
   };
 
+  declareOutput = (): void => {
+    if (this.checkedAttributesCount == 1) {
+        this.openAddOutputNameModal();
+    } else if (this.checkedAttributesCount > 1) {
+        this.declareAttributes();
+    }
+  }
+
+  private openAddOutputNameModal = (): void => {
+    const modalTitle = 'Enter name of the ouput to be created';
+    const modalButtons = [];
+    const modal = this.ModalService.createCustomModal(new ModalModel(
+        'sm',
+        modalTitle,
+        null,
+        modalButtons,
+        null /* type */
+    ));
+    modalButtons.push(new ButtonModel('Save', 'blue',
+        () => {
+            const outputName: string = modal.instance.dynamicContent.instance.inputNameForm.value;
+            if (outputName) {
+                this.declareAttributes(outputName);
+            } else {
+                this.Notification.warning({
+                    message: 'Failed to set input name',
+                    title: 'Warning'
+                });
+            }
+            this.ModalService.closeCurrentModal();
+        }
+    ));
+    modalButtons.push(new ButtonModel('Cancel', 'outline grey', () => {
+        this.ModalService.closeCurrentModal();
+    }));
+    this.ModalService.addDynamicContentToModal(modal, DeclareInputComponent, {defaultInputName: this.generateDefaultOutputName()});
+    modal.instance.open();
+  }
+
+  generateDefaultOutputName = (): string => {
+    let defaultInputName: string;
+    let instancesIds = this.keysPipe.transform(this.instanceFeAttributesMap, []);
+    angular.forEach(instancesIds, (instanceId: string) => {
+      const selectedOutput : AttributeBEModel = this.attributesService.getCheckedAttributes(this.instanceFeAttributesMap[instanceId])[0];
+        let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
+        defaultInputName = selectedOutput.name;
+        if (selectedInstanceData.invariantName) {
+          defaultInputName = selectedInstanceData.invariantName+'_'+selectedOutput.name;
+        }
+    });
+    return defaultInputName;
+  }
 
   /*** DECLARE ATTRIBUTES/OUTPUTS ***/
-  declareAttributes = (): void => {
+  declareAttributes = (outputName?: string): void => {
+    this.loadingAttributes = true;
     let selectedComponentInstancesAttributes: InstanceBeAttributesMap = new InstanceBeAttributesMap();
     let selectedComponentInstancesOutputs: InstanceBeAttributesMap = new InstanceBeAttributesMap();
     let instancesIds = this.keysPipe.transform(this.instanceFeAttributesMap, []);
@@ -445,6 +499,9 @@ export class AttributesOutputsComponent {
         if (!this.isOutput(selectedInstanceData.originType)) {
           // convert Attribute FE model -> Attribute BE model, extract only checked
           selectedComponentInstancesAttributes[instanceId] = this.attributesService.getCheckedAttributes(this.instanceFeAttributesMap[instanceId]);
+          if (outputName) {
+            selectedComponentInstancesAttributes[instanceId][0].outputName = outputName;
+          }
         } else {
           selectedComponentInstancesOutputs[instanceId] = this.attributesService.getCheckedAttributes(this.instanceFeAttributesMap[instanceId]);
         }
@@ -463,7 +520,8 @@ export class AttributesOutputsComponent {
         this.outputs.push(newOutput);
         this.updateAttributeValueAfterDeclare(newOutput);
       });
-    });
+      this.loadingAttributes = false;
+    }, error => {this.loadingAttributes = false;}); //ignore error
   };
 
   saveChangedData = (): Promise<(AttributeBEModel | OutputBEModel)[]> => {
index e06d702..207c79a 100644 (file)
@@ -45,6 +45,9 @@ public class AttributesTabComponent extends AbstractPageObject {
         }
         waitForElementVisibility(By.xpath(XpathSelector.ATTRIBUTES_CHECKBOX.getXpath(attributeName))).click();
         waitToBeClickable(By.xpath(XpathSelector.DECLARE_OUTPUT_BTN.getXpath())).click();
+        final By setInputNameLocator = By.xpath(XpathSelector.SET_INPUT_NAME_FIELD.getXpath());
+        final WebElement inputNameField = waitForElementVisibility(setInputNameLocator, 5);
+        waitToBeClickable(By.xpath(XpathSelector.INPUT_NAME_SAVE_BTN.getXpath())).click();
         waitForAddedOutputNotification();
     }
 
@@ -82,6 +85,8 @@ public class AttributesTabComponent extends AbstractPageObject {
         ATTRIBUTES_CHECKBOX("//checkbox[@data-tests-id='%s']"),
         DECLARE_OUTPUT_BTN("declare-button declare-output", "//button[@data-tests-id='%s']"),
         INSTANCE_SPAN("//div[contains(@class,'table-rows-header')]"),
+        SET_INPUT_NAME_FIELD("//*[@id=\"myText\"]"),
+        INPUT_NAME_SAVE_BTN("//button[@data-tests-id='Save']"),
         ADDED_OUTPUT_NOTIFICATION("tab-indication", "//div[@data-tests-id='Outputs']/div[contains(@class, '%s')]");
 
         @Getter