aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvasraz <vasyl.razinkov@est.tech>2022-03-24 18:31:14 +0000
committerVasyl Razinkov <vasyl.razinkov@est.tech>2022-04-04 16:56:40 +0000
commit4aff8f5eafb6fbd6cc2c764fa1a5a676fa05c89c (patch)
tree4fbb91db254b1e4791830f5f91673e58376b293e
parentf6b81e6da9b95ec5ef2c8b2b7b50fb8de9f3dd28 (diff)
Implement adding Interface to VFC
Change-Id: I7cd8b82c306294d897d37d486aa3eeff7ca4206d Signed-off-by: Vasyl Razinkov <vasyl.razinkov@est.tech> Issue-ID: SDC-3893 Signed-off-by: andre.schmid <andre.schmid@est.tech>
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogic.java82
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInterfaceOperationServlet.java61
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentNodeFilterServlet.java8
-rw-r--r--catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java117
-rw-r--r--catalog-ui/src/app/ng2/app.module.ts2
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-interface-operation.component.less2
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/interface-operations.component.ts483
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.html27
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.ts111
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.module.ts16
-rw-r--r--catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.html35
-rw-r--r--catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.ts235
-rw-r--r--catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/operation-creator-interface-definition.component.html211
-rw-r--r--catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/operation-creator-interface-definition.component.less200
-rw-r--r--catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/operation-creator-interface-definition.component.ts582
-rw-r--r--catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/operation-creator-interface-definition.module.ts52
-rw-r--r--catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/param-row/param-row.component.html100
-rw-r--r--catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/param-row/param-row.component.less73
-rw-r--r--catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/param-row/param-row.component.ts257
-rw-r--r--catalog-ui/src/app/ng2/pages/interface-operation/interface-operation.page.component.ts87
-rw-r--r--catalog-ui/src/app/ng2/services/component-services/component.service.ts34
-rw-r--r--integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/ImportVfcUiTest.java2
-rw-r--r--integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/ServiceTemplateDesignUiTests.java2
23 files changed, 2356 insertions, 423 deletions
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogic.java
index 57571c0b49..4e44967dcb 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogic.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogic.java
@@ -26,6 +26,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.UUID;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.openecomp.sdc.be.components.impl.exceptions.BusinessLogicException;
@@ -209,8 +210,7 @@ public class ComponentInterfaceOperationBusinessLogic extends BaseBusinessLogic
lockComponent(componentId, component, "Update Interface Operation on Component instance");
wasLocked = true;
}
- final StorageOperationStatus status =
- toscaOperationFacade.updateComponentInterfaces(component.getUniqueId(), component.getInterfaces(), interfaceDefinitionType);
+ final StorageOperationStatus status = toscaOperationFacade.updateComponentInterfaces(component, interfaceDefinitionType);
if (status != StorageOperationStatus.OK) {
janusGraphDao.rollback();
responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR);
@@ -233,6 +233,84 @@ public class ComponentInterfaceOperationBusinessLogic extends BaseBusinessLogic
return Optional.of(component);
}
+ public Optional<Component> createInterfaceOperationInResource(final String componentId, final InterfaceDefinition interfaceDefinition,
+ final ComponentTypeEnum componentTypeEnum,
+ final Wrapper<ResponseFormat> errorWrapper, final boolean shouldLock)
+ throws BusinessLogicException {
+ final Component component = getComponent(componentId);
+ ResponseFormat responseFormat;
+ final String componentInterfaceUpdatedKey = interfaceDefinition.getType();
+
+ Map<String, InterfaceDefinition> componentInterfaceMap = component.getInterfaces();
+ if (MapUtils.isEmpty(componentInterfaceMap)) {
+ componentInterfaceMap = new HashMap<>();
+ component.setInterfaces(componentInterfaceMap);
+ }
+
+ interfaceDefinition.setUniqueId(componentInterfaceUpdatedKey);
+ interfaceDefinition.setToscaResourceName(componentInterfaceUpdatedKey);
+
+ final Optional<OperationDataDefinition> optionalOperationDataDefinition = interfaceDefinition.getOperations().values().stream().findFirst();
+ if (optionalOperationDataDefinition.isEmpty()) {
+ responseFormat = componentsUtils.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NOT_FOUND);
+ LOGGER.debug("Failed to found interface operation on component instance with id {}, error: {}", componentId, responseFormat);
+ errorWrapper.setInnerElement(responseFormat);
+ return Optional.empty();
+ }
+
+ final OperationDataDefinition updatedOperationDataDefinition = optionalOperationDataDefinition.get();
+ updatedOperationDataDefinition.setUniqueId(UUID.randomUUID().toString());
+
+ final InterfaceDefinition interfaceDefinitionFound = componentInterfaceMap.get(componentInterfaceUpdatedKey);
+ if (interfaceDefinitionFound != null) {
+ final Map<String, OperationDataDefinition> operationsFromComponent = interfaceDefinitionFound.getOperations();
+ final String updatedOperationDataDefinitionName = updatedOperationDataDefinition.getName();
+ final boolean find = operationsFromComponent.containsKey(updatedOperationDataDefinitionName);
+ if (find) {
+ responseFormat = componentsUtils.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NAME_ALREADY_IN_USE,
+ updatedOperationDataDefinitionName);
+ LOGGER.error("Operation '{}' for Interface '{}' already exist, error: '{}'", updatedOperationDataDefinitionName,
+ componentInterfaceUpdatedKey, responseFormat);
+ errorWrapper.setInnerElement(responseFormat);
+ return Optional.empty();
+ } else {
+ operationsFromComponent.put(updatedOperationDataDefinitionName, updatedOperationDataDefinition);
+ interfaceDefinition.setOperations(operationsFromComponent);
+ }
+ }
+
+ componentInterfaceMap.put(componentInterfaceUpdatedKey, interfaceDefinition);
+
+ boolean wasLocked = false;
+ try {
+ if (shouldLock) {
+ lockComponent(componentId, component, "Update Interface Operation on Component instance");
+ wasLocked = true;
+ }
+ final Either<InterfaceDefinition, StorageOperationStatus> operationStatusEither =
+ toscaOperationFacade.addInterfaceToComponent(componentInterfaceUpdatedKey, interfaceDefinition, component);
+ if (operationStatusEither.isRight()) {
+ janusGraphDao.rollback();
+ responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR);
+ LOGGER.error("Exception occurred when updating Component Instance Interfaces {}", responseFormat);
+ errorWrapper.setInnerElement(responseFormat);
+ return Optional.empty();
+ }
+ janusGraphDao.commit();
+ } catch (final Exception e) {
+ janusGraphDao.rollback();
+ LOGGER.error("Exception occurred when updating Interface Operation on Component Instance: ", e);
+ responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR);
+ errorWrapper.setInnerElement(responseFormat);
+ throw new BusinessLogicException(responseFormat);
+ } finally {
+ if (wasLocked) {
+ unlockComponent(component.getUniqueId(), componentTypeEnum);
+ }
+ }
+ return Optional.of(component);
+ }
+
public User validateUser(final String userId) {
final User user = userValidations.validateUserExists(userId);
userValidations.validateUserRole(user, Arrays.asList(Role.DESIGNER, Role.ADMIN));
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInterfaceOperationServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInterfaceOperationServlet.java
index 83ee15240f..3b8bfe5bd7 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInterfaceOperationServlet.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInterfaceOperationServlet.java
@@ -36,6 +36,7 @@ import java.util.Optional;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
@@ -138,9 +139,8 @@ public class ComponentInterfaceOperationServlet extends AbstractValidationsServl
}
final Wrapper<ResponseFormat> errorWrapper = new Wrapper<>();
try {
- final Optional<ComponentInstance> actionResponse = componentInterfaceOperationBusinessLogic
- .updateComponentInstanceInterfaceOperation(componentId, componentInstanceId, mappedInterfaceOperationData.get(), componentTypeEnum,
- errorWrapper, true);
+ final Optional<ComponentInstance> actionResponse = componentInterfaceOperationBusinessLogic.updateComponentInstanceInterfaceOperation(
+ componentId, componentInstanceId, mappedInterfaceOperationData.get(), componentTypeEnum, errorWrapper, true);
if (actionResponse.isEmpty()) {
LOGGER.error(FAILED_TO_UPDATE_INTERFACE_OPERATION, componentInstanceId);
return buildErrorResponse(errorWrapper.getInnerElement());
@@ -186,7 +186,60 @@ public class ComponentInterfaceOperationServlet extends AbstractValidationsServl
final Wrapper<ResponseFormat> errorWrapper = new Wrapper<>();
try {
final Optional<Component> actionResponse = componentInterfaceOperationBusinessLogic
- .updateResourceInterfaceOperation(componentId, mappedInterfaceOperationData.get(), componentTypeEnum, errorWrapper, true);
+ .updateResourceInterfaceOperation(componentId, mappedInterfaceOperationData.get(), componentTypeEnum,
+ errorWrapper, true);
+ if (actionResponse.isEmpty()) {
+ LOGGER.error(FAILED_TO_UPDATE_INTERFACE_OPERATION, componentId);
+ return buildErrorResponse(errorWrapper.getInnerElement());
+ } else {
+ LOGGER.debug(INTERFACE_OPERATION_SUCCESSFULLY_UPDATED, componentId);
+ return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), actionResponse.get());
+ }
+ } catch (final Exception e) {
+ BeEcompErrorManager.getInstance().logBeRestApiGeneralError(UPDATE_INTERFACE_OPERATION);
+ LOGGER.error(FAILED_TO_UPDATE_INTERFACE_OPERATION_WITH_ERROR, e);
+ return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
+ }
+ }
+
+ @POST
+ @Path("/{componentType}/{componentId}/resource/interfaceOperation")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Operation(description = "Create Interface Operation", method = "POST", summary = "Create Interface Operation on ComponentInstance", responses = {
+ @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
+ @ApiResponse(responseCode = "201", description = "Create Interface Operation"),
+ @ApiResponse(responseCode = "403", description = "Restricted operation"),
+ @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")})
+ @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
+ public Response createInterfaceOperationInResource(
+ @Parameter(description = "valid values: resources", schema = @Schema(allowableValues = {ComponentTypeEnum.RESOURCE_PARAM_NAME}))
+ @PathParam("componentType") final String componentType,
+ @Parameter(description = "Component Id") @PathParam("componentId") String componentId,
+ @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) throws IOException {
+ LOGGER.debug(START_HANDLE_REQUEST_OF, request.getMethod(), request.getRequestURI());
+ LOGGER.debug(MODIFIER_ID_IS, userId);
+ final User userModifier = componentInterfaceOperationBusinessLogic.validateUser(userId);
+ final ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentType);
+ if (componentTypeEnum == null) {
+ LOGGER.debug(UNSUPPORTED_COMPONENT_TYPE, componentType);
+ return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, componentType));
+ }
+ final byte[] bytes = IOUtils.toByteArray(request.getInputStream());
+ if (bytes == null || bytes.length == 0) {
+ LOGGER.error(INTERFACE_OPERATION_CONTENT_INVALID);
+ return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
+ }
+ final String data = new String(bytes);
+ final Optional<InterfaceDefinition> mappedInterfaceOperationData = getMappedInterfaceData(data, userModifier, componentTypeEnum);
+ if (mappedInterfaceOperationData.isEmpty()) {
+ LOGGER.error(INTERFACE_OPERATION_CONTENT_INVALID, data);
+ return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
+ }
+ final Wrapper<ResponseFormat> errorWrapper = new Wrapper<>();
+ try {
+ final Optional<Component> actionResponse = componentInterfaceOperationBusinessLogic.createInterfaceOperationInResource(
+ componentId, mappedInterfaceOperationData.get(), componentTypeEnum, errorWrapper, true);
if (actionResponse.isEmpty()) {
LOGGER.error(FAILED_TO_UPDATE_INTERFACE_OPERATION, componentId);
return buildErrorResponse(errorWrapper.getInnerElement());
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentNodeFilterServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentNodeFilterServlet.java
index 77b0998e53..c66bb8a8ec 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentNodeFilterServlet.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentNodeFilterServlet.java
@@ -64,7 +64,7 @@ import org.openecomp.sdc.common.api.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-@Path("/v1/catalog/{componentType}/{componentId}/componentInstance/{componentInstanceId}/{constraintType}")
+@Path("/v1/catalog")
@Tags({@Tag(name = "SDCE-2 APIs")})
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@@ -99,7 +99,7 @@ public class ComponentNodeFilterServlet extends AbstractValidationsServlet {
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
- @Path("/nodeFilter")
+ @Path("/{componentType}/{componentId}/componentInstance/{componentInstanceId}/{constraintType}/nodeFilter")
@Operation(description = "Add Component Filter Constraint", method = "POST", summary = "Add Component Filter Constraint", responses = {
@ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
@ApiResponse(responseCode = "201", description = "Create Component Filter"),
@@ -154,7 +154,7 @@ public class ComponentNodeFilterServlet extends AbstractValidationsServlet {
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
- @Path("/{constraintIndex}/nodeFilter")
+ @Path("/{componentType}/{componentId}/componentInstance/{componentInstanceId}/{constraintType}/{constraintIndex}/nodeFilter")
@Operation(description = "Update Component Filter Constraint", method = "PUT", summary = "Update Component Filter Constraint", responses = {
@ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
@ApiResponse(responseCode = "201", description = "Create Component Filter"),
@@ -208,7 +208,7 @@ public class ComponentNodeFilterServlet extends AbstractValidationsServlet {
@DELETE
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
- @Path("{constraintIndex}/nodeFilter")
+ @Path("/{componentType}/{componentId}/componentInstance/{componentInstanceId}/{constraintType}/{constraintIndex}/nodeFilter")
@Operation(description = "Delete Component Filter Constraint", method = "Delete", summary = "Delete Component Filter Constraint", responses = {
@ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
@ApiResponse(responseCode = "201", description = "Delete Component Filter Constraint"),
diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java
index c07523d3cc..496fd0fe08 100644
--- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java
+++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java
@@ -43,9 +43,7 @@ import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiPredicate;
-import java.util.function.Predicate;
import java.util.stream.Collectors;
-import java.util.stream.StreamSupport;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
@@ -55,9 +53,9 @@ import org.apache.tinkerpop.gremlin.structure.Edge;
import org.janusgraph.graphdb.query.JanusGraphPredicate;
import org.openecomp.sdc.be.config.Configuration;
import org.openecomp.sdc.be.config.ConfigurationManager;
+import org.openecomp.sdc.be.dao.janusgraph.HealingJanusGraphDao;
import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
import org.openecomp.sdc.be.dao.jsongraph.GraphVertex;
-import org.openecomp.sdc.be.dao.janusgraph.HealingJanusGraphDao;
import org.openecomp.sdc.be.dao.jsongraph.types.EdgeLabelEnum;
import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum;
import org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum;
@@ -487,7 +485,8 @@ public class ToscaOperationFacade {
});
}
- public <T extends Component> Either<T, StorageOperationStatus> getByToscaResourceNameAndVersion(final String toscaResourceName, final String version, final String model) {
+ public <T extends Component> Either<T, StorageOperationStatus> getByToscaResourceNameAndVersion(final String toscaResourceName,
+ final String version, final String model) {
Either<T, StorageOperationStatus> result;
Map<GraphPropertyEnum, Object> hasProperties = new EnumMap<>(GraphPropertyEnum.class);
@@ -904,8 +903,9 @@ public class ToscaOperationFacade {
}
public <T extends Component> Either<T, StorageOperationStatus> getComponentByNameAndVendorRelease(final ComponentTypeEnum componentType,
- final String name, final String vendorRelease,
- final JsonParseFlagEnum parseFlag, final String modelName) {
+ final String name, final String vendorRelease,
+ final JsonParseFlagEnum parseFlag,
+ final String modelName) {
Map<GraphPropertyEnum, Object> hasProperties = new EnumMap<>(GraphPropertyEnum.class);
Map<GraphPropertyEnum, Object> hasNotProperties = new EnumMap<>(GraphPropertyEnum.class);
hasProperties.put(GraphPropertyEnum.NAME, name);
@@ -1871,16 +1871,17 @@ public class ToscaOperationFacade {
updateInstancesCapAndReqOnComponentFromDB(component);
return storageOperationStatus;
}
-
- public StorageOperationStatus updateCalculatedCapabilitiesRequirements(final Map<ComponentInstance, Map<String, List<CapabilityDefinition>>> instCapabilties,
- final Map<ComponentInstance, Map<String, List<RequirementDefinition>>> instReg,
- final Component component) {
+
+ public StorageOperationStatus updateCalculatedCapabilitiesRequirements(
+ final Map<ComponentInstance, Map<String, List<CapabilityDefinition>>> instCapabilties,
+ final Map<ComponentInstance, Map<String, List<RequirementDefinition>>> instReg,
+ final Component component) {
StorageOperationStatus storageOperationStatus = StorageOperationStatus.OK;
if (instCapabilties != null) {
for (Entry<ComponentInstance, Map<String, List<CapabilityDefinition>>> entry : instCapabilties.entrySet()) {
final Map<String, List<CapabilityDefinition>> cap = entry.getValue();
- for (List<CapabilityDefinition> capabilityList: cap.values()) {
- for (CapabilityDefinition capability: capabilityList) {
+ for (List<CapabilityDefinition> capabilityList : cap.values()) {
+ for (CapabilityDefinition capability : capabilityList) {
nodeTemplateOperation.updateComponentInstanceCapabilities(component.getUniqueId(), entry.getKey().getUniqueId(), capability);
}
}
@@ -1889,9 +1890,10 @@ public class ToscaOperationFacade {
if (instReg != null) {
for (Entry<ComponentInstance, Map<String, List<RequirementDefinition>>> entry : instReg.entrySet()) {
final Map<String, List<RequirementDefinition>> req = entry.getValue();
- for (List<RequirementDefinition> requirementList: req.values()) {
- for (RequirementDefinition requirement: requirementList) {
- storageOperationStatus = nodeTemplateOperation.updateComponentInstanceRequirement(component.getUniqueId(), entry.getKey().getUniqueId(), requirement);
+ for (List<RequirementDefinition> requirementList : req.values()) {
+ for (RequirementDefinition requirement : requirementList) {
+ storageOperationStatus = nodeTemplateOperation.updateComponentInstanceRequirement(component.getUniqueId(),
+ entry.getKey().getUniqueId(), requirement);
if (storageOperationStatus != StorageOperationStatus.OK) {
return storageOperationStatus;
}
@@ -2103,6 +2105,7 @@ public class ToscaOperationFacade {
}
return result;
}
+
public Either<Boolean, StorageOperationStatus> validateComponentNameUniqueness(String name, ResourceTypeEnum resourceType,
ComponentTypeEnum componentType) {
String normalizedName = ValidationUtils.normaliseComponentName(name);
@@ -2130,7 +2133,8 @@ public class ToscaOperationFacade {
final ComponentTypeEnum componentType) {
final String normalizedName = ValidationUtils.normaliseComponentName(resourceName);
final Either<List<GraphVertex>, JanusGraphOperationStatus> vertexEither = janusGraphDao
- .getByCriteria(getVertexTypeEnum(resourceType), propertiesToMatch(normalizedName, componentType), null, null, JsonParseFlagEnum.NoParse, modelName);
+ .getByCriteria(getVertexTypeEnum(resourceType), propertiesToMatch(normalizedName, componentType), null, null, JsonParseFlagEnum.NoParse,
+ modelName);
if (vertexEither.isRight() && vertexEither.right().value() != JanusGraphOperationStatus.NOT_FOUND) {
log.debug("failed to get vertex from graph with property normalizedName: {} and model: {}", normalizedName, modelName);
return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(vertexEither.right().value()));
@@ -2210,7 +2214,8 @@ public class ToscaOperationFacade {
if (ComponentTypeEnum.RESOURCE == componentTypeEnum) {
internalVertexTypes.add(VertexTypeEnum.NODE_TYPE);
}
- if (ComponentTypeEnum.SERVICE == componentTypeEnum || SERVICE.equalsIgnoreCase(internalComponentType) || VF.equalsIgnoreCase(internalComponentType)) {
+ if (ComponentTypeEnum.SERVICE == componentTypeEnum || SERVICE.equalsIgnoreCase(internalComponentType) || VF.equalsIgnoreCase(
+ internalComponentType)) {
internalVertexTypes.add(VertexTypeEnum.TOPOLOGY_TEMPLATE);
}
return internalVertexTypes;
@@ -2471,7 +2476,8 @@ public class ToscaOperationFacade {
return null;
}
- public Either<Boolean, StorageOperationStatus> validateToscaResourceNameExtends(String templateNameCurrent, String templateNameExtends, String model) {
+ public Either<Boolean, StorageOperationStatus> validateToscaResourceNameExtends(String templateNameCurrent, String templateNameExtends,
+ String model) {
String currentTemplateNameChecked = templateNameExtends;
while (currentTemplateNameChecked != null && !currentTemplateNameChecked.equalsIgnoreCase(templateNameCurrent)) {
Either<Resource, StorageOperationStatus> latestByToscaResourceName = getLatestByToscaResourceName(currentTemplateNameChecked, model);
@@ -2617,27 +2623,6 @@ public class ToscaOperationFacade {
return Either.left(servicesAll);
}
- private List<GraphVertex> getVerticesForModel(final String modelName, final List<GraphVertex> graphVertexList) {
- final Predicate<? super GraphVertex> filterPredicate =
- StringUtils.isEmpty(modelName) ? this::vertexNotConnectedToAnyModel
- : graphVertex -> vertexValidForModel(graphVertex, modelName).isPresent();
- return StreamSupport.stream(graphVertexList.spliterator(), false).filter(filterPredicate).collect(Collectors.toList());
- }
-
- private boolean vertexNotConnectedToAnyModel(final GraphVertex vertex) {
- return !vertex.getVertex().edges(Direction.OUT, EdgeLabelEnum.MODEL.name()).hasNext();
- }
-
- private Optional<GraphVertex> vertexValidForModel(final GraphVertex vertex, final String model) {
- final Either<List<GraphVertex>, JanusGraphOperationStatus> nodeModelVertices = janusGraphDao
- .getParentVertices(vertex, EdgeLabelEnum.MODEL, JsonParseFlagEnum.NoParse);
- if (nodeModelVertices.isRight() || Objects.isNull(nodeModelVertices.left().value())) {
- return Optional.empty();
- }
- return nodeModelVertices.left().value().stream().filter(graphVertex -> graphVertex.getMetadataProperty(GraphPropertyEnum.MODEL).equals(model))
- .findFirst();
- }
-
public void rollback() {
janusGraphDao.rollback();
}
@@ -3107,7 +3092,7 @@ public class ToscaOperationFacade {
public StorageOperationStatus updateComponentInstanceCapabilityProperties(Component containerComponent, String componentInstanceUniqueId) {
return convertComponentInstanceProperties(containerComponent, componentInstanceUniqueId).map(instanceCapProps -> topologyTemplateOperation
- .updateComponentInstanceCapabilityProperties(containerComponent, componentInstanceUniqueId, instanceCapProps))
+ .updateComponentInstanceCapabilityProperties(containerComponent, componentInstanceUniqueId, instanceCapProps))
.orElse(StorageOperationStatus.NOT_FOUND);
}
@@ -3127,10 +3112,54 @@ public class ToscaOperationFacade {
return topologyTemplateOperation.updateComponentInstanceInterfaces(containerComponent, componentInstanceUniqueId, mapInterfaceDataDefinition);
}
- public StorageOperationStatus updateComponentInterfaces(final String componentId, final Map<String, InterfaceDefinition> interfaces,
- final String componentInterfaceUpdatedKey) {
- MapInterfaceDataDefinition mapInterfaceDataDefinition = convertComponentInterfaces(interfaces);
- return topologyTemplateOperation.updateComponentInterfaces(componentId, mapInterfaceDataDefinition, componentInterfaceUpdatedKey);
+ public StorageOperationStatus updateComponentInterfaces(final Component component, final String componentInterfaceUpdatedKey) {
+ MapInterfaceDataDefinition mapInterfaceDataDefinition = convertComponentInterfaces(component.getInterfaces());
+ return topologyTemplateOperation.updateComponentInterfaces(component.getUniqueId(), mapInterfaceDataDefinition, componentInterfaceUpdatedKey);
+ }
+
+ public Either<InterfaceDefinition, StorageOperationStatus> addInterfaceToComponent(final String interfaceName,
+ final InterfaceDefinition interfaceDefinition,
+ final Component component) {
+
+ final boolean match = component.getInterfaces().keySet().stream().anyMatch(s -> s.equals(interfaceName));
+ StorageOperationStatus status = StorageOperationStatus.OK;
+ final ToscaElementOperation toscaElementOperation = getToscaElementOperation(component);
+ if (match) {
+ status = toscaElementOperation.updateToscaDataOfToscaElement(component.getUniqueId(), EdgeLabelEnum.INTERFACE_ARTIFACTS,
+ VertexTypeEnum.INTERFACE_ARTIFACTS, interfaceDefinition, JsonPresentationFields.TYPE);
+ } else {
+ status = toscaElementOperation.addToscaDataToToscaElement(component.getUniqueId(), EdgeLabelEnum.INTERFACE_ARTIFACTS,
+ VertexTypeEnum.INTERFACE_ARTIFACTS, interfaceDefinition, JsonPresentationFields.TYPE);
+ }
+
+ if (status != StorageOperationStatus.OK) {
+ CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to add the interface {} to the component {}. Status is {}. ",
+ interfaceName, component.getName(), status);
+ return Either.right(status);
+ }
+ final ComponentParametersView filter = new ComponentParametersView(true);
+ filter.setIgnoreInterfaces(false);
+ filter.setIgnoreInterfaceInstances(false);
+ final Either<Component, StorageOperationStatus> getUpdatedComponentRes = getToscaElement(component.getUniqueId(), filter);
+ if (getUpdatedComponentRes.isRight()) {
+ CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to get updated component {}. Status is {}. ",
+ component.getUniqueId(), getUpdatedComponentRes.right().value());
+ return Either.right(getUpdatedComponentRes.right().value());
+ }
+ InterfaceDefinition newInterfaceDefinition = null;
+ final Map<String, InterfaceDefinition> interfaces = (getUpdatedComponentRes.left().value()).getInterfaces();
+ if (MapUtils.isNotEmpty(interfaces)) {
+ final Optional<String> interfaceNameOptional = interfaces.keySet().stream().filter(key -> key.equals(interfaceName)).findAny();
+ if (interfaceNameOptional.isPresent()) {
+ newInterfaceDefinition = interfaces.get(interfaceNameOptional.get());
+ }
+ }
+ if (newInterfaceDefinition == null) {
+ CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to find recently added interface {} on the component {}. Status is {}. ",
+ interfaceName, component.getUniqueId(), StorageOperationStatus.NOT_FOUND);
+ return Either.right(StorageOperationStatus.NOT_FOUND);
+ }
+ return Either.left(newInterfaceDefinition);
}
public StorageOperationStatus updateComponentCalculatedCapabilitiesProperties(Component containerComponent) {
diff --git a/catalog-ui/src/app/ng2/app.module.ts b/catalog-ui/src/app/ng2/app.module.ts
index e9ae1201af..37167b4360 100644
--- a/catalog-ui/src/app/ng2/app.module.ts
+++ b/catalog-ui/src/app/ng2/app.module.ts
@@ -45,6 +45,7 @@ import {UiElementsModule} from './components/ui/ui-elements.module';
import {ConnectionWizardModule} from './pages/composition/graph/connection-wizard/connection-wizard.module';
import {InterfaceOperationModule} from './pages/interface-operation/interface-operation.module';
import {OperationCreatorModule} from './pages/interface-operation/operation-creator/operation-creator.module';
+import {OperationCreatorInterfaceDefinitionModule} from './pages/interface-definition/operation-creator/operation-creator-interface-definition.module';
import {LayoutModule} from './components/layout/layout.module';
import {UserService} from './services/user.service';
import {DynamicComponentService} from './services/dynamic-component.service';
@@ -158,6 +159,7 @@ export function configServiceFactory(config: ConfigService, authService: Authent
InterfaceOperationModule,
InterfaceDefinitionModule,
OperationCreatorModule,
+ OperationCreatorInterfaceDefinitionModule,
InterfaceOperationHandlerModule,
ServicePathCreatorModule,
ServicePathsListModule,
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-interface-operation.component.less b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-interface-operation.component.less
index 4c7f8aba48..ac917134f2 100644
--- a/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-interface-operation.component.less
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-interface-operation.component.less
@@ -20,7 +20,7 @@
@import '../../../../../../../assets/styles/variables.less';
@import '../../../../../../../assets/styles/override.less';
-.operation-creator {
+.operation-creator-interface-definition {
font-family: @font-opensans-regular;
user-select: none;
padding-top: 12px;
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/interface-operations.component.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/interface-operations.component.ts
index 07d8fd6eea..c17c130d92 100644
--- a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/interface-operations.component.ts
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/interface-operations.component.ts
@@ -20,7 +20,9 @@
*/
import {Component, ComponentRef, Inject, Input} from '@angular/core';
-import {TopologyTemplateService} from '../../../services/component-services/topology-template.service';
+import {
+ TopologyTemplateService
+} from '../../../services/component-services/topology-template.service';
import {TranslateService} from "../../../shared/translator/translate.service";
import {ModalService} from 'app/ng2/services/modal.service';
import {ModalComponent} from 'app/ng2/components/ui/modal/modal.component';
@@ -29,265 +31,282 @@ import {PluginsService} from "app/ng2/services/plugins.service";
import {SelectedComponentType} from "../common/store/graph.actions";
import {WorkspaceService} from "../../workspace/workspace.service";
-import {ComponentInterfaceDefinitionModel, InterfaceOperationModel} from "../../../../models/interfaceOperation";
-import {InterfaceOperationHandlerComponent} from "./operation-creator/interface-operation-handler.component";
-
-import {ArtifactModel, ButtonModel, ComponentInstance, ComponentMetadata, InputBEModel, InterfaceModel, ModalModel} from 'app/models';
+import {
+ ComponentInterfaceDefinitionModel,
+ InterfaceOperationModel
+} from "../../../../models/interfaceOperation";
+import {
+ InterfaceOperationHandlerComponent
+} from "./operation-creator/interface-operation-handler.component";
+
+import {
+ ArtifactModel,
+ ButtonModel,
+ ComponentInstance,
+ ComponentMetadata,
+ InputBEModel,
+ InterfaceModel,
+ ModalModel
+} from 'app/models';
import {ArtifactGroupType} from "../../../../utils/constants";
-import {DropdownValue} from "../../../components/ui/form-components/dropdown/ui-element-dropdown.component";
+import {
+ DropdownValue
+} from "../../../components/ui/form-components/dropdown/ui-element-dropdown.component";
import {ToscaArtifactService} from "../../../services/tosca-artifact.service";
import {ToscaArtifactModel} from "../../../../models/toscaArtifact";
export class UIInterfaceOperationModel extends InterfaceOperationModel {
- isCollapsed: boolean = true;
- isEllipsis: boolean;
- MAX_LENGTH = 75;
- constructor(operation: InterfaceOperationModel) {
- super(operation);
-
- if (!operation.description) {
- this.description = '';
- }
+ isCollapsed: boolean = true;
+ isEllipsis: boolean;
+ MAX_LENGTH = 75;
+
+ constructor(operation: InterfaceOperationModel) {
+ super(operation);
- if (this.description.length > this.MAX_LENGTH) {
- this.isEllipsis = true;
- } else {
- this.isEllipsis = false;
+ if (!operation.description) {
+ this.description = '';
+ }
+
+ if (this.description.length > this.MAX_LENGTH) {
+ this.isEllipsis = true;
+ } else {
+ this.isEllipsis = false;
+ }
}
- }
- getDescriptionEllipsis(): string {
- if (this.isCollapsed && this.description.length > this.MAX_LENGTH) {
- return this.description.substr(0, this.MAX_LENGTH - 3) + '...';
+ getDescriptionEllipsis(): string {
+ if (this.isCollapsed && this.description.length > this.MAX_LENGTH) {
+ return this.description.substr(0, this.MAX_LENGTH - 3) + '...';
+ }
+ return this.description;
}
- return this.description;
- }
- toggleCollapsed(e) {
- e.stopPropagation();
- this.isCollapsed = !this.isCollapsed;
- }
+ toggleCollapsed(e) {
+ e.stopPropagation();
+ this.isCollapsed = !this.isCollapsed;
+ }
}
class ModalTranslation {
- EDIT_TITLE: string;
- CANCEL_BUTTON: string;
- CLOSE_BUTTON: string;
- SAVE_BUTTON: string;
-
- constructor(private TranslateService: TranslateService) {
- this.TranslateService.languageChangedObservable.subscribe(lang => {
- this.EDIT_TITLE = this.TranslateService.translate('INTERFACE_EDIT_TITLE');
- this.CANCEL_BUTTON = this.TranslateService.translate("INTERFACE_CANCEL_BUTTON");
- this.CLOSE_BUTTON = this.TranslateService.translate("INTERFACE_CLOSE_BUTTON");
- this.SAVE_BUTTON = this.TranslateService.translate("INTERFACE_SAVE_BUTTON");
- });
- }
+ EDIT_TITLE: string;
+ CANCEL_BUTTON: string;
+ CLOSE_BUTTON: string;
+ SAVE_BUTTON: string;
+
+ constructor(private TranslateService: TranslateService) {
+ this.TranslateService.languageChangedObservable.subscribe(lang => {
+ this.EDIT_TITLE = this.TranslateService.translate('INTERFACE_EDIT_TITLE');
+ this.CANCEL_BUTTON = this.TranslateService.translate("INTERFACE_CANCEL_BUTTON");
+ this.CLOSE_BUTTON = this.TranslateService.translate("INTERFACE_CLOSE_BUTTON");
+ this.SAVE_BUTTON = this.TranslateService.translate("INTERFACE_SAVE_BUTTON");
+ });
+ }
}
export class UIInterfaceModel extends ComponentInterfaceDefinitionModel {
- isCollapsed: boolean = false;
-
- constructor(interf?: any) {
- super(interf);
- this.operations = _.map(
- this.operations,
- (operation) => new UIInterfaceOperationModel(operation)
- );
- }
-
- toggleCollapse() {
- this.isCollapsed = !this.isCollapsed;
- }
+ isCollapsed: boolean = false;
+
+ constructor(interf?: any) {
+ super(interf);
+ this.operations = _.map(
+ this.operations,
+ (operation) => new UIInterfaceOperationModel(operation)
+ );
+ }
+
+ toggleCollapse() {
+ this.isCollapsed = !this.isCollapsed;
+ }
}
@Component({
- selector: 'app-interface-operations',
- templateUrl: './interface-operations.component.html',
- styleUrls: ['./interface-operations.component.less'],
- providers: [ModalService, TranslateService]
+ selector: 'app-interface-operations',
+ templateUrl: './interface-operations.component.html',
+ styleUrls: ['./interface-operations.component.less'],
+ providers: [ModalService, TranslateService]
})
export class InterfaceOperationsComponent {
- interfaces: UIInterfaceModel[];
- inputs: Array<InputBEModel>;
- isLoading: boolean;
- interfaceTypes: { [interfaceType: string]: string[] };
- topologyTemplate: TopologyTemplate;
- componentMetaData: ComponentMetadata;
- componentInstanceSelected: ComponentInstance;
- modalInstance: ComponentRef<ModalComponent>;
- modalTranslation: ModalTranslation;
- componentInstancesInterfaces: Map<string, InterfaceModel[]>;
-
- deploymentArtifactsFilePath: Array<DropdownValue> = [];
- toscaArtifactTypes: Array<DropdownValue> = [];
-
- @Input() component: ComponentInstance;
- @Input() isViewOnly: boolean;
- @Input() enableMenuItems: Function;
- @Input() disableMenuItems: Function;
- @Input() componentType: SelectedComponentType;
-
-
- constructor(
- private TranslateService: TranslateService,
- private PluginsService: PluginsService,
- private topologyTemplateService: TopologyTemplateService,
- private toscaArtifactService: ToscaArtifactService,
- private modalServiceNg2: ModalService,
- private workspaceService: WorkspaceService,
- @Inject("Notification") private Notification: any,
- ) {
- this.modalTranslation = new ModalTranslation(TranslateService);
- }
-
- ngOnInit(): void {
- this.componentMetaData = this.workspaceService.metadata;
- this.loadComponentInstances();
- this.loadDeployedArtifacts();
- this.loadToscaArtifacts()
- }
-
- private loadComponentInstances() {
- this.isLoading = true;
- this.topologyTemplateService.getComponentInstances(this.componentMetaData.componentType, this.componentMetaData.uniqueId)
- .subscribe((response) => {
- this.componentInstanceSelected = response.componentInstances.find(ci => ci.uniqueId === this.component.uniqueId);
- this.initComponentInstanceInterfaceOperations();
- this.isLoading = false;
- });
- }
-
- private initComponentInstanceInterfaceOperations() {
- this.initInterfaces(this.componentInstanceSelected.interfaces);
- this.sortInterfaces();
- }
-
- private initInterfaces(interfaces: ComponentInterfaceDefinitionModel[]): void {
- this.interfaces = _.map(interfaces, (interfaceModel) => new UIInterfaceModel(interfaceModel));
- }
-
- private sortInterfaces(): void {
- this.interfaces = _.filter(this.interfaces, (interf) => interf.operations && interf.operations.length > 0); // remove empty interfaces
- this.interfaces.sort((a, b) => a.type.localeCompare(b.type)); // sort interfaces alphabetically
- _.forEach(this.interfaces, (interf) => {
- interf.operations.sort((a, b) => a.name.localeCompare(b.name)); // sort operations alphabetically
- });
- }
-
- collapseAll(value: boolean = true): void {
- _.forEach(this.interfaces, (interf) => {
- interf.isCollapsed = value;
- });
- }
-
- isAllCollapsed(): boolean {
- return _.every(this.interfaces, (interf) => interf.isCollapsed);
- }
-
- isAllExpanded(): boolean {
- return _.every(this.interfaces, (interf) => !interf.isCollapsed);
- }
-
- isListEmpty(): boolean {
- return _.filter(
- this.interfaces,
- (interf) => interf.operations && interf.operations.length > 0
- ).length === 0;
- }
-
- private enableOrDisableSaveButton = (): boolean => {
- return this.isViewOnly;
- }
-
- onSelectInterfaceOperation(interfaceModel: UIInterfaceModel, operation: InterfaceOperationModel) {
-
- const buttonList = [];
- if (this.isViewOnly) {
- const closeButton: ButtonModel = new ButtonModel(this.modalTranslation.CLOSE_BUTTON, 'outline white', this.cancelAndCloseModal);
- buttonList.push(closeButton);
- } else {
- const saveButton: ButtonModel = new ButtonModel(this.modalTranslation.SAVE_BUTTON, 'blue', () =>
- this.updateInterfaceOperation(), this.enableOrDisableSaveButton);
- const cancelButton: ButtonModel = new ButtonModel(this.modalTranslation.CANCEL_BUTTON, 'outline white', this.cancelAndCloseModal);
- buttonList.push(saveButton);
- buttonList.push(cancelButton);
+ interfaces: UIInterfaceModel[];
+ inputs: Array<InputBEModel>;
+ isLoading: boolean;
+ interfaceTypes: { [interfaceType: string]: string[] };
+ topologyTemplate: TopologyTemplate;
+ componentMetaData: ComponentMetadata;
+ componentInstanceSelected: ComponentInstance;
+ modalInstance: ComponentRef<ModalComponent>;
+ modalTranslation: ModalTranslation;
+ componentInstancesInterfaces: Map<string, InterfaceModel[]>;
+
+ deploymentArtifactsFilePath: Array<DropdownValue> = [];
+ toscaArtifactTypes: Array<DropdownValue> = [];
+
+ @Input() component: ComponentInstance;
+ @Input() isViewOnly: boolean;
+ @Input() enableMenuItems: Function;
+ @Input() disableMenuItems: Function;
+ @Input() componentType: SelectedComponentType;
+
+
+ constructor(
+ private TranslateService: TranslateService,
+ private PluginsService: PluginsService,
+ private topologyTemplateService: TopologyTemplateService,
+ private toscaArtifactService: ToscaArtifactService,
+ private modalServiceNg2: ModalService,
+ private workspaceService: WorkspaceService,
+ @Inject("Notification") private Notification: any,
+ ) {
+ this.modalTranslation = new ModalTranslation(TranslateService);
+ }
+
+ ngOnInit(): void {
+ this.componentMetaData = this.workspaceService.metadata;
+ this.loadComponentInstances();
+ this.loadDeployedArtifacts();
+ this.loadToscaArtifacts()
+ }
+
+ private loadComponentInstances() {
+ this.isLoading = true;
+ this.topologyTemplateService.getComponentInstances(this.componentMetaData.componentType, this.componentMetaData.uniqueId)
+ .subscribe((response) => {
+ this.componentInstanceSelected = response.componentInstances.find(ci => ci.uniqueId === this.component.uniqueId);
+ this.initComponentInstanceInterfaceOperations();
+ this.isLoading = false;
+ });
+ }
+
+ private initComponentInstanceInterfaceOperations() {
+ this.initInterfaces(this.componentInstanceSelected.interfaces);
+ this.sortInterfaces();
+ }
+
+ private initInterfaces(interfaces: ComponentInterfaceDefinitionModel[]): void {
+ this.interfaces = _.map(interfaces, (interfaceModel) => new UIInterfaceModel(interfaceModel));
+ }
+
+ private sortInterfaces(): void {
+ this.interfaces = _.filter(this.interfaces, (interf) => interf.operations && interf.operations.length > 0); // remove empty interfaces
+ this.interfaces.sort((a, b) => a.type.localeCompare(b.type)); // sort interfaces alphabetically
+ _.forEach(this.interfaces, (interf) => {
+ interf.operations.sort((a, b) => a.name.localeCompare(b.name)); // sort operations alphabetically
+ });
+ }
+
+ collapseAll(value: boolean = true): void {
+ _.forEach(this.interfaces, (interf) => {
+ interf.isCollapsed = value;
+ });
+ }
+
+ isAllCollapsed(): boolean {
+ return _.every(this.interfaces, (interf) => interf.isCollapsed);
+ }
+
+ isAllExpanded(): boolean {
+ return _.every(this.interfaces, (interf) => !interf.isCollapsed);
+ }
+
+ isListEmpty(): boolean {
+ return _.filter(
+ this.interfaces,
+ (interf) => interf.operations && interf.operations.length > 0
+ ).length === 0;
+ }
+
+ private enableOrDisableSaveButton = (): boolean => {
+ return this.isViewOnly;
}
- const modalModel: ModalModel = new ModalModel('l', this.modalTranslation.EDIT_TITLE, '', buttonList, 'custom');
- this.modalInstance = this.modalServiceNg2.createCustomModal(modalModel);
-
- this.modalServiceNg2.addDynamicContentToModal(
- this.modalInstance,
- InterfaceOperationHandlerComponent,
- {
- deploymentArtifactsFilePath: this.deploymentArtifactsFilePath,
- toscaArtifactTypes: this.toscaArtifactTypes,
- selectedInterface: interfaceModel,
- selectedInterfaceOperation: operation,
- validityChangedCallback: this.enableOrDisableSaveButton,
- isViewOnly: this.isViewOnly
+
+ onSelectInterfaceOperation(interfaceModel: UIInterfaceModel, operation: InterfaceOperationModel) {
+
+ const buttonList = [];
+ if (this.isViewOnly) {
+ const closeButton: ButtonModel = new ButtonModel(this.modalTranslation.CLOSE_BUTTON, 'outline white', this.cancelAndCloseModal);
+ buttonList.push(closeButton);
+ } else {
+ const saveButton: ButtonModel = new ButtonModel(this.modalTranslation.SAVE_BUTTON, 'blue', () =>
+ this.updateInterfaceOperation(), this.enableOrDisableSaveButton);
+ const cancelButton: ButtonModel = new ButtonModel(this.modalTranslation.CANCEL_BUTTON, 'outline white', this.cancelAndCloseModal);
+ buttonList.push(saveButton);
+ buttonList.push(cancelButton);
}
- );
- this.modalInstance.instance.open();
- }
-
- private cancelAndCloseModal = () => {
- this.loadComponentInstances();
- return this.modalServiceNg2.closeCurrentModal();
- }
-
- private updateInterfaceOperation() {
- this.isLoading = true;
- const interfaceOperationHandlerComponentInstance: InterfaceOperationHandlerComponent = this.modalInstance.instance.dynamicContent.instance;
- const operationUpdated: InterfaceOperationModel = interfaceOperationHandlerComponentInstance.operationToUpdate;
- const isArtifactChecked = interfaceOperationHandlerComponentInstance.enableAddArtifactImplementation;
- if (!isArtifactChecked) {
- let artifactName = interfaceOperationHandlerComponentInstance.artifactName;
- artifactName = artifactName === undefined ? '' : artifactName;
- operationUpdated.implementation = new ArtifactModel({'artifactName': artifactName} as ArtifactModel);
+ const modalModel: ModalModel = new ModalModel('l', this.modalTranslation.EDIT_TITLE, '', buttonList, 'custom');
+ this.modalInstance = this.modalServiceNg2.createCustomModal(modalModel);
+
+ this.modalServiceNg2.addDynamicContentToModal(
+ this.modalInstance,
+ InterfaceOperationHandlerComponent,
+ {
+ deploymentArtifactsFilePath: this.deploymentArtifactsFilePath,
+ toscaArtifactTypes: this.toscaArtifactTypes,
+ selectedInterface: interfaceModel ? interfaceModel : new UIInterfaceModel(),
+ selectedInterfaceOperation: operation ? operation : new InterfaceOperationModel(),
+ validityChangedCallback: this.enableOrDisableSaveButton,
+ isViewOnly: this.isViewOnly
+ }
+ );
+ this.modalInstance.instance.open();
+ }
+
+ private cancelAndCloseModal = () => {
+ this.loadComponentInstances();
+ return this.modalServiceNg2.closeCurrentModal();
}
- this.topologyTemplateService.updateComponentInstanceInterfaceOperation(
- this.componentMetaData.uniqueId,
- this.componentMetaData.componentType,
- this.componentInstanceSelected.uniqueId,
- operationUpdated)
+
+ private updateInterfaceOperation() {
+ this.isLoading = true;
+ const interfaceOperationHandlerComponentInstance: InterfaceOperationHandlerComponent = this.modalInstance.instance.dynamicContent.instance;
+ const operationUpdated: InterfaceOperationModel = interfaceOperationHandlerComponentInstance.operationToUpdate;
+ const isArtifactChecked = interfaceOperationHandlerComponentInstance.enableAddArtifactImplementation;
+ if (!isArtifactChecked) {
+ let artifactName = interfaceOperationHandlerComponentInstance.artifactName;
+ artifactName = artifactName === undefined ? '' : artifactName;
+ operationUpdated.implementation = new ArtifactModel({'artifactName': artifactName} as ArtifactModel);
+ }
+ this.topologyTemplateService.updateComponentInstanceInterfaceOperation(
+ this.componentMetaData.uniqueId,
+ this.componentMetaData.componentType,
+ this.componentInstanceSelected.uniqueId,
+ operationUpdated)
.subscribe((updatedComponentInstance: ComponentInstance) => {
this.componentInstanceSelected = new ComponentInstance(updatedComponentInstance);
this.initComponentInstanceInterfaceOperations();
});
- this.modalServiceNg2.closeCurrentModal();
- this.isLoading = false;
- }
-
- loadDeployedArtifacts() {
- this.topologyTemplateService.getArtifactsByType(this.componentMetaData.componentType, this.componentMetaData.uniqueId, ArtifactGroupType.DEPLOYMENT)
- .subscribe(response => {
- let artifactsDeployment = response.deploymentArtifacts;
- if (artifactsDeployment) {
- let deploymentArtifactsFound = <ArtifactModel[]>_.values(artifactsDeployment)
- deploymentArtifactsFound.forEach(value => {
- this.deploymentArtifactsFilePath.push(new DropdownValue(value, value.artifactType.concat('->').concat(value.artifactName)));
+ this.modalServiceNg2.closeCurrentModal();
+ this.isLoading = false;
+ }
+
+ loadDeployedArtifacts() {
+ this.topologyTemplateService.getArtifactsByType(this.componentMetaData.componentType, this.componentMetaData.uniqueId, ArtifactGroupType.DEPLOYMENT)
+ .subscribe(response => {
+ let artifactsDeployment = response.deploymentArtifacts;
+ if (artifactsDeployment) {
+ let deploymentArtifactsFound = <ArtifactModel[]>_.values(artifactsDeployment)
+ deploymentArtifactsFound.forEach(value => {
+ this.deploymentArtifactsFilePath.push(new DropdownValue(value, value.artifactType.concat('->').concat(value.artifactName)));
+ });
+ }
+ }, error => {
+ this.Notification.error({
+ message: 'Failed to Load the Deployed Artifacts:' + error,
+ title: 'Failure'
+ });
+ });
+ }
+
+ loadToscaArtifacts() {
+ this.toscaArtifactService.getToscaArtifacts(this.componentMetaData.model).subscribe(response => {
+ if (response) {
+ let toscaArtifactsFound = <ToscaArtifactModel[]>_.values(response);
+ toscaArtifactsFound.forEach(value => this.toscaArtifactTypes.push(new DropdownValue(value, value.type)));
+ }
+ }, error => {
+ this.Notification.error({
+ message: 'Failed to Load Tosca Artifacts:' + error,
+ title: 'Failure'
+ });
});
- }}, error => {
- this.Notification.error({
- message: 'Failed to Load the Deployed Artifacts:' + error,
- title: 'Failure'
- });
- });
- }
-
- loadToscaArtifacts() {
- this.toscaArtifactService.getToscaArtifacts(this.componentMetaData.model).subscribe(response => {
- if (response) {
- let toscaArtifactsFound = <ToscaArtifactModel[]>_.values(response);
- toscaArtifactsFound.forEach(value => this.toscaArtifactTypes.push(new DropdownValue(value, value.type)));
- }
- }, error => {
- this.Notification.error({
- message: 'Failed to Load Tosca Artifacts:' + error,
- title: 'Failure'
- });
- });
- }
+ }
}
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.html b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.html
index 7a73a5babc..5f02bc2bf7 100644
--- a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.html
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.html
@@ -25,19 +25,30 @@
<div class="side-by-side">
<div class="form-item">
- <sdc-input
+ <sdc-dropdown
label="{{ 'OPERATION_INTERFACE_TYPE' | translate }}"
- [(value)]="interfaceType"
- [disabled]=!isViewOnly>
- </sdc-input>
+ [required]="true"
+ [testId]="'interface-name'"
+ [selectedOption]="selectedInterfaceType"
+ [placeHolder]="'Select...'"
+ [disabled]="isViewOnly || isEdit"
+ (changed)="onSelectInterface($event)"
+ [options]="interfaceTypeOptions">
+ </sdc-dropdown>
</div>
<div class="form-item">
- <sdc-input
+ <sdc-dropdown
+ #interfaceOperationDropDown
label="{{ 'OPERATION_NAME' | translate }}"
- [(value)]="operationToUpdate.name"
- [disabled]=!isViewOnly>
- </sdc-input>
+ [required]="true"
+ [testId]="'operation-name'"
+ [selectedOption]="selectedInterfaceOperation"
+ [placeHolder]="'Select...'"
+ [disabled]="isViewOnly || isEdit"
+ (changed)="onSelectOperation($event)"
+ [options]="interfaceOperationOptions">
+ </sdc-dropdown>
</div>
</div>
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.ts
index 059708592e..5cc7f691aa 100644
--- a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.ts
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.ts
@@ -18,17 +18,18 @@
* SPDX-License-Identifier: Apache-2.0
* ============LICENSE_END=========================================================
*/
-
-import {Component, EventEmitter, Input, Output} from '@angular/core';
+import {Component, EventEmitter, Input, Output, ViewChild} from '@angular/core';
import {UIInterfaceModel} from "../interface-operations.component";
import {InputOperationParameter, InterfaceOperationModel, IOperationParamsList} from "../../../../../models/interfaceOperation";
import {TranslateService} from "../../../../shared/translator/translate.service";
-import {IDropDownOption} from "onap-ui-angular/dist/form-elements/dropdown/dropdown-models";
import {DropdownValue} from "../../../../components/ui/form-components/dropdown/ui-element-dropdown.component";
import {ArtifactModel} from "../../../../../models/artifacts";
import {PropertyBEModel} from "../../../../../models/properties-inputs/property-be-model";
import {PropertyParamRowComponent} from "./property-param-row/property-param-row.component";
import {PropertyFEModel} from "../../../../../models/properties-inputs/property-fe-model";
+import {IDropDownOption} from 'onap-ui-angular';
+import {ComponentServiceNg2} from "../../../../services/component-services/component.service";
+import {DropDownComponent} from "onap-ui-angular/dist/form-elements/dropdown/dropdown.component";
import {DataTypeService} from "../../../../services/data-type.service";
import {Observable} from "rxjs/Observable";
import {DataTypeModel} from "../../../../../models/data-types";
@@ -43,13 +44,15 @@ export class InterfaceOperationHandlerComponent {
@Input() private modelName: string;
@Output('propertyChanged') emitter: EventEmitter<PropertyFEModel> = new EventEmitter<PropertyFEModel>();
+ @ViewChild('interfaceOperationDropDown') interfaceOperationDropDown: DropDownComponent;
+
input: {
toscaArtifactTypes: Array<DropdownValue>;
selectedInterface: UIInterfaceModel;
selectedInterfaceOperation: InterfaceOperationModel;
validityChangedCallback: Function;
isViewOnly: boolean;
- interfaceTypesMap: Map<string, string[]>;
+ isEdit: boolean;
};
dataTypeMap$: Observable<Map<string, DataTypeModel>>;
@@ -64,10 +67,13 @@ export class InterfaceOperationHandlerComponent {
isLoading: boolean = false;
readonly: boolean;
isViewOnly: boolean;
+ isEdit: boolean;
interfaceTypes: Array<DropdownValue> = [];
- interfaceOperations: Array<DropdownValue> = [];
-
- interfaceTypesMap: Map<string, string[]>;
+ interfaceTypeOptions: Array<DropDownOption> = [];
+ selectedInterfaceType: DropDownOption = undefined;
+ interfaceOperationMap: Map<string, Array<string>> = new Map<string, Array<string>>();
+ interfaceOperationOptions: Array<DropDownOption> = [];
+ selectedInterfaceOperation: DropDownOption = undefined;
toscaArtifactTypeSelected: string;
toscaArtifactTypeProperties: Array<PropertyBEModel> = [];
@@ -80,7 +86,7 @@ export class InterfaceOperationHandlerComponent {
propertyValueValid: boolean = true;
inputTypeOptions: any[];
- constructor(private dataTypeService: DataTypeService) {
+ constructor(private dataTypeService: DataTypeService, private componentServiceNg2: ComponentServiceNg2) {
this.dataTypeMap$ = new Observable<Map<string, DataTypeModel>>(subscriber => {
this.dataTypeService.findAllDataTypesByModel(this.modelName)
.then((dataTypesMap: Map<string, DataTypeModel>) => {
@@ -95,6 +101,7 @@ export class InterfaceOperationHandlerComponent {
ngOnInit() {
this.isViewOnly = this.input.isViewOnly;
+ this.isEdit = this.input.isEdit;
this.interfaceType = this.input.selectedInterface.type;
this.operationToUpdate = this.input.selectedInterfaceOperation;
this.operationToUpdate.interfaceId = this.input.selectedInterface.uniqueId;
@@ -113,18 +120,56 @@ export class InterfaceOperationHandlerComponent {
}
this.inputs = Array.from(this.operationToUpdate.inputs.listToscaDataDefinition);
- this.interfaceTypesMap = this.input.interfaceTypesMap;
- this.loadInterfaceTypesAndOperations();
this.removeImplementationQuote();
this.validityChanged();
this.loadInterfaceOperationImplementation();
+ this.loadInterfaceType();
+ }
+
+ private loadInterfaceType() {
+ this.componentServiceNg2.getInterfaceTypesByModel(undefined)
+ .subscribe(response => {
+ if (response) {
+ this.interfaceOperationMap = new Map<string, Array<string>>();
+ for (const interfaceType of Object.keys(response).sort()) {
+ const operationList = response[interfaceType];
+ operationList.sort();
+ this.interfaceOperationMap.set(interfaceType, operationList);
+ const operationDropDownOption: DropDownOption = new DropDownOption(interfaceType);
+ this.interfaceTypeOptions.push(operationDropDownOption);
+ if (this.interfaceType == interfaceType) {
+ this.selectedInterfaceType = operationDropDownOption;
+ }
+ }
+ this.loadInterfaceTypeOperations();
+ }
+ });
+ }
+
+ loadInterfaceTypeOperations() {
+ this.interfaceOperationOptions = new Array<DropDownOption>();
+ const interfaceOperationList = this.interfaceOperationMap.get(this.interfaceType);
+
+ if (interfaceOperationList) {
+ interfaceOperationList.forEach(operationName => {
+ const operationOption = new DropDownOption(operationName, operationName);
+ this.interfaceOperationOptions.push(operationOption);
+ if (this.operationToUpdate.name == operationName) {
+ this.selectedInterfaceOperation = operationOption
+ }
+ });
+ }
+
+ this.interfaceOperationDropDown.allOptions = this.interfaceOperationOptions;
}
private loadInterfaceOperationImplementation() {
this.toscaArtifactTypes = this.input.toscaArtifactTypes;
- this.artifactVersion = this.operationToUpdate.implementation.artifactVersion;
- this.artifactName = this.operationToUpdate.implementation.artifactName;
- this.toscaArtifactTypeProperties = this.operationToUpdate.implementation.properties;
+ if (this.operationToUpdate.implementation) {
+ this.artifactVersion = this.operationToUpdate.implementation.artifactVersion;
+ this.artifactName = this.operationToUpdate.implementation.artifactName;
+ this.toscaArtifactTypeProperties = this.operationToUpdate.implementation.properties;
+ }
this.artifactTypeProperties = this.convertArtifactsPropertiesToInput();
this.getArtifactTypesSelected();
}
@@ -348,11 +393,43 @@ export class InterfaceOperationHandlerComponent {
return inputList;
}
- private loadInterfaceTypesAndOperations() {
- console.log("loadInterfaceTypesAndOperations ", this.interfaceTypesMap.keys());
+ onSelectInterface(dropDownOption: DropDownOption) {
+ if (dropDownOption) {
+ this.setInterfaceType(dropDownOption);
+ } else {
+ this.setInterfaceType(undefined);
+ }
+ this.setInterfaceOperation(undefined);
+ this.interfaceOperationDropDown.selectOption({} as IDropDownOption);
+ this.loadInterfaceTypeOperations();
+ }
- Array.from(this.interfaceTypesMap.keys()).forEach(value => this.interfaceTypes.push(new DropdownValue(value, value)));
- console.log("loadInterfaceTypesAndOperations interfaceType ", this.interfaceTypes);
+ onSelectOperation(dropDownOption: DropDownOption) {
+ if (this.selectedInterfaceType && dropDownOption) {
+ this.setInterfaceOperation(dropDownOption);
+ }
}
+ private setInterfaceType(dropDownOption: DropDownOption) {
+ this.selectedInterfaceType = dropDownOption ? dropDownOption : undefined;
+ this.interfaceType = dropDownOption ? dropDownOption.value : undefined;
+ this.operationToUpdate.interfaceType = dropDownOption ? dropDownOption.value : undefined;
+ this.operationToUpdate.interfaceId = dropDownOption ? dropDownOption.value : undefined;
+ }
+
+ private setInterfaceOperation(dropDownOption: DropDownOption) {
+ this.operationToUpdate.name = dropDownOption ? dropDownOption.value : undefined;
+ this.operationToUpdate.operationType = dropDownOption ? dropDownOption.value : undefined;
+ this.selectedInterfaceOperation = dropDownOption ? dropDownOption : undefined;
+ }
}
+
+class DropDownOption implements IDropDownOption {
+ value: string;
+ label: string;
+
+ constructor(value: string, label?: string) {
+ this.value = value;
+ this.label = label || value;
+ }
+} \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.module.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.module.ts
index b212eec034..bcc797c64c 100644
--- a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.module.ts
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.module.ts
@@ -25,16 +25,14 @@ import {CommonModule} from "@angular/common";
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
import {FormElementsModule} from "app/ng2/components/ui/form-components/form-elements.module";
import {TranslateModule} from "app/ng2/shared/translator/translate.module";
-
-
+import {AddInputComponent} from './add-input/add-input.component';
+import {InputListComponent} from './input-list/input-list.component';
+import {InputListItemComponent} from './input-list/input-list-item/input-list-item.component';
+import {PropertyParamRowComponent} from "./property-param-row/property-param-row.component";
+import {InterfaceOperationHandlerComponent} from "./interface-operation-handler.component";
import {SdcUiComponentsModule} from "onap-ui-angular/dist";
-import { InterfaceOperationHandlerComponent } from "app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component";
-import { PropertyParamRowComponent } from "app/ng2/pages/composition/interface-operatons/operation-creator/property-param-row/property-param-row.component";
-import { UiElementsModule } from "app/ng2/components/ui/ui-elements.module";
-import { PropertyTableModule } from "app/ng2/components/logic/properties-table/property-table.module";
-import { AddInputComponent } from './add-input/add-input.component';
-import { InputListComponent } from './input-list/input-list.component';
-import { InputListItemComponent } from './input-list/input-list-item/input-list-item.component';
+import {UiElementsModule} from "app/ng2/components/ui/ui-elements.module";
+import {PropertyTableModule} from "app/ng2/components/logic/properties-table/property-table.module";
@NgModule({
declarations: [
diff --git a/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.html b/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.html
index 25ccf111a1..f3043ffebd 100644
--- a/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.html
+++ b/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.html
@@ -24,6 +24,13 @@
<div>{{ 'INTERFACE_DATA_EMPTY' | translate }}</div>
</div>
</div>
+ <div
+ class="top-add-btn add-btn"
+ [ngClass]="{'disabled': readonly}"
+ data-tests-id="add-operation"
+ (click)="onSelectInterfaceOperation(undefined, undefined)">
+ {{ 'INTERFACE_ADD_OPERATION' | translate }}
+ </div>
<div class="operation-list">
<div *ngIf="!isInterfaceListEmpty()">
<div class="expand-collapse" *ngIf="isOperationListEmpty()">
@@ -38,11 +45,11 @@
</a>
</div>
- <div class="interface-row" *ngFor="let interface of interfaces">
- <div class="interface-accordion" (click)="interface.toggleCollapse()">
+ <div class="interface-row" *ngFor="let interface1 of interfaces">
+ <div class="interface-accordion" (click)="interface1.toggleCollapse()">
<span
class="chevron-container"
- [ngClass]="{'isCollapsed': interface.isCollapsed}"
+ [ngClass]="{'isCollapsed': interface1.isCollapsed}"
*ngIf="isOperationListEmpty()">
<svg-icon
name="caret1-down-o"
@@ -50,10 +57,10 @@
size="small">
</svg-icon>
</span>
- <span class="interface-name">{{interface.type}}</span>
+ <span class="interface-name">{{interface1.type}}</span>
</div>
- <div class="generic-table" *ngIf="!interface.isCollapsed && isOperationListEmpty()">
+ <div class="generic-table" *ngIf="!interface1.isCollapsed && isOperationListEmpty()">
<div class="header-row table-row">
<span
class="cell header-cell field-name header-name">
@@ -63,20 +70,14 @@
{{ 'INTERFACE_HEADER_DESCRIPTION' | translate }}
</span>
</div>
-
- <div class="data-row" *ngFor="let operation of interface.operations"
- (click)="onSelectInterfaceOperation(interface, operation)">
- <span
- class="cell field-name">
- {{operation.name}}
- </span>
- <span class="cell field-description"
- [ngClass]="{'collapsed': operation.isCollapsed}">
- {{operation.getDescriptionEllipsis()}}
+ <div class="data-row" *ngFor="let operation of interface1.operations" (click)="onSelectInterfaceOperation(interface1, operation)">
+ <span class="cell field-name">{{operation.name}}</span>
+ <span class="cell field-description" [ngClass]="{'collapsed': operation.isCollapsed}">
+ {{operation.getDescriptionEllipsis()}}
<span class="more-or-less link" (click)="operation.toggleCollapsed($event)">
- {{!operation.isEllipsis ? '' : operation.isCollapsed ? 'More' : 'Less'}}
+ {{!operation.isEllipsis ? '' : operation.isCollapsed ? 'More' : 'Less'}}
+ </span>
</span>
- </span>
</div>
</div>
</div>
diff --git a/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.ts b/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.ts
index 8dd17f60e2..c9a6d07057 100644
--- a/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.ts
+++ b/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.ts
@@ -20,26 +20,27 @@
*/
import {Component, ComponentRef, Inject, Input} from '@angular/core';
import {Component as IComponent} from 'app/models/components/component';
+import {WorkflowServiceNg2} from 'app/ng2/services/workflow.service';
import {ISdcConfig, SdcConfigToken} from "app/ng2/config/sdc-config.config";
import {TranslateService} from "app/ng2/shared/translator/translate.service";
-
+import {IModalButtonComponent, SdcUiServices} from 'onap-ui-angular';
import {ModalComponent} from 'app/ng2/components/ui/modal/modal.component';
+
import {ModalService} from 'app/ng2/services/modal.service';
-import {ButtonModel, CapabilitiesGroup, ModalModel, OperationModel} from 'app/models';
+import {
+ ButtonModel,
+ CapabilitiesGroup,
+ InputBEModel,
+ InterfaceModel,
+ ModalModel,
+ OperationModel,
+ WORKFLOW_ASSOCIATION_OPTIONS
+} from 'app/models';
import {ComponentServiceNg2} from 'app/ng2/services/component-services/component.service';
-
-import {SdcUiServices} from 'onap-ui-angular';
import {TopologyTemplateService} from "../../services/component-services/topology-template.service";
-import {
- ComponentInterfaceDefinitionModel,
- InputOperationParameter,
- InterfaceOperationModel
-} from "../../../models/interfaceOperation";
-import {
- PropertyParamRowComponent
-} from "../composition/interface-operatons/operation-creator/property-param-row/property-param-row.component";
+import {InterfaceOperationModel} from "../../../models/interfaceOperation";
import {
InterfaceOperationHandlerComponent
} from "../composition/interface-operatons/operation-creator/interface-operation-handler.component";
@@ -49,15 +50,17 @@ import {
import {ToscaArtifactModel} from "../../../models/toscaArtifact";
import {ToscaArtifactService} from "../../services/tosca-artifact.service";
import {
- UIInterfaceOperationModel
-} from "../composition/interface-operatons/interface-operations.component";
+ InterfaceOperationComponent
+} from "../interface-operation/interface-operation.page.component";
+import {Observable} from "rxjs/Observable";
+import {PluginsService} from 'app/ng2/services/plugins.service';
export class UIOperationModel extends OperationModel {
isCollapsed: boolean = true;
isEllipsis: boolean;
MAX_LENGTH = 75;
- constructor(operation: UIOperationModel) {
+ constructor(operation: OperationModel) {
super(operation);
if (!operation.description) {
@@ -109,15 +112,14 @@ class ModalTranslation {
}
}
-export class UIInterfaceModel extends ComponentInterfaceDefinitionModel {
+export class UIInterfaceModel extends InterfaceModel {
isCollapsed: boolean = false;
constructor(interf?: any) {
super(interf);
- this.operations = _.map(
- this.operations,
- (operation) => new UIInterfaceOperationModel(operation)
- );
+ if (this.operations) {
+ this.operations = this.operations.map((operation) => new UIOperationModel(operation));
+ }
}
toggleCollapse() {
@@ -130,16 +132,14 @@ export class UIInterfaceModel extends ComponentInterfaceDefinitionModel {
selector: 'interface-definition',
templateUrl: './interface-definition.page.component.html',
styleUrls: ['interface-definition.page.component.less'],
- providers: [ModalService, TranslateService]
+ providers: [ModalService, TranslateService, InterfaceOperationComponent]
})
-
export class InterfaceDefinitionComponent {
modalInstance: ComponentRef<ModalComponent>;
interfaces: UIInterfaceModel[];
- inputs: Array<InputOperationParameter> = [];
+ inputs: InputBEModel[];
- properties: Array<PropertyParamRowComponent> = [];
deploymentArtifactsFilePath: Array<DropdownValue> = [];
toscaArtifactTypes: Array<DropdownValue> = [];
@@ -153,6 +153,10 @@ export class InterfaceDefinitionComponent {
capabilities: CapabilitiesGroup;
isViewOnly: boolean;
+ openOperation: OperationModel;
+ enableWorkflowAssociation: boolean;
+ workflowIsOnline: boolean;
+
@Input() component: IComponent;
@Input() readonly: boolean;
@Input() enableMenuItems: Function;
@@ -167,19 +171,52 @@ export class InterfaceDefinitionComponent {
private modalServiceNg2: ModalService,
private modalServiceSdcUI: SdcUiServices.ModalService,
private topologyTemplateService: TopologyTemplateService,
- private toscaArtifactService: ToscaArtifactService
+ private toscaArtifactService: ToscaArtifactService,
+ private ComponentServiceNg2: ComponentServiceNg2,
+ private WorkflowServiceNg2: WorkflowServiceNg2,
+ private ModalServiceSdcUI: SdcUiServices.ModalService,
+ private PluginsService: PluginsService
) {
this.modalTranslation = new ModalTranslation(translateService);
this.interfaceTypesMap = new Map<string, string[]>();
}
ngOnInit(): void {
- console.info("this.component.lifecycleState ", this.component.lifecycleState);
- if (this.component) {
- this.isViewOnly = this.component.componentMetadata.isComponentDataEditable();
- this.initInterfaceDefinition();
- this.loadInterfaceTypes();
- this.loadToscaArtifacts();
+ this.isLoading = true;
+ this.interfaces = [];
+ this.workflowIsOnline = !_.isUndefined(this.PluginsService.getPluginByStateUrl('workflowDesigner'));
+ Observable.forkJoin(
+ this.ComponentServiceNg2.getInterfaceOperations(this.component),
+ this.ComponentServiceNg2.getComponentInputs(this.component),
+ this.ComponentServiceNg2.getInterfaceTypes(this.component),
+ this.ComponentServiceNg2.getCapabilitiesAndRequirements(this.component.componentType, this.component.uniqueId)
+ ).subscribe((response: any[]) => {
+ const callback = (workflows) => {
+ this.isLoading = false;
+ this.initInterfaces(response[0].interfaces);
+ this.sortInterfaces();
+ this.inputs = response[1].inputs;
+ this.interfaceTypes = response[2];
+ this.workflows = (workflows.items) ? workflows.items : workflows;
+ this.capabilities = response[3].capabilities;
+ };
+ if (this.enableWorkflowAssociation && this.workflowIsOnline) {
+ this.WorkflowServiceNg2.getWorkflows().subscribe(
+ callback,
+ (err) => {
+ this.workflowIsOnline = false;
+ callback([]);
+ }
+ );
+ } else {
+ callback([]);
+ }
+ });
+ }
+
+ initInterfaces(interfaces: InterfaceModel[]): void {
+ if (interfaces) {
+ this.interfaces = interfaces.map((interf) => new UIInterfaceModel(interf));
}
}
@@ -190,15 +227,18 @@ export class InterfaceDefinitionComponent {
private disableSaveButton = (): boolean => {
return this.isViewOnly ||
(this.isEnableAddArtifactImplementation()
- && (!this.modalInstance.instance.dynamicContent.instance.toscaArtifactTypeSelected ||
- !this.modalInstance.instance.dynamicContent.instance.artifactName)
+ && (!this.modalInstance.instance.dynamicContent.toscaArtifactTypeSelected ||
+ !this.modalInstance.instance.dynamicContent.artifactName)
);
}
onSelectInterfaceOperation(interfaceModel: UIInterfaceModel, operation: InterfaceOperationModel) {
+ const isEdit = operation !== undefined;
const cancelButton: ButtonModel = new ButtonModel(this.modalTranslation.CANCEL_BUTTON, 'outline white', this.cancelAndCloseModal);
- const saveButton: ButtonModel = new ButtonModel(this.modalTranslation.SAVE_BUTTON, 'blue', () =>
- this.updateOperation(), this.disableSaveButton);
+ const saveButton: ButtonModel = new ButtonModel(this.modalTranslation.SAVE_BUTTON, 'blue',
+ () => isEdit ? this.updateOperation() : this.createOperationCallback(),
+ this.disableSaveButton
+ );
const interfaceDataModal: ModalModel =
new ModalModel('l', this.modalTranslation.EDIT_TITLE, '', [saveButton, cancelButton], 'custom');
this.modalInstance = this.modalServiceNg2.createCustomModal(interfaceDataModal);
@@ -209,12 +249,14 @@ export class InterfaceDefinitionComponent {
{
deploymentArtifactsFilePath: this.deploymentArtifactsFilePath,
toscaArtifactTypes: this.toscaArtifactTypes,
- selectedInterface: interfaceModel,
- selectedInterfaceOperation: operation,
+ selectedInterface: interfaceModel ? interfaceModel : new UIInterfaceModel(),
+ selectedInterfaceOperation: operation ? operation : new InterfaceOperationModel(),
validityChangedCallback: this.disableSaveButton,
isViewOnly: this.isViewOnly,
+ isEdit: isEdit,
interfaceTypesMap: this.interfaceTypesMap,
- });
+ }
+ );
this.modalInstance.instance.open();
}
@@ -239,6 +281,27 @@ export class InterfaceDefinitionComponent {
this.modalServiceNg2.closeCurrentModal();
}
+ private createOperationCallback(): void {
+ const operationToUpdate = this.modalInstance.instance.dynamicContent.instance.operationToUpdate;
+ console.log('createOperationCallback', operationToUpdate);
+ console.log('this.component', this.component);
+ this.componentServiceNg2.createComponentInterfaceOperation(this.component.uniqueId, this.component.getTypeUrl(), operationToUpdate)
+ .subscribe((newOperation: InterfaceOperationModel) => {
+ const foundInterface = this.interfaces.find(value => value.type === newOperation.interfaceType);
+ if (foundInterface) {
+ foundInterface.operations.push(new UIOperationModel(new OperationModel(newOperation)));
+ } else {
+ const uiInterfaceModel = new UIInterfaceModel();
+ uiInterfaceModel.type = newOperation.interfaceType;
+ uiInterfaceModel.uniqueId = newOperation.interfaceType;
+ uiInterfaceModel.operations = [];
+ uiInterfaceModel.operations.push(new UIOperationModel(new OperationModel(newOperation)));
+ this.interfaces.push(uiInterfaceModel);
+ }
+ });
+ this.modalServiceNg2.closeCurrentModal();
+ }
+
private handleEnableAddArtifactImplementation = (newOperation: InterfaceOperationModel): InterfaceOperationModel => {
if (!this.isEnableAddArtifactImplementation()) {
newOperation.implementation.artifactType = null;
@@ -248,7 +311,7 @@ export class InterfaceDefinitionComponent {
}
private isEnableAddArtifactImplementation = (): boolean => {
- return this.modalInstance.instance.dynamicContent.instance.enableAddArtifactImplementation;
+ return this.modalInstance.instance.dynamicContent.enableAddArtifactImplementation;
}
private initInterfaceDefinition() {
@@ -257,7 +320,7 @@ export class InterfaceDefinitionComponent {
this.topologyTemplateService.getComponentInterfaceOperations(this.component.componentType, this.component.uniqueId)
.subscribe((response) => {
if (response.interfaces) {
- this.interfaces = _.map(response.interfaces, (interfaceModel) => new UIInterfaceModel(interfaceModel));
+ this.interfaces = response.interfaces.map((interfaceModel) => new UIInterfaceModel(interfaceModel));
}
this.isLoading = false;
});
@@ -301,11 +364,11 @@ export class InterfaceDefinitionComponent {
}
isAllCollapsed(): boolean {
- return _.every(this.interfaces, (interfaceData) => interfaceData.isCollapsed);
+ return this.interfaces.every((interfaceData) => interfaceData.isCollapsed);
}
isAllExpanded(): boolean {
- return _.every(this.interfaces, (interfaceData) => !interfaceData.isCollapsed);
+ return this.interfaces.every((interfaceData) => !interfaceData.isCollapsed);
}
isInterfaceListEmpty(): boolean {
@@ -313,8 +376,92 @@ export class InterfaceDefinitionComponent {
}
isOperationListEmpty(): boolean {
- return _.filter(this.interfaces, (interfaceData) =>
- interfaceData.operations && interfaceData.operations.length > 0).length > 0;
+ return this.interfaces.filter((interfaceData) => interfaceData.operations && interfaceData.operations.length > 0).length > 0;
+ }
+
+ onRemoveOperation = (event: Event, operation: OperationModel): void => {
+ event.stopPropagation();
+
+ const deleteButton: IModalButtonComponent = {
+ id: 'deleteButton',
+ text: this.modalTranslation.DELETE_BUTTON,
+ type: 'primary',
+ size: 'small',
+ closeModal: true,
+ callback: () => {
+ this.ComponentServiceNg2
+ .deleteInterfaceOperation(this.component, operation)
+ .subscribe(() => {
+ const curInterf = this.interfaces.find((interf) => interf.type === operation.interfaceType);
+ const index = curInterf.operations.findIndex((el) => el.uniqueId === operation.uniqueId);
+ curInterf.operations.splice(index, 1);
+ if (!curInterf.operations.length) {
+ const interfIndex = this.interfaces.findIndex((interf) => interf.type === operation.interfaceType);
+ this.interfaces.splice(interfIndex, 1);
+ }
+ });
+ }
+ };
+
+ const cancelButton: IModalButtonComponent = {
+ id: 'cancelButton',
+ text: this.modalTranslation.CANCEL_BUTTON,
+ type: 'secondary',
+ size: 'small',
+ closeModal: true,
+ callback: () => {
+ this.openOperation = null;
+ },
+ };
+
+ this.ModalServiceSdcUI.openWarningModal(
+ this.modalTranslation.DELETE_TITLE,
+ this.modalTranslation.deleteText(operation.name),
+ 'deleteOperationModal',
+ [deleteButton, cancelButton],
+ );
+ }
+
+ private createOperation = (operation: OperationModel): void => {
+ this.ComponentServiceNg2.createInterfaceOperation(this.component, operation).subscribe((response: OperationModel) => {
+ this.openOperation = null;
+
+ let curInterf = this.interfaces.find((interf) => interf.type === operation.interfaceType);
+
+ if (!curInterf) {
+ curInterf = new UIInterfaceModel({
+ type: response.interfaceType,
+ uniqueId: response.uniqueId,
+ operations: []
+ });
+ this.interfaces.push(curInterf);
+ }
+
+ const newOpModel = new UIOperationModel(response);
+ curInterf.operations.push(newOpModel);
+ this.sortInterfaces();
+
+ if (operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.EXTERNAL && operation.artifactData) {
+ this.ComponentServiceNg2.uploadInterfaceOperationArtifact(this.component, newOpModel, operation).subscribe();
+ } else if (response.workflowId && operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.EXISTING) {
+ this.WorkflowServiceNg2.associateWorkflowArtifact(this.component, response).subscribe();
+ } else if (operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.NEW) {
+ this.$state.go('workspace.plugins', {path: 'workflowDesigner'});
+ }
+ });
+ }
+
+ private enableOrDisableSaveButton = (shouldEnable: boolean): void => {
+ const saveButton = this.modalInstance.instance.dynamicContent.getButtonById('saveButton');
+ saveButton.disabled = !shouldEnable;
+ }
+
+ private sortInterfaces(): void {
+ this.interfaces = this.interfaces.filter((interf) => interf.operations && interf.operations.length > 0); // remove empty interfaces
+ this.interfaces.sort((a, b) => a.type.localeCompare(b.type)); // sort interfaces alphabetically
+ this.interfaces.forEach((interf) => {
+ interf.operations.sort((a, b) => a.name.localeCompare(b.name)); // sort operations alphabetically
+ });
}
}
diff --git a/catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/operation-creator-interface-definition.component.html b/catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/operation-creator-interface-definition.component.html
new file mode 100644
index 0000000000..687c79fe86
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/operation-creator-interface-definition.component.html
@@ -0,0 +1,211 @@
+<!--
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2022 Nordix Foundation. 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=========================================================
+-->
+
+<div class="operation-creator-interface-definition">
+ <loader [display]="isLoading" [size]="'large'" [relative]="true"></loader>
+
+ <form class="w-sdc-form">
+
+ <div class="side-by-side">
+ <div class="form-item">
+ <sdc-dropdown
+ label="{{ 'OPERATION_INTERFACE_TYPE' | translate }}"
+ [required]="true"
+ testId="interface-name"
+ [selectedOption]="getSelectedDropdown(interfaceNames, operation.interfaceType)"
+ placeHolder="Select..."
+ [disabled]="readonly"
+ (changed)="onSelectInterface($event)"
+ [options]="interfaceNames">
+ </sdc-dropdown>
+ </div>
+
+ <div class="form-item" *ngIf="!isInterfaceOther()">
+ <sdc-dropdown
+ #operationNamesDropdown
+ label="{{ 'OPERATION_NAME' | translate }}"
+ [required]="true"
+ testId="operation-name"
+ [selectedOption]="getSelectedDropdown(operationNames, operation.name)"
+ placeHolder="Select..."
+ [disabled]="readonly"
+ (changed)="onSelectOperationName($event)"
+ [options]="operationNames">
+ </sdc-dropdown>
+ </div>
+ <div class="form-item" *ngIf="isInterfaceOther()">
+ <sdc-input
+ label="{{ 'OPERATION_NAME' | translate }}"
+ [(value)]="operation.name"
+ testId="operationName"
+ (valueChange)="onChangeName()"
+ [disabled]="readonly">
+ </sdc-input>
+ </div>
+
+ </div>
+
+ <div class="i-sdc-form-item sdc-input">
+ <span class="sdc-input__label">{{ 'OPERATION_DESCRIPTION' | translate }}</span>
+ <textarea
+ data-tests-id="operationDescription"
+ rows="2"
+ name="description"
+ [(ngModel)]="descriptionValue"
+ [ngClass]="{'disabled': readonly}">
+ </textarea>
+ </div>
+
+ <div class="side-by-side" *ngIf="enableWorkflowAssociation">
+ <div class="form-item">
+ <sdc-dropdown
+ #workflowAssignmentDropdown
+ label="{{ 'OPERATION_WORKFLOW_ASSIGNMENT' | translate }}"
+ placeHolder="Select..."
+ testId="association-type"
+ [selectedOption]="toDropDownOption(workflowAssociationType)"
+ [options]="associationOptions"
+ (changed)="toggleAssociateWorkflow($event)"
+ [disabled]="readonly">
+ </sdc-dropdown>
+ </div>
+
+ <div class="form-item" *ngIf="!isUsingExistingWF() && !isUsingExternalWF()"></div>
+
+ <div
+ *ngIf="isUsingExternalWF()"
+ class="form-item sdc-input">
+ <label class="sdc-input__label">{{ 'OPERATION_ARTIFACT' | translate }}</label>
+ <div class="i-sdc-form-item i-sdc-form-file-upload">
+ <span
+ class="i-sdc-form-file-name"
+ data-tests-id="artifactFilename">
+ {{ operation.artifactFileName }}
+ </span>
+ <div
+ *ngIf="operation.artifactFileName"
+ class="i-sdc-form-file-upload-x-btn"
+ data-tests-id="clearArtifact"
+ (click)="onChangeArtifactFile({ target: {} })"></div>
+ <label
+ class="i-sdc-form-file-upload-label"
+ [ngClass]="{'disabled': readonly}">
+ <input
+ type="file"
+ base-sixty-four-input
+ maxsize="10240"
+ data-tests-id="artifactUpload"
+ (change)="onChangeArtifactFile($event)"
+ (click)="$event.target.value = ''"
+ />
+ <div class="file-upload-browse-btn">Browse</div>
+ </label>
+ </div>
+ </div>
+
+ <div class="form-item sdc-input" *ngIf="isUsingExistingWF()">
+ <label class="sdc-input__label required">{{ 'OPERATION_WORKFLOW' | translate }}
+ <span class="archive-warning" *ngIf="workflowIsOnline && archivedWorkflowId === operation.workflowId">({{ 'OPERATION_WORKFLOW_ARCHIVED' | translate }})</span>
+ <span class="no-workflow-warning" *ngIf="!workflowIsOnline">{{ 'OPERATION_NO_WORKFLOW_CONNECTION' | translate }}</span>
+ <span class="no-workflow-warning" *ngIf="workflowIsOnline && !workflows.length">{{ 'OPERATION_NO_WORKFLOW_ERROR' | translate }}</span>
+ </label>
+ <sdc-dropdown
+ placeHolder="Select..."
+ testId="associated-workflow"
+ [selectedOption]="getSelectedDropdown(workflows, operation.workflowId)"
+ [options]="workflows"
+ (changed)="onSelectWorkflow($event)"
+ [disabled]="readonly || !workflows.length || !workflowIsOnline">
+ </sdc-dropdown>
+ </div>
+
+ <div class="form-item sdc-input" *ngIf="isUsingExistingWF()">
+ <sdc-dropdown
+ *ngIf="workflowIsOnline && workflows.length"
+ label="{{ 'OPERATION_WORKFLOW_VERSION' | translate }}"
+ testId="associated-workflow-version"
+ [selectedOption]="getSelectedDropdown(workflowVersions, operation.workflowVersionId)"
+ [options]="workflowVersions"
+ (changed)="changeWorkflowVersion($event)"
+ [disabled]="!operation.workflowId || archivedWorkflowId === operation.workflowId || readonly">
+ </sdc-dropdown>
+ </div>
+ </div>
+
+ <div class="separator-buttons">
+ <tabs #propertyInputTabs tabStyle="round-tabs" (tabChanged)="tabChanged($event)" [hideIndicationOnTabChange]="true">
+ <tab tabTitle="Inputs"></tab>
+ <tab tabTitle="Outputs"></tab>
+ </tabs>
+ <a
+ class="add-param-link add-btn"
+ *ngIf="!isUsingExistingWF() && !readonly"
+ data-tests-id="addInputParameter"
+ [ngClass]="{'disabled':!canAdd()}"
+ (click)="addParam()">{{ currentTab === TYPE_INPUT ? 'Add Input' : 'Add Output' }}</a>
+ </div>
+
+ <div class="generic-table">
+ <div class="header-row table-row">
+ <span class="cell header-cell field-name">{{ 'OPERATION_PARAM_NAME' | translate }}</span>
+ <span class="cell header-cell field-type">{{ 'OPERATION_PARAM_TYPE' | translate }}</span>
+ <span class="cell header-cell field-property" *ngIf="currentTab == TYPE_INPUT">
+ {{ 'OPERATION_PARAM_PROPERTY' | translate }}
+ <span
+ *ngIf="!isUsingExistingWF()"
+ class="sprite-new info-icon"
+ tooltip="{{propertyTooltipText}}"
+ tooltipDelay="0">
+ </span>
+ </span>
+ <span class="cell header-cell field-mandatory" *ngIf="!isUsingExistingWF()">{{ 'OPERATION_PARAM_MANDATORY' | translate }}</span>
+ <span class="cell header-cell remove" *ngIf="!isUsingExistingWF() && !readonly">●●●</span>
+ </div>
+
+ <div class="empty-msg data-row" *ngIf="tableParameters.length === 0">
+ <div>{{ 'EMPTY_PARAM_TABLE_HEADER' | translate }}</div>
+ <div *ngIf="isUsingExistingWF() && !operation.workflowVersionId">
+ <div *ngIf="workflows.length">
+ <span class="bold-message">{{ 'EMPTY_PARAM_TABLE_NO_SELECTED_WORKFLOW_1' | translate }}</span>
+ <span>{{ 'EMPTY_PARAM_TABLE_NO_SELECTED_WORKFLOW_2' | translate }}</span>
+ </div>
+ <div *ngIf="!workflows.length">
+ Only <span class="bold-message">certified</span> workflow versions can be assigned to an operation
+ </div>
+ </div>
+ </div>
+
+ <param-row
+ *ngFor="let param of tableParameters"
+ class="data-row"
+ [isInputParam]="currentTab === TYPE_INPUT"
+ [isAssociateWorkflow]="isUsingExistingWF()"
+ [param]="param"
+ [inputProps]="inputProperties"
+ [capabilitiesProps]="componentCapabilities"
+ [operationOutputs]="operationOutputs"
+ [onRemoveParam]="onRemoveParam"
+ [readonly]="readonly"
+ [validityChanged]="validityChanged">
+ </param-row>
+ </div>
+
+ </form>
+</div>
diff --git a/catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/operation-creator-interface-definition.component.less b/catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/operation-creator-interface-definition.component.less
new file mode 100644
index 0000000000..0afaa47ca3
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/operation-creator-interface-definition.component.less
@@ -0,0 +1,200 @@
+/*
+* ============LICENSE_START=======================================================
+* SDC
+* ================================================================================
+* Copyright (C) 2022 Nordix Foundation. 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.
+*
+* SPDX-License-Identifier: Apache-2.0
+* ============LICENSE_END=========================================================
+*/
+@import '../../../../../assets/styles/variables.less';
+@import '../../../../../assets/styles/override.less';
+
+.operation-creator-interface-definition {
+ font-family: @font-opensans-regular;
+ user-select: none;
+ padding-top: 12px;
+ padding-bottom: 20px;
+
+ .i-sdc-form-label {
+ font-size: 12px;
+ }
+
+ .w-sdc-form .i-sdc-form-item {
+ margin-bottom: 15px;
+ }
+
+ textarea {
+ min-height: 74px;
+ margin-bottom: 18px;
+ }
+
+ /deep/ .sdc-dropdown__component-container {
+ .sdc-dropdown__header {
+ height: 38px;
+ line-height: 35px;
+
+ svg-icon {
+ margin: 13px 6px;
+ }
+ }
+ }
+
+ /deep/ .sdc-input {
+ margin-bottom: 0;
+
+ .sdc-input__input {
+ height: 38px;
+ }
+ }
+
+ .side-by-side {
+ display: flex;
+
+ .form-item {
+ flex: 1;
+
+ &:first-child {
+ margin-right: 14px;
+ flex-basis: 37%;
+ flex-grow: 0;
+ flex-shrink: 0;
+ }
+
+ &:nth-child(3) {
+ margin-left: 14px;
+ flex: 0.4;
+ }
+
+ .i-sdc-form-file-upload {
+ height: 37px;
+ margin-bottom: 0;
+
+ .i-sdc-form-file-name {
+ padding: 8px 10px;
+ }
+
+ .i-sdc-form-file-upload-x-btn {
+ top: 13px;
+ }
+
+ .file-upload-browse-btn {
+ height: 100%;
+ padding: 7px 6px;
+ z-index: 1;
+ }
+ }
+
+ }
+ }
+
+ .archive-warning {
+ font-family: @font-opensans-bold;
+ color: @main_color_i;
+ }
+
+ .no-workflow-warning {
+ font-family: @font-opensans-bold;
+ color: @sdcui_color_red;
+ float: right;
+ }
+
+ .input-param-title {
+ font-size: 16px;
+ text-transform: uppercase;
+ }
+
+ .separator-buttons {
+ display: flex;
+ justify-content: space-between;
+ margin-top: 10px;
+
+ .add-param-link {
+ &:not(.disabled):hover {
+ cursor: pointer;
+ }
+ }
+
+ .tab {
+ width: 84px;
+ text-align: center;
+ }
+ }
+
+ .generic-table {
+ max-height: 244px;
+ min-height: 91px;
+ background: @main_color_p;
+
+ .header-row .header-cell {
+ .info-icon {
+ float: right;
+ position: relative;
+ top: 2px;
+ }
+ /deep/ .tooltip-inner {
+ padding: 2px;
+ max-width: 270px;
+ font-size: 11px;
+ }
+ &.remove {
+ padding: 10px;
+ font-size: 10px;
+ }
+ }
+
+ .data-row {
+ &.empty-msg {
+ .bold-message {
+ font-family: @font-opensans-bold;
+ }
+
+ :first-child {
+ &:not(:only-child) {
+ margin: 6px 0;
+ }
+ }
+
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ padding: 14px;
+ }
+ }
+
+ /deep/ .cell {
+ &.field-name, &.field-type {
+ flex: 1;
+ }
+
+ &.field-property {
+ &, &:last-child {
+ flex: 1;
+ }
+ }
+
+ &.field-mandatory {
+ flex: 0.5;
+ text-align: center;
+ }
+
+ &.remove {
+ min-width: 40px;
+ max-width: 40px;
+ }
+ }
+
+ }
+}
diff --git a/catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/operation-creator-interface-definition.component.ts b/catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/operation-creator-interface-definition.component.ts
new file mode 100644
index 0000000000..1897e3190d
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/operation-creator-interface-definition.component.ts
@@ -0,0 +1,582 @@
+/*
+* ============LICENSE_START=======================================================
+* SDC
+* ================================================================================
+* Copyright (C) 2022 Nordix Foundation. 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.
+*
+* SPDX-License-Identifier: Apache-2.0
+* ============LICENSE_END=========================================================
+*/
+import * as _ from "lodash";
+import {Component, ViewChild} from '@angular/core';
+
+import {TranslateService} from "app/ng2/shared/translator/translate.service";
+import {WorkflowServiceNg2} from 'app/ng2/services/workflow.service';
+import {
+ Capability,
+ InputBEModel,
+ InterfaceModel,
+ OperationModel,
+ OperationParameter,
+ WORKFLOW_ASSOCIATION_OPTIONS
+} from 'app/models';
+
+import {Tabs} from "app/ng2/components/ui/tabs/tabs.component";
+import {
+ DropdownValue
+} from "app/ng2/components/ui/form-components/dropdown/ui-element-dropdown.component";
+import {IDropDownOption} from 'onap-ui-angular';
+import {DropDownComponent} from "onap-ui-angular/dist/components";
+import {DROPDOWN_OPTION_TYPE} from "app/utils";
+import {Subscription} from "rxjs";
+
+export class DropDownOption implements IDropDownOption {
+ value: string;
+ label: string;
+
+ constructor(value: string, label?: string) {
+ this.value = value;
+ this.label = label || value;
+ }
+}
+
+class TypedDropDownOption extends DropDownOption {
+ type: string;
+
+ constructor(value: string, label?: string, type?: string) {
+ super(value, label);
+ this.type = type;
+ }
+}
+
+export interface OperationCreatorInput {
+ allWorkflows: Array<any>,
+ inputOperation: OperationModel,
+ interfaces: Array<InterfaceModel>,
+ inputProperties: Array<InputBEModel>,
+ enableWorkflowAssociation: boolean,
+ readonly: boolean,
+ interfaceTypes: { [interfaceType: string]: Array<string> },
+ validityChangedCallback: Function,
+ workflowIsOnline: boolean,
+ capabilities: Array<Capability>
+}
+
+@Component({
+ selector: 'operation-creator-interface-definition',
+ templateUrl: './operation-creator-interface-definition.component.html',
+ styleUrls: ['./operation-creator-interface-definition.component.less'],
+ providers: [TranslateService]
+})
+
+export class OperationCreatorInterfaceDefinitionComponent implements OperationCreatorInput {
+
+ input: OperationCreatorInput;
+ inputOperation: OperationModel;
+ interfaces: Array<InterfaceModel>;
+ operation: OperationModel;
+ interfaceNames: Array<TypedDropDownOption> = [];
+ interfaceTypes: { [interfaceType: string]: Array<string> };
+ operationNames: Array<TypedDropDownOption> = [];
+ validityChangedCallback: Function;
+ capabilities: Array<Capability>;
+
+ allWorkflows: Array<any>;
+ workflows: Array<DropdownValue> = [];
+ workflowVersions: Array<DropdownValue> = [];
+ inputProperties: Array<InputBEModel> = [];
+ archivedWorkflowId: string = '&';
+
+ inputParameters: Array<OperationParameter> = [];
+ noAssignInputParameters: Array<OperationParameter> = [];
+ assignInputParameters: { [key: string]: { [key: string]: Array<OperationParameter>; }; } = {};
+
+ outputParameters: Array<OperationParameter> = [];
+ noAssignOutputParameters: Array<OperationParameter> = [];
+ assignOutputParameters: { [key: string]: { [key: string]: Array<OperationParameter>; }; } = {};
+ componentCapabilities: Array<Capability> = [];
+
+ tableParameters: Array<OperationParameter> = [];
+ operationOutputs: Array<OperationModel> = [];
+
+ associationOptions: Array<DropdownValue> = [];
+ workflowAssociationType: string;
+
+ enableWorkflowAssociation: boolean;
+ workflowIsOnline: boolean;
+ isEditMode: boolean = false;
+ isLoading: boolean = false;
+ readonly: boolean;
+
+ propertyTooltipText: String;
+
+ TYPE_INPUT = 'Inputs';
+ TYPE_OUTPUT = 'Outputs';
+
+ INTERFACE_OTHER_HEADER = 'Local Interfaces';
+ INTERFACE_OTHER = 'Local';
+
+ @ViewChild('propertyInputTabs') propertyInputTabs: Tabs;
+ @ViewChild('operationNamesDropdown') operationNamesDropdown: DropDownComponent;
+ @ViewChild('workflowAssignmentDropdown') workflowAssignmentDropdown: DropDownComponent;
+ currentTab: String;
+
+ constructor(private workflowServiceNg2: WorkflowServiceNg2, private translateService: TranslateService) {
+ this.translateService.languageChangedObservable.subscribe(lang => {
+ this.propertyTooltipText = this.translateService.translate("OPERATION_PROPERTY_TOOLTIP_TEXT");
+
+ this.associationOptions = [
+ new DropDownOption(WORKFLOW_ASSOCIATION_OPTIONS.EXTERNAL, this.translateService.translate("EXTERNAL_WORKFLOW_ASSOCIATION")),
+ new DropDownOption(WORKFLOW_ASSOCIATION_OPTIONS.EXISTING, this.translateService.translate("EXISTING_WORKFLOW_ASSOCIATION")),
+ ];
+
+ this.workflowAssociationType = this.operation.workflowAssociationType;
+ });
+
+ this.currentTab = this.TYPE_INPUT;
+ }
+
+ createInterfaceDropdown(type: string) {
+ let label = type;
+ const lastDot = label.lastIndexOf('.');
+ if (lastDot > -1) {
+ label = label.substr(lastDot + 1);
+ }
+ return new TypedDropDownOption(type, label);
+ }
+
+ ngOnInit() {
+ this.interfaceNames = _.map(
+ _.keys(this.interfaceTypes),
+ type => this.createInterfaceDropdown(type)
+ );
+ this.interfaceNames.unshift(new TypedDropDownOption('Existing Interfaces', 'Existing Interfaces', DROPDOWN_OPTION_TYPE.HEADER));
+ this.interfaceNames = this.interfaceNames.concat([
+ new TypedDropDownOption(' ', ' ', DROPDOWN_OPTION_TYPE.HORIZONTAL_LINE),
+ new TypedDropDownOption(this.INTERFACE_OTHER_HEADER, this.INTERFACE_OTHER_HEADER, DROPDOWN_OPTION_TYPE.HEADER),
+ new TypedDropDownOption(this.INTERFACE_OTHER)
+ ]);
+ const inputOperation = this.inputOperation;
+ this.operation = new OperationModel(inputOperation || {});
+
+ this.operationOutputs = _.reduce(
+ this.interfaces,
+ (acc: Array<OperationModel>, interf) => [
+ ...acc,
+ ..._.filter(
+ interf.operations,
+ op => op.uniqueId !== this.operation.uniqueId
+ ),
+ ],
+ []);
+
+ if (this.enableWorkflowAssociation) {
+ if (this.workflowIsOnline) {
+ this.workflows = _.map(
+ _.filter(
+ this.allWorkflows,
+ (workflow: any) => {
+ if (workflow.archiving === this.workflowServiceNg2.WF_STATE_ACTIVE) {
+ return true;
+ }
+ if (workflow.archiving === this.workflowServiceNg2.WF_STATE_ARCHIVED &&
+ workflow.id === this.operation.workflowId) {
+ this.archivedWorkflowId = workflow.id;
+ return true;
+ }
+ return false;
+ }
+ ),
+ (workflow: any) => new DropdownValue(workflow.id, workflow.name)
+ );
+ } else {
+ this.workflows = [];
+ }
+ }
+ this.reconstructOperation();
+ this.filterCapabilities();
+ this.validityChanged();
+ this.updateTable();
+ }
+
+ ngAfterViewInit() {
+ if (this.workflowAssignmentDropdown) {
+ this.workflowAssignmentDropdown.allOptions = this.associationOptions && this.associationOptions.length ?
+ this.associationOptions :
+ [
+ new DropDownOption(WORKFLOW_ASSOCIATION_OPTIONS.EXTERNAL, this.translateService.translate("EXTERNAL_WORKFLOW_ASSOCIATION")),
+ new DropDownOption(WORKFLOW_ASSOCIATION_OPTIONS.EXISTING, this.translateService.translate("EXISTING_WORKFLOW_ASSOCIATION")),
+ ];
+ }
+ }
+
+ reconstructOperation = () => {
+
+ const buildAndUpdate = () => {
+ this.buildParams();
+ this.updateTable();
+ };
+
+ const inputOperation = this.inputOperation;
+ if (inputOperation) {
+ this.onSelectInterface(new DropDownOption(this.operation.interfaceType));
+
+ if (this.enableWorkflowAssociation && inputOperation.workflowVersionId && this.isUsingExistingWF(inputOperation)) {
+ this.assignInputParameters[this.operation.workflowId] = {[inputOperation.workflowVersionId]: []};
+ this.assignOutputParameters[this.operation.workflowId] = {[inputOperation.workflowVersionId]: []};
+ this.inputParameters = this.assignInputParameters[this.operation.workflowId][this.operation.workflowVersionId];
+ this.outputParameters = this.assignOutputParameters[this.operation.workflowId][this.operation.workflowVersionId];
+
+ const sub = this.onSelectWorkflow(new DropDownOption(inputOperation.workflowId), inputOperation.workflowVersionId);
+ if (sub) {
+ sub.add(() => {
+ buildAndUpdate();
+ this.operation.workflowVersionId = '-1';
+ setTimeout(() => this.operation.workflowVersionId = this.inputOperation.workflowVersionId);
+ });
+ } else {
+ buildAndUpdate();
+ }
+ } else {
+ this.inputParameters = this.noAssignInputParameters;
+ this.outputParameters = this.noAssignOutputParameters;
+ buildAndUpdate();
+ }
+
+ if (inputOperation.uniqueId) {
+ this.isEditMode = true;
+ }
+ }
+
+ }
+
+ filterCapabilities() {
+ this.componentCapabilities = _.filter(this.capabilities, (cap: Capability) => cap.properties);
+ }
+
+ buildParams = () => {
+
+ if (this.inputOperation.outputs) {
+ this.currentTab = this.TYPE_OUTPUT;
+ this.updateTable();
+ _.forEach(
+ [...this.inputOperation.outputs.listToscaDataDefinition].sort((a, b) => a.name.localeCompare(b.name)),
+ (output: OperationParameter) => {
+ this.addParam({...output, required: Boolean(output.required)});
+ }
+ );
+ }
+
+ this.currentTab = this.TYPE_INPUT;
+ this.updateTable();
+ if (this.inputOperation.inputs) {
+ _.forEach(
+ [...this.inputOperation.inputs.listToscaDataDefinition].sort((a, b) => a.name.localeCompare(b.name)),
+ (input: OperationParameter) => {
+ this.addParam({...input, required: Boolean(input.required)});
+ }
+ );
+ }
+
+ }
+
+ isInterfaceOther(): boolean {
+ return this.operation.interfaceType === this.INTERFACE_OTHER;
+ }
+
+ onSelectInterface(interf: IDropDownOption) {
+ if (interf && this.operation.interfaceType !== interf.value) {
+ this.operation.name = null;
+ }
+ this.operation.interfaceType = interf && interf.value;
+ this.operationNames = !this.operation.interfaceType ? [] : (
+ _.map(
+ this.interfaceTypes[this.operation.interfaceType],
+ name => {
+ const curInterf = _.find(
+ this.interfaces,
+ interf => interf.type === this.operation.interfaceType
+ );
+ const existingOp = _.find(
+ curInterf && curInterf.operations || [],
+ op => op.name === name
+ );
+ const ddType = (existingOp && existingOp.uniqueId !== this.operation.uniqueId) ? DROPDOWN_OPTION_TYPE.HORIZONTAL_LINE : DROPDOWN_OPTION_TYPE.SIMPLE;
+ return new TypedDropDownOption(name, name, ddType);
+ }
+ )
+ );
+ if (this.operationNamesDropdown) {
+ this.operationNamesDropdown.allOptions = <IDropDownOption[]>this.operationNames;
+ }
+ this.validityChanged();
+ }
+
+ onSelectOperationName(name: IDropDownOption) {
+ if (name) {
+ this.operation.name = name.value;
+ }
+ this.validityChanged();
+ }
+
+ onChangeName() {
+ this.validityChanged();
+ }
+
+ get descriptionValue() {
+ return this.operation.description;
+ }
+
+ set descriptionValue(v) {
+ this.operation.description = v || null;
+ this.validityChanged();
+ }
+
+ onSelectWorkflow(workflowId: DropDownOption, selectedVersionId?: string): Subscription {
+
+ if (_.isUndefined(workflowId) || !this.workflowIsOnline) {
+ return;
+ }
+
+ if (this.operation.workflowId === workflowId.value && !selectedVersionId) {
+ return;
+ }
+
+ this.operation.workflowId = workflowId.value;
+ if (!this.assignInputParameters[this.operation.workflowId]) {
+ this.assignInputParameters[this.operation.workflowId] = {};
+ this.assignOutputParameters[this.operation.workflowId] = {};
+ }
+ this.operation.workflowName = workflowId.label;
+ if (!this.assignInputParameters[this.operation.workflowName]) {
+ this.assignInputParameters[this.operation.workflowName] = {};
+ this.assignOutputParameters[this.operation.workflowName] = {};
+ }
+
+ this.isLoading = true;
+ this.validityChanged();
+ return this.workflowServiceNg2.getWorkflowVersions(this.operation.workflowId).subscribe((versions: Array<any>) => {
+ this.isLoading = false;
+
+ this.workflowVersions = _.map(
+ _.filter(
+ versions, version => version.state === this.workflowServiceNg2.VERSION_STATE_CERTIFIED
+ ).sort((a, b) => a.name.localeCompare(b.name)),
+ (version: any) => {
+ if (!this.assignInputParameters[this.operation.workflowId][version.id] && version.id !== selectedVersionId) {
+ this.assignInputParameters[this.operation.workflowId][version.id] = _.map(version.inputs, (input: any) => {
+ return new OperationParameter({
+ ...input,
+ type: input.type.toLowerCase(),
+ required: Boolean(input.mandatory)
+ });
+ })
+ .sort((a, b) => a.name.localeCompare(b.name));
+
+ this.assignOutputParameters[this.operation.workflowId][version.id] = _.map(version.outputs, (output: any) => {
+ return new OperationParameter({
+ ...output,
+ type: output.type.toLowerCase(),
+ required: Boolean(output.mandatory)
+ });
+ })
+ .sort((a, b) => a.name.localeCompare(b.name));
+ }
+ return new DropdownValue(version.id, `V ${version.name}`);
+ }
+ );
+ if (!selectedVersionId && this.workflowVersions.length) {
+ this.operation.workflowVersionId = _.last(this.workflowVersions).value;
+ this.operation.workflowVersion = _.last(this.workflowVersions).label;
+ }
+
+ this.changeWorkflowVersion(new DropDownOption(this.operation.workflowVersionId));
+ this.validityChanged();
+ });
+
+ }
+
+ changeWorkflowVersion(versionId: DropDownOption) {
+
+ if (_.isUndefined(versionId) || !this.workflowIsOnline) {
+ return;
+ }
+
+ this.operation.workflowVersionId = versionId.value;
+ this.inputParameters = this.assignInputParameters[this.operation.workflowId][this.operation.workflowVersionId];
+ this.outputParameters = this.assignOutputParameters[this.operation.workflowId][this.operation.workflowVersionId];
+ this.updateTable();
+ this.validityChanged();
+
+ }
+
+ toggleAssociateWorkflow(type: DropDownOption) {
+
+ if (_.isUndefined(type)) {
+ return;
+ }
+
+ this.operation.workflowAssociationType = type.value;
+ this.workflowAssociationType = this.operation.workflowAssociationType;
+
+ if (!this.isUsingExistingWF()) {
+ this.inputParameters = this.noAssignInputParameters;
+ this.outputParameters = this.noAssignOutputParameters;
+ } else {
+ if (!this.operation.workflowId || !this.operation.workflowVersionId) {
+ this.inputParameters = [];
+ this.outputParameters = [];
+ } else {
+ this.inputParameters = this.assignInputParameters[this.operation.workflowId][this.operation.workflowVersionId];
+ this.outputParameters = this.assignOutputParameters[this.operation.workflowId][this.operation.workflowVersionId];
+ }
+ }
+
+ this.updateTable();
+ this.validityChanged();
+
+ }
+
+ onChangeArtifactFile(e: any) {
+ const file = e.target.files && e.target.files[0];
+ this.operation.artifactFileName = file && file.name;
+
+ if (!this.operation.artifactFileName) {
+ this.operation.artifactData = null;
+ this.validityChanged();
+ return;
+ }
+
+ const reader = new FileReader();
+ reader.onloadend = () => {
+ this.isLoading = false;
+ const result = <String>reader.result;
+ this.operation.artifactData = result.substring(result.indexOf(',') + 1);
+ this.validityChanged();
+ }
+
+ this.isLoading = true;
+ reader.readAsDataURL(file);
+ }
+
+ tabChanged = (event) => {
+
+ this.currentTab = event.title;
+ this.updateTable();
+
+ }
+
+ updateTable() {
+
+ switch (this.currentTab) {
+ case this.TYPE_INPUT:
+ this.tableParameters = this.inputParameters;
+ break;
+ case this.TYPE_OUTPUT:
+ this.tableParameters = this.outputParameters;
+ break;
+ }
+
+ }
+
+ addParam(param?: OperationParameter): void {
+ this.tableParameters.push(new OperationParameter(param || {required: false}));
+ this.validityChanged();
+ }
+
+ canAdd = (): boolean => {
+
+ let valid = true;
+ if (this.currentTab === this.TYPE_INPUT) {
+ _.forEach(this.inputParameters, param => {
+ if (!param.name || !param.inputId) {
+ valid = false;
+ }
+ });
+ } else {
+ _.forEach(this.outputParameters, param => {
+ if (!param.name || !param.type) {
+ valid = false;
+ }
+ });
+ }
+
+ return valid;
+
+ }
+
+ isParamsValid = (): boolean => {
+
+ let valid = true;
+ _.forEach(this.inputParameters, param => {
+ if (!param.name || !param.inputId) {
+ valid = false;
+ }
+ });
+ _.forEach(this.outputParameters, param => {
+ if (!param.name || !param.type) {
+ valid = false;
+ }
+ });
+
+ return valid;
+
+ }
+
+ onRemoveParam = (param: OperationParameter): void => {
+ let index = _.indexOf(this.tableParameters, param);
+ this.tableParameters.splice(index, 1);
+ this.validityChanged();
+ }
+
+ createParamLists = () => {
+ this.operation.createInputsList(this.inputParameters);
+ this.operation.createOutputsList(this.outputParameters);
+ }
+
+ isUsingExistingWF = (operation?: OperationModel): boolean => {
+ operation = operation || this.operation;
+ return operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.EXISTING;
+ }
+
+ isUsingExternalWF = (operation?: OperationModel): boolean => {
+ operation = operation || this.operation;
+ return operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.EXTERNAL;
+ }
+
+ shouldCreateWF = (operation?: OperationModel): boolean => {
+ operation = operation || this.operation;
+ return operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.NEW;
+ }
+
+ checkFormValidForSubmit = (): boolean => {
+ return this.operation.name &&
+ (!this.isUsingExistingWF() || this.operation.workflowVersionId) &&
+ this.isParamsValid();
+ }
+
+ validityChanged = () => {
+ let validState = this.checkFormValidForSubmit();
+ this.validityChangedCallback(validState);
+ }
+
+ getSelectedDropdown(options: DropdownValue[], selectedValue: string): DropdownValue {
+ const selectedDropdown = _.find(options, (option) => option.value === selectedValue);
+ return selectedDropdown || this.toDropDownOption(null);
+ }
+
+ toDropDownOption(val: string) {
+ return {value: val, label: val};
+ }
+}
diff --git a/catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/operation-creator-interface-definition.module.ts b/catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/operation-creator-interface-definition.module.ts
new file mode 100644
index 0000000000..7f75240735
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/operation-creator-interface-definition.module.ts
@@ -0,0 +1,52 @@
+/*
+* ============LICENSE_START=======================================================
+* SDC
+* ================================================================================
+* Copyright (C) 2022 Nordix Foundation. 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.
+*
+* SPDX-License-Identifier: Apache-2.0
+* ============LICENSE_END=========================================================
+*/
+import {NgModule} from "@angular/core";
+import {ParamRowComponent} from "./param-row/param-row.component";
+import {OperationCreatorInterfaceDefinitionComponent} from "./operation-creator-interface-definition.component";
+import {UiElementsModule} from "../../../components/ui/ui-elements.module";
+import {TranslateModule} from "../../../shared/translator/translate.module";
+import {SdcUiComponentsModule} from "onap-ui-angular";
+import {CommonModule} from "@angular/common";
+import {FormsModule} from "@angular/forms";
+import {FormElementsModule} from "../../../components/ui/form-components/form-elements.module";
+
+@NgModule({
+ declarations: [
+ OperationCreatorInterfaceDefinitionComponent,
+ ParamRowComponent
+ ],
+ imports: [
+ CommonModule,
+ SdcUiComponentsModule,
+ FormsModule,
+ FormElementsModule,
+ TranslateModule,
+ UiElementsModule
+ ],
+ exports: [],
+ entryComponents: [
+ OperationCreatorInterfaceDefinitionComponent
+ ],
+ providers: []
+})
+
+export class OperationCreatorInterfaceDefinitionModule {
+}
diff --git a/catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/param-row/param-row.component.html b/catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/param-row/param-row.component.html
new file mode 100644
index 0000000000..1ed0375a16
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/param-row/param-row.component.html
@@ -0,0 +1,100 @@
+<!--
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2022 Nordix Foundation. 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=========================================================
+-->
+
+<div class="cell field-name">
+ <ui-element-input
+ *ngIf="!isAssociateWorkflow"
+ [testId]="'param-name-' + (param.name || 'unnamed')"
+ [(value)]="param.name"
+ (valueChange)="onChangeName()"
+ [readonly]="readonly">
+ </ui-element-input>
+ <span *ngIf="isAssociateWorkflow">{{param.name}}</span>
+</div>
+
+<div class="cell field-type">
+ <ui-element-dropdown
+ *ngIf="!isAssociateWorkflow"
+ [testId]="'param-type-' + (param.name || 'unnamed')"
+ [values]="propTypeEnum"
+ [(value)]="param.type"
+ (valueChange)="onChangeType()"
+ [readonly]="readonly">
+ </ui-element-dropdown>
+ <span *ngIf="isAssociateWorkflow">{{param.type}}</span>
+</div>
+
+<div class="cell field-property" *ngIf="isInputParam">
+ <select
+ *ngIf="filteredInputProps.length || operationOutputCats.length || !isAssociateWorkflow"
+ [(ngModel)]="param.inputId"
+ (change)="onChangeProperty($event)"
+ [ngClass]="{'disabled': readonly}"
+ [attr.data-tests-id]="'value-param-property-' + (param.name || 'unnamed')">
+ <option
+ *ngFor="let prop of filteredInputProps"
+ [ngValue]="prop.value">
+ {{prop.label}}
+ </option>
+ <optgroup
+ *ngFor="let operation of operationOutputCats"
+ label="{{operation.operationName}}">
+ <option
+ *ngFor="let output of operation.outputs"
+ [ngValue]="output.value">
+ {{output.label}}
+ </option>
+ </optgroup>
+ <optgroup
+ *ngFor="let cap of filteredCapabilitiesProps"
+ label="{{cap.capabilityName}}">
+ <option
+ *ngFor="let prop of cap.properties"
+ [ngValue]="prop.value">
+ {{prop.label}}
+ </option>
+ </optgroup>
+ </select>
+ <span
+ *ngIf="!filteredInputProps.length && !operationOutputCats.length && isAssociateWorkflow"
+ class="no-properties-error">
+ {{ 'PARAM_NONE_OF_TYPE' | translate }}
+ </span>
+</div>
+
+<div class="cell field-mandatory" *ngIf="!isAssociateWorkflow">
+ <checkbox
+ *ngIf="!isAssociateWorkflow"
+ [attr.data-tests-id]="'param-mandatory-' + (param.name || 'unnamed')"
+ [(checked)]="param.required"
+ [ngClass]="{'disabled':readonly}">
+ </checkbox>
+</div>
+
+<div class="cell remove" *ngIf="!isAssociateWorkflow && !readonly">
+ <svg-icon
+ name="trash-o"
+ mode="info"
+ size="small"
+ [attr.data-tests-id]="'param-remove-' + (param.name || 'unnamed')"
+ (click)="onRemoveParam(param)"
+ [clickable]="true">
+ </svg-icon>
+</div>
diff --git a/catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/param-row/param-row.component.less b/catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/param-row/param-row.component.less
new file mode 100644
index 0000000000..d616bad1f9
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/param-row/param-row.component.less
@@ -0,0 +1,73 @@
+/*
+* ============LICENSE_START=======================================================
+* SDC
+* ================================================================================
+* Copyright (C) 2022 Nordix Foundation. 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.
+*
+* SPDX-License-Identifier: Apache-2.0
+* ============LICENSE_END=========================================================
+*/
+@import '../../../../../../assets/styles/variables.less';
+
+.remove {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ svg-icon {
+ position: relative;
+ right: -3px;
+
+ &:hover {
+ cursor: pointer;
+ }
+ }
+}
+
+
+.cell {
+ min-height: 50px;
+ padding: 10px;
+ display: flex;
+ align-items: center;
+
+ > * {
+ flex-basis: 100%;
+ }
+
+ /deep/ select {
+ height: 30px;
+ }
+
+ input {
+ height: 30px;
+ border: none;
+ padding-left: 10px;
+ }
+
+ select {
+ width: 100%;
+ }
+
+ &.field-property {
+ &:last-child {
+ flex: 1;
+ }
+
+ .no-properties-error {
+ color: @func_color_q;
+ font-style: italic;
+ }
+ }
+}
diff --git a/catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/param-row/param-row.component.ts b/catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/param-row/param-row.component.ts
new file mode 100644
index 0000000000..43760ba117
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/interface-definition/operation-creator/param-row/param-row.component.ts
@@ -0,0 +1,257 @@
+/*
+* ============LICENSE_START=======================================================
+* SDC
+* ================================================================================
+* Copyright (C) 2022 Nordix Foundation. 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.
+*
+* SPDX-License-Identifier: Apache-2.0
+* ============LICENSE_END=========================================================
+*/
+import {Component, Input} from '@angular/core';
+import {DataTypeService} from "app/ng2/services/data-type.service";
+import {
+ Capability,
+ DataTypeModel,
+ InputBEModel,
+ OperationModel,
+ OperationParameter
+} from 'app/models';
+import {
+ DropdownValue
+} from "app/ng2/components/ui/form-components/dropdown/ui-element-dropdown.component";
+import {WorkspaceService} from "../../../workspace/workspace.service";
+
+class DropdownValueType extends DropdownValue {
+ type: string;
+
+ constructor(value: string, label: string, type?: string) {
+ super(value, label);
+ if (type) {
+ this.type = type;
+ }
+ }
+}
+
+@Component({
+ selector: 'param-row',
+ templateUrl: './param-row.component.html',
+ styleUrls: ['./param-row.component.less']
+})
+
+export class ParamRowComponent {
+ @Input() param: OperationParameter;
+ @Input() inputProps: Array<InputBEModel>;
+ @Input() operationOutputs: Array<OperationModel>;
+ @Input() capabilitiesProps: Array<Capability>;
+ @Input() onRemoveParam: Function;
+ @Input() isAssociateWorkflow: boolean;
+ @Input() readonly: boolean;
+ @Input() isInputParam: boolean;
+ @Input() validityChanged: Function;
+
+ propTypeEnum: Array<string> = [];
+ operationOutputCats: Array<{ operationName: string, outputs: Array<DropdownValueType> }> = [];
+ filteredInputProps: Array<DropdownValue> = [];
+ filteredCapabilitiesProps: Array<{ capabilityName: string, properties: Array<DropdownValueType> }> = [];
+
+ constructor(private dataTypeService: DataTypeService, protected workspaceService: WorkspaceService) {
+ }
+
+ ngOnInit() {
+ if (this.isInputParam) {
+ this.propTypeEnum = _.uniq(
+ _.map(
+ _.concat(
+ this.getPrimitiveSubtypes(),
+ _.reduce(
+ this.operationOutputs,
+ (acc, op) => [...acc, ...op.outputs.listToscaDataDefinition],
+ []),
+ _.reduce(
+ this.capabilitiesProps,
+ (acc, capab) => [...acc, ...capab.properties],
+ [])
+ ),
+ prop => prop.type
+ )
+ );
+ } else {
+ const dataTypes: Array<DataTypeModel> = _.toArray(this.dataTypeService.getDataTypeByModel(this.workspaceService.metadata.model));
+ this.propTypeEnum = _.concat(
+ _.map(
+ _.filter(
+ dataTypes,
+ type => this.isTypePrimitive(type.name)
+ ),
+ type => type.name
+ ).sort(),
+ _.map(
+ _.filter(
+ dataTypes,
+ type => !this.isTypePrimitive(type.name)
+ ),
+ type => type.name
+ ).sort()
+ );
+ }
+
+ this.onChangeType();
+ this.validityChanged();
+ }
+
+ onChangeName() {
+ this.validityChanged();
+ }
+
+ onChangeType() {
+ if (!this.isInputParam) {
+ this.validityChanged();
+ return;
+ }
+
+ this.filteredInputProps = _.map(
+ _.filter(
+ this.getPrimitiveSubtypes(),
+ prop => !this.param.type || prop.type === this.param.type
+ ),
+ prop => new DropdownValue(prop.uniqueId, prop.name)
+ );
+ this.filteredInputProps.unshift(new DropdownValue("", ""));
+
+ this.operationOutputCats = _.filter(
+ _.map(
+ this.operationOutputs,
+ op => {
+ return {
+ operationName: `${op.displayType()}.${op.name}`,
+ outputs: _.map(
+ _.filter(op.outputs.listToscaDataDefinition, output => !this.param.type || output.type === this.param.type),
+ output => new DropdownValueType(
+ `${op.interfaceType}.${op.name}.${output.name}`,
+ output.name,
+ output.type
+ )
+ )
+ };
+ }
+ ),
+ category => category.outputs.length > 0
+ );
+
+ this.filteredCapabilitiesProps = _.filter(
+ _.map(
+ this.capabilitiesProps,
+ cap => {
+ return {
+ capabilityName: cap.name,
+ properties: _.map(
+ _.filter(cap.properties, prop => !this.param.type || prop.type === this.param.type),
+ prop => new DropdownValueType(
+ prop.uniqueId,
+ prop.name,
+ prop.type
+ )
+ )
+ };
+ }
+ ),
+ capability => capability.properties.length > 0
+ );
+
+ if (this.param.inputId) {
+ const selProp = this.getSelectedProp();
+ if (selProp && selProp.type === this.param.type) {
+ this.param.inputId = '-1';
+ setTimeout(() => this.param.inputId = selProp.uniqueId || selProp.value);
+ } else {
+ this.param.inputId = null;
+ }
+ }
+
+ this.validityChanged();
+ }
+
+ onChangeProperty() {
+ const newProp = this.getSelectedProp();
+
+ if (!this.param.type) {
+ this.param.type = newProp.type;
+ this.onChangeType();
+ }
+
+ if (!this.param.name) {
+ this.param.name = newProp.name || newProp.label;
+ }
+
+ this.validityChanged();
+ }
+
+ getPrimitiveSubtypes(): Array<InputBEModel> {
+ const flattenedProps: Array<any> = [];
+ const dataTypes = this.dataTypeService.getDataTypeByModel(this.workspaceService.metadata.model);
+
+ _.forEach(this.inputProps, prop => {
+ const type: DataTypeModel = _.find(
+ _.toArray(dataTypes),
+ (type: DataTypeModel) => type.name === prop.type
+ );
+ flattenedProps.push(prop);
+ if (!type) {
+ console.error('Could not find prop in dataTypes: ', prop);
+ } else {
+ if (type.properties) {
+ _.forEach(type.properties, subType => {
+ if (this.isTypePrimitive(subType.type)) {
+ flattenedProps.push({
+ type: subType.type,
+ name: `${prop.name}.${subType.name}`,
+ uniqueId: `${prop.uniqueId}.${subType.name}`
+ });
+ }
+ });
+ }
+ }
+ });
+
+ return flattenedProps;
+ }
+
+ getSelectedProp() {
+ return _.find(
+ this.getPrimitiveSubtypes(),
+ prop => this.param.inputId === prop.uniqueId
+ ) || _.find(
+ _.reduce(
+ this.operationOutputCats,
+ (acc, cat) => [...acc, ...cat.outputs],
+ []),
+ (out: DropdownValueType) => this.param.inputId === out.value
+ ) || _.find(
+ _.reduce(
+ this.filteredCapabilitiesProps,
+ (acc, cap) => [...acc, ...cap.properties],
+ []),
+ (prop: DropdownValueType) => this.param.inputId === prop.value
+ );
+ }
+
+ isTypePrimitive(type: string): boolean {
+ return (
+ type === 'string' ||
+ type === 'integer' ||
+ type === 'float' ||
+ type === 'boolean'
+ );
+ }
+}
diff --git a/catalog-ui/src/app/ng2/pages/interface-operation/interface-operation.page.component.ts b/catalog-ui/src/app/ng2/pages/interface-operation/interface-operation.page.component.ts
index 4f93e727ec..75a31b96c0 100644
--- a/catalog-ui/src/app/ng2/pages/interface-operation/interface-operation.page.component.ts
+++ b/catalog-ui/src/app/ng2/pages/interface-operation/interface-operation.page.component.ts
@@ -1,36 +1,52 @@
+/*
+* ============LICENSE_START=======================================================
+* SDC
+* ================================================================================
+* Copyright (C) 2022 Nordix Foundation. 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.
+*
+* SPDX-License-Identifier: Apache-2.0
+* ============LICENSE_END=========================================================
+*/
import * as _ from "lodash";
-import { Component, Input, Inject } from '@angular/core';
-import {Component as IComponent } from 'app/models/components/component';
+import {Component, Inject, Input} from '@angular/core';
+import {Component as IComponent} from 'app/models/components/component';
-import { SdcConfigToken, ISdcConfig } from "app/ng2/config/sdc-config.config";
-import {TranslateService } from "app/ng2/shared/translator/translate.service";
+import {ISdcConfig, SdcConfigToken} from "app/ng2/config/sdc-config.config";
+import {TranslateService} from "app/ng2/shared/translator/translate.service";
-import {Observable } from "rxjs/Observable";
+import {Observable} from "rxjs/Observable";
-import { ModalComponent } from 'onap-ui-angular/dist/modals/modal.component';
-import {ModalService } from 'app/ng2/services/modal.service';
+import {ModalComponent} from 'onap-ui-angular/dist/modals/modal.component';
+import {ModalService} from 'app/ng2/services/modal.service';
import {
+ CapabilitiesGroup,
+ Capability,
InputBEModel,
- OperationModel,
InterfaceModel,
- WORKFLOW_ASSOCIATION_OPTIONS,
- CapabilitiesGroup,
- Capability
+ OperationModel,
+ WORKFLOW_ASSOCIATION_OPTIONS
} from 'app/models';
-// import {SdcUiComponents } from 'sdc-ui/lib/angular';
-// import {ModalButtonComponent } from 'sdc-ui/lib/angular/components';
-// import { IModalButtonComponent, IModalConfig } from 'sdc-ui/lib/angular/modals/models/modal-config';
+import {ComponentServiceNg2} from 'app/ng2/services/component-services/component.service';
+import {PluginsService} from 'app/ng2/services/plugins.service';
+import {WorkflowServiceNg2} from 'app/ng2/services/workflow.service';
-import {ComponentServiceNg2 } from 'app/ng2/services/component-services/component.service';
-import {PluginsService } from 'app/ng2/services/plugins.service';
-import {WorkflowServiceNg2 } from 'app/ng2/services/workflow.service';
-
-import { OperationCreatorComponent, OperationCreatorInput } from 'app/ng2/pages/interface-operation/operation-creator/operation-creator.component';
-import { IModalButtonComponent } from 'onap-ui-angular';
-import { ModalButtonComponent } from 'onap-ui-angular';
-import { IModalConfig } from 'onap-ui-angular';
-import { SdcUiServices } from 'onap-ui-angular';
+import {
+ OperationCreatorComponent,
+ OperationCreatorInput
+} from 'app/ng2/pages/interface-operation/operation-creator/operation-creator.component';
+import {IModalButtonComponent, IModalConfig, SdcUiServices} from 'onap-ui-angular';
export class UIOperationModel extends OperationModel {
isCollapsed: boolean = true;
@@ -143,7 +159,6 @@ export class InterfaceOperationComponent {
private WorkflowServiceNg2: WorkflowServiceNg2,
private ModalServiceNg2: ModalService,
private ModalServiceSdcUI: SdcUiServices.ModalService
-
) {
this.enableWorkflowAssociation = sdcConfig.enableWorkflowAssociation;
this.modalTranslation = new ModalTranslation(TranslateService);
@@ -164,7 +179,7 @@ export class InterfaceOperationComponent {
this.sortInterfaces();
this.inputs = response[1].inputs;
this.interfaceTypes = response[2];
- this.workflows = (workflows.items) ? workflows.items: workflows;
+ this.workflows = (workflows.items) ? workflows.items : workflows;
this.capabilities = response[3].capabilities;
};
if (this.enableWorkflowAssociation && this.workflowIsOnline) {
@@ -308,16 +323,16 @@ export class InterfaceOperationComponent {
closeModal: true,
callback: () => {
this.ComponentServiceNg2
- .deleteInterfaceOperation(this.component, operation)
- .subscribe(() => {
- const curInterf = _.find(this.interfaces, (interf) => interf.type === operation.interfaceType);
- const index = _.findIndex(curInterf.operations, (el) => el.uniqueId === operation.uniqueId);
- curInterf.operations.splice(index, 1);
- if (!curInterf.operations.length) {
- const interfIndex = _.findIndex(this.interfaces, (interf) => interf.type === operation.interfaceType);
- this.interfaces.splice(interfIndex, 1);
- }
- });
+ .deleteInterfaceOperation(this.component, operation)
+ .subscribe(() => {
+ const curInterf = _.find(this.interfaces, (interf) => interf.type === operation.interfaceType);
+ const index = _.findIndex(curInterf.operations, (el) => el.uniqueId === operation.uniqueId);
+ curInterf.operations.splice(index, 1);
+ if (!curInterf.operations.length) {
+ const interfIndex = _.findIndex(this.interfaces, (interf) => interf.type === operation.interfaceType);
+ this.interfaces.splice(interfIndex, 1);
+ }
+ });
}
};
@@ -372,7 +387,7 @@ export class InterfaceOperationComponent {
} else if (response.workflowId && operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.EXISTING) {
this.WorkflowServiceNg2.associateWorkflowArtifact(this.component, response).subscribe();
} else if (operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.NEW) {
- this.$state.go('workspace.plugins', { path: 'workflowDesigner' });
+ this.$state.go('workspace.plugins', {path: 'workflowDesigner'});
}
});
}
diff --git a/catalog-ui/src/app/ng2/services/component-services/component.service.ts b/catalog-ui/src/app/ng2/services/component-services/component.service.ts
index 8d91eede84..3889b73f49 100644
--- a/catalog-ui/src/app/ng2/services/component-services/component.service.ts
+++ b/catalog-ui/src/app/ng2/services/component-services/component.service.ts
@@ -238,12 +238,44 @@ export class ComponentServiceNg2 {
});
}
+ createComponentInterfaceOperation(componentMetaDataId: string,
+ componentMetaDataType: string,
+ operation: InterfaceOperationModel): Observable<InterfaceOperationModel> {
+ const operationList = {
+ interfaces: {
+ [operation.interfaceType]: {
+ type: operation.interfaceType,
+ operations: {
+ [operation.name]: new BEInterfaceOperationModel(operation)
+ }
+ }
+ }
+ };
+ console.log(operationList);
+ console.log(this.baseUrl + componentMetaDataType + componentMetaDataId + '/resource/interfaceOperation')
+ return this.http.post<any>(this.baseUrl + componentMetaDataType + componentMetaDataId + '/resource/interfaceOperation', operationList)
+ .map((res: any) => {
+ const interf: InterfaceModel = _.find(res.interfaces, interf => interf.type === operation.interfaceType);
+ const newOperation: OperationModel = _.find(interf.operations, op => op.name === operation.name);
+
+ return new InterfaceOperationModel({
+ ...newOperation,
+ interfaceType: interf.type,
+ interfaceId: interf.uniqueId,
+ });
+ });
+ }
+
deleteInterfaceOperation(component: Component, operation: OperationModel): Observable<OperationModel> {
return this.http.delete<OperationModel>(this.baseUrl + component.getTypeUrl() + component.uniqueId + '/interfaces/' + operation.interfaceId + '/operations/' + operation.uniqueId);
}
getInterfaceTypes(component: Component): Observable<{ [id: string]: Array<string> }> {
- return this.http.get<any>(this.baseUrl + 'interfaceLifecycleTypes' + ((component && component.model) ? '?model=' + component.model : ''))
+ return this.getInterfaceTypesByModel(component && component.model);
+ }
+
+ getInterfaceTypesByModel(model: string): Observable<{ [id: string]: Array<string> }> {
+ return this.http.get<any>(this.baseUrl + 'interfaceLifecycleTypes' + ((model) ? '?model=' + model : ''))
.map((res: any) => {
const interfaceMap = {};
if (!res) {
diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/ImportVfcUiTest.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/ImportVfcUiTest.java
index 62d8be8a33..e1705a2255 100644
--- a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/ImportVfcUiTest.java
+++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/ImportVfcUiTest.java
@@ -68,11 +68,9 @@ import org.onap.sdc.frontend.ci.tests.utilities.FileHandling;
import org.openecomp.sdc.be.model.ComponentInstance;
import org.openqa.selenium.WebDriver;
import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Ignore;
import org.testng.annotations.Test;
import org.yaml.snakeyaml.Yaml;
-@Ignore // solved in https://gerrit.onap.org/r/c/sdc/+/127976
public class ImportVfcUiTest extends SetupCDTest {
private String filePath;
diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/ServiceTemplateDesignUiTests.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/ServiceTemplateDesignUiTests.java
index d6e04d6e13..96193f69a2 100644
--- a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/ServiceTemplateDesignUiTests.java
+++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/ServiceTemplateDesignUiTests.java
@@ -91,7 +91,6 @@ import org.openqa.selenium.WebDriver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Ignore;
import org.testng.annotations.Test;
import org.yaml.snakeyaml.Yaml;
@@ -241,7 +240,6 @@ public class ServiceTemplateDesignUiTests extends SetupCDTest {
}
@Test(dependsOnMethods = "addRelationshipTemplate")
- @Ignore // solved in https://gerrit.onap.org/r/c/sdc/+/127976
public void updateInterfaceOperation() throws Exception {
homePage.isLoaded();
componentPage = (ComponentPage) homePage.clickOnComponent(vfResourceCreateData.getName());