Add support for delete property from non-normative data type 84/133184/11
authorvasraz <vasyl.razinkov@est.tech>
Thu, 9 Feb 2023 17:57:56 +0000 (17:57 +0000)
committerVasyl Razinkov <vasyl.razinkov@est.tech>
Fri, 10 Feb 2023 09:45:37 +0000 (09:45 +0000)
Signed-off-by: Vasyl Razinkov <vasyl.razinkov@est.tech>
Change-Id: I668b1e7f7d00e97b7827d759766e105fdd53ed53
Issue-ID: SDC-4378

catalog-be/src/main/java/org/openecomp/sdc/be/servlets/DataTypeServlet.java
catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesUploadServlet.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperation.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ModelOperation.java
catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/ModelOperationTest.java
catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.html
catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.ts
catalog-ui/src/app/ng2/services/data-type.service.ts
common-app-api/src/main/java/org/openecomp/sdc/common/api/Constants.java

index 05c1fb7..3a62600 100644 (file)
@@ -35,6 +35,7 @@ import java.util.List;
 import java.util.Optional;
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
 import javax.ws.rs.HeaderParam;
 import javax.ws.rs.POST;
@@ -63,7 +64,6 @@ import org.openecomp.sdc.common.api.Constants;
 import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode;
 import org.openecomp.sdc.common.log.wrappers.Logger;
 import org.springframework.stereotype.Controller;
-import org.apache.commons.lang3.StringUtils;
 
 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
 @Path("/v1/catalog/data-types")
@@ -162,10 +162,10 @@ public class DataTypeServlet extends BeGenericServlet {
                 String.format("Property model is not the same as the data type model. Must be '%s'", model));
         }
         if (StringUtils.isEmpty(dataType.getModel())) {
-            dataType.setModel("SDC AID");
+            dataType.setModel(Constants.DEFAULT_MODEL_NAME);
         }
         final PropertyDefinitionDto property = dataTypeOperation.createProperty(id, propertyDefinitionDto);
-        dataTypeOperation.addPropertyToAdditionalTypeDataType(dataType, property);
+        dataTypeOperation.updatePropertyInAdditionalTypeDataType(dataType, property, true);
         dataTypeBusinessLogic.updateApplicationDataTypeCache(id);
         return Response.status(Status.CREATED).entity(property).build();
     }
@@ -204,7 +204,7 @@ public class DataTypeServlet extends BeGenericServlet {
             dataType.setModel(Constants.DEFAULT_MODEL_NAME);
         }
         final PropertyDefinitionDto property = dataTypeOperation.updateProperty(id, propertyDefinitionDto);
-        dataTypeOperation.addPropertyToAdditionalTypeDataType(dataType, property);
+        dataTypeOperation.updatePropertyInAdditionalTypeDataType(dataType, property, true);
         dataTypeBusinessLogic.updateApplicationDataTypeCache(id);
         return Response.status(Status.CREATED).entity(property).build();
     }
@@ -224,4 +224,38 @@ public class DataTypeServlet extends BeGenericServlet {
         return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK),
             gson.toJson(dataTypeOperation.getAllDataTypeModels(dataTypeName)));
     }
+
+    @DELETE
+    @Path("{dataTypeId}/{propertyId}")
+    public Response deleteProperty(@Parameter(in = ParameterIn.PATH, required = true, description = "The data type id")
+                                   @PathParam("dataTypeId") final String dataTypeId,
+                                   @Parameter(in = ParameterIn.PATH, required = true, description = "The property id to delete")
+                                   @PathParam("propertyId") final String propertyId) {
+        final Optional<DataTypeDataDefinition> dataTypeOptional = dataTypeOperation.getDataTypeByUid(dataTypeId);
+        dataTypeOptional.orElseThrow(() -> {
+            throw new OperationException(ActionStatus.DATA_TYPE_NOT_FOUND, String.format("Failed to find data type '%s'", dataTypeId));
+        });
+        final DataTypeDataDefinition dataTypeDataDefinition = dataTypeOptional.get();
+        if (StringUtils.isEmpty(dataTypeDataDefinition.getModel())) {
+            dataTypeDataDefinition.setModel(Constants.DEFAULT_MODEL_NAME);
+        }
+        final PropertyDefinitionDto propertyDefinitionDto;
+        try {
+            propertyDefinitionDto = dataTypeOperation.deleteProperty(dataTypeDataDefinition, propertyId);
+            dataTypeOperation.updatePropertyInAdditionalTypeDataType(dataTypeDataDefinition, propertyDefinitionDto, false);
+        } catch (OperationException e) {
+            final PropertyDefinitionDto dto = new PropertyDefinitionDto();
+            dto.setName(extractNameFromPropertyId(propertyId));
+            dataTypeOperation.updatePropertyInAdditionalTypeDataType(dataTypeDataDefinition, dto, false);
+            throw e;
+        } finally {
+            dataTypeBusinessLogic.updateApplicationDataTypeCache(dataTypeId);
+        }
+        return Response.status(Status.OK).entity(propertyDefinitionDto).build();
+    }
+
+    private String extractNameFromPropertyId(final String propertyId) {
+        final String[] split = propertyId.split("\\.");
+        return split[split.length - 1];
+    }
 }
index 8974704..f7ea9bb 100644 (file)
@@ -137,7 +137,7 @@ public class TypesUploadServlet extends AbstractValidationsServlet {
     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
     public Response uploadCapabilityType(@Parameter(description = "FileInputStream") @FormDataParam("capabilityTypeZip") File file,
                                          @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator,
-                                         @Parameter(description = "model") @FormDataParam("model") String modelName,
+                                         @Parameter(description = "model name") @FormDataParam("model") String modelName,
                                          @Parameter(description = "includeToModelImport") @FormDataParam("includeToModelImport") boolean includeToModelDefaultImports) {
         ConsumerFourParam<Wrapper<Response>, String, String, Boolean> createElementsMethod = (responseWrapper, ymlPayload, model, includeToModelImport) ->
             createElementsType(responseWrapper, () -> capabilityTypeImportManager.createCapabilityTypes(ymlPayload, modelName,
@@ -157,10 +157,10 @@ public class TypesUploadServlet extends AbstractValidationsServlet {
     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
     public Response uploadRelationshipType(@Parameter(description = "FileInputStream") @FormDataParam("relationshipTypeZip") File file,
                                            @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator,
-                                           @Parameter(description = "model") @FormDataParam("model") String modelName,
+                                           @Parameter(description = "model name") @FormDataParam("model") String modelName,
                                            @Parameter(description = "includeToModelImport") @FormDataParam("includeToModelImport") boolean includeToModelDefaultImports) {
-        return uploadElementTypeServletLogic(
-            this::createRelationshipTypes, file, request, creator, NodeTypeEnum.RelationshipType.getName(), modelName, includeToModelDefaultImports);
+        return uploadElementTypeServletLogic(this::createRelationshipTypes, file, request, creator, NodeTypeEnum.RelationshipType.getName(),
+            modelName, includeToModelDefaultImports);
     }
 
     @POST
@@ -174,7 +174,7 @@ public class TypesUploadServlet extends AbstractValidationsServlet {
     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
     public Response uploadInterfaceLifecycleType(@Parameter(description = "FileInputStream") @FormDataParam("interfaceLifecycleTypeZip") File file,
                                                  @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator,
-                                                 @Parameter(description = "model") @FormDataParam("model") String modelName,
+                                                 @Parameter(description = "model name") @FormDataParam("model") String modelName,
                                                  @Parameter(description = "includeToModelImport") @FormDataParam("includeToModelImport") boolean includeToModelDefaultImports) {
         ConsumerTwoParam<Wrapper<Response>, String> createElementsMethod = (responseWrapper, ymlPayload) ->
             createElementsType(responseWrapper, () -> interfaceLifecycleTypeImportManager.createLifecycleTypes(ymlPayload, modelName,
@@ -230,7 +230,7 @@ public class TypesUploadServlet extends AbstractValidationsServlet {
     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
     public Response uploadDataTypes(@Parameter(description = "FileInputStream") @FormDataParam("dataTypesZip") File file,
                                     @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator,
-                                    @Parameter(description = "model") @FormDataParam("model") String modelName,
+                                    @Parameter(description = "model name") @FormDataParam("model") String modelName,
                                     @Parameter(description = "includeToModelImport") @FormDataParam("includeToModelImport") boolean includeToModelDefaultImports) {
         return uploadElementTypeServletLogic(this::createDataTypes, file, request, creator, NodeTypeEnum.DataType.getName(), modelName,
             includeToModelDefaultImports);
@@ -247,7 +247,7 @@ public class TypesUploadServlet extends AbstractValidationsServlet {
     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
     public Response uploadDataTypesYaml(@Parameter(description = "FileInputStream") @FormDataParam("dataTypesYaml") File file,
                                         @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator,
-                                        @Parameter(description = "model") @FormDataParam("model") String modelName,
+                                        @Parameter(description = "model name") @FormDataParam("model") String modelName,
                                         @Parameter(description = "includeToModelImport") @FormDataParam("includeToModelImport") boolean includeToModelDefaultImports) {
         return uploadElementTypeServletLogicYaml(this::createDataTypes, file, request, creator, NodeTypeEnum.DataType.getName(), modelName,
             includeToModelDefaultImports);
@@ -263,7 +263,7 @@ public class TypesUploadServlet extends AbstractValidationsServlet {
         @ApiResponse(responseCode = "409", description = "group types already exist")})
     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
     public Response uploadGroupTypes(@Parameter(description = "toscaTypeMetadata") @FormDataParam("toscaTypeMetadata") String toscaTypesMetaData,
-                                     @Parameter(description = "model") @FormDataParam("model") String modelName,
+                                     @Parameter(description = "model name") @FormDataParam("model") String modelName,
                                      @Parameter(description = "FileInputStream") @FormDataParam("groupTypesZip") File file,
                                      @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator,
                                      @Parameter(description = "includeToModelImport") @FormDataParam("includeToModelImport") boolean includeToModelDefaultImports) {
@@ -282,7 +282,7 @@ public class TypesUploadServlet extends AbstractValidationsServlet {
         @ApiResponse(responseCode = "409", description = "policy types already exist")})
     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
     public Response uploadPolicyTypes(@Parameter(description = "toscaTypeMetadata") @FormDataParam("toscaTypeMetadata") String toscaTypesMetaData,
-                                      @Parameter(description = "model") @FormDataParam("model") String modelName,
+                                      @Parameter(description = "model name") @FormDataParam("model") String modelName,
                                       @Parameter(description = "FileInputStream") @FormDataParam("policyTypesZip") File file,
                                       @Context final HttpServletRequest request, @HeaderParam("USER_ID") String creator,
                                       @Parameter(description = "includeToModelImport") @FormDataParam("includeToModelImport") boolean includeToModelDefaultImports) {
@@ -331,8 +331,6 @@ public class TypesUploadServlet extends AbstractValidationsServlet {
             final Wrapper<Response> responseWrapper = doUploadTypeValidations(request, userId, file);
             if (responseWrapper.isEmpty()) {
                 fillZipContents(yamlStringWrapper, file);
-            }
-            if (responseWrapper.isEmpty()) {
                 createElementsMethod.accept(responseWrapper, yamlStringWrapper.getInnerElement(), modelName, includeToModelDefaultImports);
             }
             return responseWrapper.getInnerElement();
@@ -353,11 +351,12 @@ public class TypesUploadServlet extends AbstractValidationsServlet {
             final String url = request.getMethod() + " " + request.getRequestURI();
             log.debug(START_HANDLE_REQUEST_OF, url);
             final Wrapper<Response> responseWrapper = doUploadTypeValidations(request, userId, file);
+            final String yamlAsString = getFileAsString(file);
             if (responseWrapper.isEmpty()) {
-                final String yamlAsString = getFileAsString(file);
                 log.debug("received yaml: {}", yamlAsString);
                 createElementsMethod.accept(responseWrapper, yamlAsString, modelName, includeToModelDefaultImports);
             }
+
             return responseWrapper.getInnerElement();
         } catch (final Exception e) {
             log.debug(CREATE_FAILED_WITH_EXCEPTION, elementTypeName, e);
index 391add9..f79f150 100644 (file)
@@ -303,8 +303,38 @@ public class DataTypeOperation extends AbstractOperation {
         return PropertyDefinitionDtoMapper.mapFrom(propertyData);
     }
 
-    public void addPropertyToAdditionalTypeDataType(DataTypeDataDefinition dataTypeDataDefinition, PropertyDefinitionDto property) {
-        modelOperation.addPropertyToAdditionalType(ElementTypeEnum.DATA_TYPE, property, dataTypeDataDefinition.getModel(), dataTypeDataDefinition.getName());
+    public void updatePropertyInAdditionalTypeDataType(final DataTypeDataDefinition dataTypeDataDefinition,
+                                                       final PropertyDefinitionDto property,
+                                                       final boolean isAdd) {
+        modelOperation.updatePropertyInAdditionalType(ElementTypeEnum.DATA_TYPE, property, dataTypeDataDefinition.getModel(),
+            dataTypeDataDefinition.getName(), isAdd);
+    }
+
+    public PropertyDefinitionDto deleteProperty(final DataTypeDataDefinition dataTypeDataDefinition, final String propertyId) {
+        final List<PropertyDefinition> propertiesData = findAllProperties(dataTypeDataDefinition.getUniqueId());
+        final String dataTypeDataDefinitionName = dataTypeDataDefinition.getName();
+        if (CollectionUtils.isEmpty(propertiesData)) {
+            throw new OperationException(ActionStatus.PROPERTY_NOT_FOUND,
+                String.format("Failed to find property '%s' for data type '%s'", propertyId, dataTypeDataDefinitionName));
+        }
+        Optional<PropertyDefinition> optionalPropertyDefinition = propertiesData.stream()
+            .filter(propertyDataDefinition -> propertyDataDefinition.getUniqueId().equals(propertyId)).findAny();
+        optionalPropertyDefinition.orElseThrow(() -> {
+            throw new OperationException(ActionStatus.PROPERTY_NOT_FOUND,
+                String.format("Failed to find property '%s' for data type '%s'", propertyId, dataTypeDataDefinitionName));
+        });
+        final Either<PropertyData, JanusGraphOperationStatus> statusEither = propertyOperation.deletePropertyFromGraph(propertyId);
+        if (statusEither.isRight()) {
+            throw new OperationException(ActionStatus.PROPERTY_NOT_FOUND,
+                String.format("Failed to delete property '%s' from data type '%s'", propertyId, dataTypeDataDefinitionName));
+        }
+        final PropertyDefinition propertyDefinition = optionalPropertyDefinition.get();
+        final PropertyData propertyData = statusEither.left().value();
+        final PropertyDataDefinition propertyDataDefinition = propertyData.getPropertyDataDefinition();
+        propertyDataDefinition.setName(propertyDefinition.getName());
+        propertyDataDefinition.setPropertyConstraints(propertyData.getConstraints());
+        propertiesData.remove(propertyDefinition);
+        return PropertyDefinitionDtoMapper.mapFrom(propertyDataDefinition);
     }
 
 }
index 311b471..1928941 100644 (file)
@@ -18,6 +18,8 @@
  */
 package org.openecomp.sdc.be.model.operations.impl;
 
+import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.DATA_TYPES;
+import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.PROPERTIES;
 import static org.openecomp.sdc.common.api.Constants.ADDITIONAL_TYPE_DEFINITIONS;
 
 import fj.data.Either;
@@ -220,11 +222,11 @@ public class ModelOperation {
     public List<Model> findAllModels() {
         return findModelsByCriteria(Collections.emptyMap());
     }
-    
+
     public List<Model> findModels(final ModelTypeEnum modelType) {
         final Map<GraphPropertyEnum, Object> propertyCriteria = new EnumMap<>(GraphPropertyEnum.class);
         propertyCriteria.put(GraphPropertyEnum.MODEL_TYPE, modelType.getValue());
-        
+
         return findModelsByCriteria(propertyCriteria);
     }
 
@@ -259,7 +261,7 @@ public class ModelOperation {
         if (optionalModelTypeEnum.isPresent()) {
             modelType = optionalModelTypeEnum.get();
         }
-        
+
         final Either<ImmutablePair<ModelData, GraphEdge>, JanusGraphOperationStatus> parentNode =
             janusGraphGenericDao.getChild(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.Model), UniqueIdBuilder.buildModelUid(modelName),
                 GraphEdgeLabels.DERIVED_FROM, NodeTypeEnum.Model, ModelData.class);
@@ -298,8 +300,8 @@ public class ModelOperation {
         }
 
         Map<String, Object> typesYamlMap = new Yaml().loadAs(typesYaml, Map.class);
-        if (typesYamlMap.containsKey("data_types")){
-            typesYamlMap = (Map<String, Object>) typesYamlMap.get("data_types");
+        if (typesYamlMap.containsKey(DATA_TYPES.getElementName())) {
+            typesYamlMap = (Map<String, Object>) typesYamlMap.get(DATA_TYPES.getElementName());
         }
         removeExistingTypesFromDefaultImports(elementTypeEnum, typesYamlMap, rebuiltModelImportList);
 
@@ -378,7 +380,7 @@ public class ModelOperation {
         if (deleteParentNodeByModel.isRight()) {
             final var janusGraphOperationStatus = deleteParentNodeByModel.right().value();
             log.error(EcompLoggerErrorCode.DATA_ERROR, ModelOperation.class.getName(),
-                "Failed to delete model {} on JanusGraph with status {}", new Object[] {model.getName(), janusGraphOperationStatus});
+                "Failed to delete model {} on JanusGraph with status {}", model.getName(), janusGraphOperationStatus);
             throw new OperationException(ActionStatus.COULD_NOT_DELETE_MODEL, model.getName());
         }
     }
@@ -397,28 +399,28 @@ public class ModelOperation {
             final Map<String, Object> existingTypeContent = getExistingTypes(elementTypeEnum, additionalTypeDefinitionsImportOptional.get());
             final Set<String> existingTypeNames = existingTypeContent.keySet();
 
-            final Map<String, Object> typesToUpate = new HashMap<>();
-
             Map<String, Object> newTypesYaml = new Yaml().load(typesYaml);
-            if (newTypesYaml.containsKey("data_types")){
-                newTypesYaml = (Map<String, Object>) newTypesYaml.get("data_types");
+            if (newTypesYaml.containsKey(DATA_TYPES.getElementName())) {
+                newTypesYaml = (Map<String, Object>) newTypesYaml.get(DATA_TYPES.getElementName());
             }
+            final Map<String, Object> typesToUpate = new HashMap<>();
             newTypesYaml.entrySet().stream().filter(entry -> existingTypeNames.contains(entry.getKey())).forEach(newTypeToUpdate -> {
 
-                final Map<String, Object> propertiesInNewDef = (Map<String, Object>) ((Map<String, Object>) newTypeToUpdate.getValue()).get("properties");
+                final Map<String, Object> propertiesInNewDef =
+                    (Map<String, Object>) ((Map<String, Object>) newTypeToUpdate.getValue()).get(PROPERTIES.getElementName());
                 final Map<String, Object> existingProperties =
-                        (Map<String, Object>) ((Map<String, Object>) existingTypeContent.get(newTypeToUpdate.getKey())).get("properties");
+                    (Map<String, Object>) ((Map<String, Object>) existingTypeContent.get(newTypeToUpdate.getKey())).get(PROPERTIES.getElementName());
 
                 final List<Entry<String, Object>> propertiesMissingFromNewDef = MapUtils.isEmpty(existingProperties) ? Collections.emptyList()
-                        : existingProperties.entrySet().stream()
-                                .filter(existingPropEntry -> !propertiesInNewDef.keySet().contains(existingPropEntry.getKey()))
-                                .collect(Collectors.toList());
+                    : existingProperties.entrySet().stream()
+                        .filter(existingPropEntry -> !propertiesInNewDef.keySet().contains(existingPropEntry.getKey()))
+                        .collect(Collectors.toList());
 
                 if (CollectionUtils.isNotEmpty(propertiesMissingFromNewDef)) {
                     typesToUpate.put(newTypeToUpdate.getKey(), newTypeToUpdate.getValue());
 
                     propertiesMissingFromNewDef
-                            .forEach(existingPropToAdd -> propertiesInNewDef.put(existingPropToAdd.getKey(), existingPropToAdd.getValue()));
+                        .forEach(existingPropToAdd -> propertiesInNewDef.put(existingPropToAdd.getKey(), existingPropToAdd.getValue()));
                 }
             });
             if (MapUtils.isNotEmpty(typesToUpate)) {
@@ -426,48 +428,51 @@ public class ModelOperation {
             }
         }
     }
-    
-    private  Optional<ToscaImportByModel> getAdditionalTypes(final String modelName) {
+
+    private Optional<ToscaImportByModel> getAdditionalTypes(final String modelName) {
         final List<ToscaImportByModel> modelImportList = toscaModelImportCassandraDao.findAllByModel(modelName);
         return modelImportList.stream().filter(t -> ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(t.getFullPath()))).findAny();
     }
 
     private Map<String, Object> getExistingTypes(final ElementTypeEnum elementTypeEnum, final ToscaImportByModel additionalTypeDefinitionsImport) {
         final Map<String, Object> existingContent = new Yaml().load(additionalTypeDefinitionsImport.getContent());
-        return  (Map<String, Object>) existingContent.get(elementTypeEnum.getToscaEntryName());
+        return (Map<String, Object>) existingContent.get(elementTypeEnum.getToscaEntryName());
     }
 
-    public void addPropertyToAdditionalType(final ElementTypeEnum elementTypeEnum, final PropertyDefinitionDto property,
-                                            final String modelName, final String name) {
+    public void updatePropertyInAdditionalType(final ElementTypeEnum elementTypeEnum, final PropertyDefinitionDto property,
+                                               final String modelName, final String name, boolean isAdd) {
         final List<ToscaImportByModel> modelImportList = toscaModelImportCassandraDao.findAllByModel(modelName);
         final Optional<ToscaImportByModel> additionalTypeDefinitionsImportOptional = modelImportList.stream()
-                .filter(t -> ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(t.getFullPath()))).findAny();
-        final ToscaImportByModel additionalTypeDefinitionsImport;
-        final List<ToscaImportByModel> rebuiltModelImportList;
+            .filter(t -> ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(t.getFullPath()))).findAny();
         if (additionalTypeDefinitionsImportOptional.isEmpty()) {
             return;
         }
-        additionalTypeDefinitionsImport = additionalTypeDefinitionsImportOptional.get();
-        rebuiltModelImportList = modelImportList.stream()
-                .filter(toscaImportByModel -> !ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(toscaImportByModel.getFullPath())))
-                .collect(Collectors.toList());
+        final ToscaImportByModel additionalTypeDefinitionsImport = additionalTypeDefinitionsImportOptional.get();
+        final List<ToscaImportByModel> rebuiltModelImportList = modelImportList.stream()
+            .filter(toscaImportByModel -> !ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(toscaImportByModel.getFullPath())))
+            .collect(Collectors.toList());
         final Map<String, Object> originalContent = new Yaml().load(additionalTypeDefinitionsImport.getContent());
-        additionalTypeDefinitionsImport.setContent(buildPropertyAdditionalTypeDefinitionContent(elementTypeEnum, name, property, originalContent));
+        additionalTypeDefinitionsImport.setContent(
+            buildPropertyAdditionalTypeDefinitionContent(elementTypeEnum, name, property, originalContent, isAdd));
         rebuiltModelImportList.add(additionalTypeDefinitionsImport);
         toscaModelImportCassandraDao.saveAll(modelName, rebuiltModelImportList);
     }
 
     private String buildPropertyAdditionalTypeDefinitionContent(final ElementTypeEnum elementTypeEnum, final String name,
-                                                                final PropertyDefinitionDto property, final Map<String, Object> originalContent) {
+                                                                final PropertyDefinitionDto property, final Map<String, Object> originalContent,
+                                                                boolean isAdd) {
         final Map<String, Object> originalTypeContent = (Map<String, Object>) originalContent.get(elementTypeEnum.getToscaEntryName());
         Map<String, Object> typeContent = (Map<String, Object>) originalTypeContent.get(name);
-        Map<String, Object> typeProperties = (Map<String, Object>) typeContent.get("properties");
-        if (typeProperties == null) {
+        Map<String, Object> typeProperties = (Map<String, Object>) typeContent.get(PROPERTIES.getElementName());
+        if (MapUtils.isEmpty(typeProperties)) {
             typeProperties = new HashMap<>();
         }
-        Map<String, Object> typeProp = constructProperty(property);
-        typeProperties.put(property.getName(), typeProp);
-        typeContent.put("properties", typeProperties);
+        if (isAdd) {
+            typeProperties.put(property.getName(), constructProperty(property));
+        } else {
+            typeProperties.remove(property.getName());
+        }
+        typeContent.put(PROPERTIES.getElementName(), typeProperties);
         return new YamlUtil().objectToYaml(originalContent);
     }
 
index 8fe8921..1bd4d9d 100644 (file)
@@ -613,7 +613,7 @@ class ModelOperationTest extends ModelTestBase {
         property.setRequired(true);
 
         String dataTypeName = "tosca.datatypes.nfv.PreviouslyExistingType1";
-        modelOperation.addPropertyToAdditionalType(ElementTypeEnum.DATA_TYPE, property, modelName, dataTypeName);
+        modelOperation.updatePropertyInAdditionalType(ElementTypeEnum.DATA_TYPE, property, modelName, dataTypeName, true);
         ArgumentCaptor<List<ToscaImportByModel>> importListArgumentCaptor = ArgumentCaptor.forClass(List.class);
         verify(toscaModelImportCassandraDao).saveAll(eq(modelName), importListArgumentCaptor.capture());
 
index e657520..12b2d99 100644 (file)
         <div class="table-header head-row hand flex-item" *ngFor="let header of tableHeadersList" (click)="onUpdateSort(header.property)">{{header.title}}
           <span *ngIf="tableSortBy === header.property" class="table-header-sort-arrow" [ngClass]="{'down': tableColumnReverse, 'up': !tableColumnReverse}"></span>
         </div>
+        <div class="table-no-text-header head-row flex-item" *ngIf="!isViewOnly"><span class="delete-col-header"></span></div>
       </div>
 
       <div class="body">
         <div *ngIf="filteredProperties.length === 0" class="no-row-text">
           {{'PROPERTY_LIST_EMPTY_MESSAGE' | translate}}
         </div>
-        <div *ngFor="let property of filteredProperties" [attr.data-tests-id]="'property-row-' + property.name" class="flex-container data-row" (click)="onNameClick(property)">
-          <div class="table-col-general flex-item text" [title]="property.name">
+        <div *ngFor="let property of filteredProperties" [attr.data-tests-id]="'property-row-' + property.name" class="flex-container data-row">
+          <div class="table-col-general flex-item text" [title]="property.name" (click)="onNameClick(property)">
             <a [attr.data-tests-id]="'property-name-' + property.name" [ngClass]="{'disabled': false}">{{property.name}}</a>
           </div>
           <div class="table-col-general flex-item text" [title]="property.type">
           <div class="table-col-general flex-item text" [title]="property.description || ''">
             <span [attr.data-tests-id]="'property-description-' + property.name" [title]="property.description">{{property.description}}</span>
           </div>
+          <div class="table-btn-col flex-item" *ngIf="!isViewOnly">
+            <button class="table-delete-btn" data-ng-if="!property.ownerId || property.ownerId==component.uniqueId"
+                    (click)="delete(property); $event.stopPropagation();"  data-ng-class="{'disabled': isViewOnly}"></button>
+          </div>
         </div>
       </div>
 
index 60edd13..f9eaa13 100644 (file)
@@ -32,6 +32,8 @@ import {TranslateService} from "../../../shared/translator/translate.service";
 import {AddPropertyComponent, PropertyValidationEvent} from "./add-property/add-property.component";
 import {IWorkspaceViewModelScope} from "../../../../view-models/workspace/workspace-view-model";
 import {SdcUiServices} from "onap-ui-angular/dist";
+import {PropertyModel} from "../../../../models/properties";
+import {SdcUiCommon, SdcUiComponents} from "onap-ui-angular";
 import {ToscaTypeHelper} from "../../../../utils/tosca-type-helper";
 
 @Component({
@@ -249,9 +251,31 @@ export class TypeWorkspacePropertiesComponent implements OnInit {
         }
         return null;
     }
+
+    delete(property: PropertyModel) {
+        let onOk: Function = (): void => {
+            this.dataTypeService.deleteProperty(this.dataType.uniqueId, property.uniqueId).subscribe((response) => {
+                const props = this.properties;
+                props.splice(props.findIndex(p => p.uniqueId === response), 1);
+                this.filter();
+            }, (error) => {
+                console.error(error);
+            });
+        };
+        let title: string = this.translateService.translate("PROPERTY_VIEW_DELETE_MODAL_TITLE");
+        let message: string = this.translateService.translate("PROPERTY_VIEW_DELETE_MODAL_TEXT", {'name': property.name});
+        const okButton = {
+            testId: "OK",
+            text: "OK",
+            type: SdcUiCommon.ButtonType.info,
+            callback: onOk,
+            closeModal: true
+        } as SdcUiComponents.ModalButtonComponent;
+        this.modalServiceSdcUI.openInfoModal(title, message, 'delete-modal', [okButton]);
+    };
 }
 
 interface TableHeader {
     title: string;
     property: string;
-}
\ No newline at end of file
+}
index 38714c9..636217f 100644 (file)
 
 import * as _ from "lodash";
 import {Inject, Injectable} from '@angular/core';
-import {DataTypeModel, DataTypesMap, PropertyFEModel, DerivedFEProperty, PropertyBEModel} from "app/models";
-import { DataTypesService } from "app/services/data-types-service";
-import { PROPERTY_DATA } from "app/utils";
+import {
+    DataTypeModel,
+    DataTypesMap,
+    DerivedFEProperty,
+    PropertyBEModel,
+    PropertyFEModel
+} from "app/models";
+import {DataTypesService} from "app/services/data-types-service";
+import {PROPERTY_DATA} from "app/utils";
 import {DerivedFEAttribute} from "../../models/attributes-outputs/derived-fe-attribute";
 import {ISdcConfig} from "../config/sdc-config.config.factory";
 import {SdcConfigToken} from "../config/sdc-config.config";
@@ -62,7 +68,7 @@ export class DataTypeService {
     }
 
     public getDataTypeByTypeName(typeName: string): DataTypeModel {
-        if(!this.dataTypes){
+        if (!this.dataTypes) {
             this.dataTypes = this.dataTypeService.getAllDataTypes();
         }
         if (!this.dataTypes[typeName]) console.log("MISSING Datatype: " + typeName);
@@ -97,6 +103,15 @@ export class DataTypeService {
         return this.httpClient.put<PropertyBEModel>(url, property);
     }
 
+    public deleteProperty(dataTypeId: string, propertyId: string): Observable<Object> {
+        const url = `${this.dataTypeUrl}/${dataTypeId}/${propertyId}`;
+        let headers = new HttpHeaders({'USER_ID': this.authService.getLoggedinUser().userId});
+        let options = {headers: headers};
+        return this.httpClient.delete(url, options).map((res: Response) => {
+            return propertyId;
+        });
+    }
+
     public createImportedType(model: string, importingFile: File): Observable<any> {
         const url = `${this.dataTypeUploadUrl}/datatypesyaml`;
         const formData = new FormData();
@@ -109,7 +124,7 @@ export class DataTypeService {
         return this.httpClient.post<any>(url, formData, options);
     }
 
-    public getConstraintsByParentTypeAndUniqueID(rootPropertyType, propertyName){
+    public getConstraintsByParentTypeAndUniqueID(rootPropertyType, propertyName) {
         // const property = this.dataTypes[rootPropertyType].properties.filter(property =>
         //     property.name == propertyName);
         // return property[0] && property[0].constraints ? property[0].constraints[0].validValues : null;
@@ -121,7 +136,7 @@ export class DataTypeService {
         if (!dataTypeObj) return;
         if (dataTypeObj.properties) {
             dataTypeObj.properties.forEach((derivedProperty) => {
-                if(dataTypeObj.name !== PROPERTY_DATA.OPENECOMP_ROOT || derivedProperty.name !== PROPERTY_DATA.SUPPLEMENTAL_DATA){//The requirement is to not display the property supplemental_data
+                if (dataTypeObj.name !== PROPERTY_DATA.OPENECOMP_ROOT || derivedProperty.name !== PROPERTY_DATA.SUPPLEMENTAL_DATA) {//The requirement is to not display the property supplemental_data
                     propertiesArray.push(new DerivedFEProperty(derivedProperty, parentName));
                 }
                 let derivedDataTypeObj: DataTypeModel = this.getDataTypeByTypeName(derivedProperty.type);
@@ -139,7 +154,7 @@ export class DataTypeService {
         if (!dataTypeObj) return;
         if (dataTypeObj.attributes) {
             dataTypeObj.attributes.forEach((derivedAttribute) => {
-                if(dataTypeObj.name !== PROPERTY_DATA.OPENECOMP_ROOT || derivedAttribute.name !== PROPERTY_DATA.SUPPLEMENTAL_DATA){//The requirement is to not display the property supplemental_data
+                if (dataTypeObj.name !== PROPERTY_DATA.OPENECOMP_ROOT || derivedAttribute.name !== PROPERTY_DATA.SUPPLEMENTAL_DATA) {//The requirement is to not display the property supplemental_data
                     attributesArray.push(new DerivedFEAttribute(derivedAttribute, parentName));
                 }
                 let derivedDataTypeObj: DataTypeModel = this.getDataTypeByTypeName(derivedAttribute.type);
@@ -156,8 +171,8 @@ export class DataTypeService {
      * Checks for custom behavior for a given data type by checking if a function exists within data-type.service with that name
      * Additional custom behavior can be added by adding a function with the given dataType name
      */
-    public checkForCustomBehavior = (property:PropertyFEModel) => {
-        let shortTypeName:string = property.type.split('.').pop();
+    public checkForCustomBehavior = (property: PropertyFEModel) => {
+        let shortTypeName: string = property.type.split('.').pop();
         if (this[shortTypeName]) {
             this[shortTypeName](property); //execute function for given type, pass property as param
         }
index 7a0feb9..039fc8e 100644 (file)
  */
 package org.openecomp.sdc.common.api;
 
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
 public final class Constants {
 
     public static final String APPLICATION_NAME = "application-name";
@@ -62,8 +66,6 @@ public final class Constants {
     public static final String RESOURCE_SUPPORTED_VERSION = "0.0.1";
     public static final String ARTIFACT_ID_FORMAT = "%s:%s:%s"; // resourceName:resourceVersion:artifactName
     public static final String ADDITIONAL_TYPE_DEFINITIONS = "additional_type_definitions.yaml";
-
-
     public static final String SERVICE_ARTIFACT_ID_FORMAT = "%s:%s:%s:%s"; // serviceName:serviceVersion:nodeTemplateName:artifactName
     public static final String CONTENT_DISPOSITION = "content-disposition";
     public static final String DOWNLOAD_ARTIFACT_LOGIC_ATTR = "downloadArtifactLogic";
@@ -156,8 +158,6 @@ public final class Constants {
     public static final String INITIAL_COUNT = "initial_count";
     public static final String VF_MODULE_TYPE = "vf_module_type";
     public static final String VOLUME_GROUP = "volume_group";
-    public static final String ASD_DEPLOYMENT_ITEM= "tosca.artifacts.asd.deploymentItem";
+    public static final String ASD_DEPLOYMENT_ITEM = "tosca.artifacts.asd.deploymentItem";
 
-    private Constants() {
-    }
 }