Add data type properties workspace 50/131450/4
authorandre.schmid <andre.schmid@est.tech>
Tue, 4 Oct 2022 19:29:28 +0000 (20:29 +0100)
committerMichael Morris <michael.morris@est.tech>
Mon, 17 Oct 2022 14:42:22 +0000 (14:42 +0000)
Implements the properties workspace for a data type, with the list
and filter feature.

Change-Id: I2ec337a0481bddd5fe32e45644abdc88e197fa49
Issue-ID: SDC-4214
Signed-off-by: André Schmid <andre.schmid@est.tech>
22 files changed:
catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml
catalog-be/src/main/java/org/openecomp/sdc/be/servlets/DataTypeServlet.java
catalog-be/src/test/java/org/openecomp/sdc/be/servlets/DataTypeServletTest.java
catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java
catalog-model/src/main/java/org/openecomp/sdc/be/exception/OperationException.java [new file with mode: 0644]
catalog-model/src/main/java/org/openecomp/sdc/be/exception/supplier/DataTypeOperationExceptionSupplier.java [new file with mode: 0644]
catalog-model/src/main/java/org/openecomp/sdc/be/model/dto/PropertyDefinitionDto.java [new file with mode: 0644]
catalog-model/src/main/java/org/openecomp/sdc/be/model/mapper/PropertyDefinitionDtoMapper.java [new file with mode: 0644]
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/PropertyOperation.java
catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperationTest.java
catalog-ui/configurations/menu.js
catalog-ui/src/app/models/properties-inputs/property-be-model.ts
catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.html [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.less [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.spec.ts [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.ts [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.html
catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.spec.ts
catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.module.ts
catalog-ui/src/app/ng2/services/data-type.service.ts
catalog-ui/src/assets/languages/en_US.json

index d9846a7..e39e0d2 100644 (file)
@@ -22,16 +22,19 @@ package org.openecomp.sdc.be.servlets;
 
 import com.jcabi.aspects.Loggable;
 import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.ArraySchema;
 import io.swagger.v3.oas.annotations.media.Content;
 import io.swagger.v3.oas.annotations.media.Schema;
 import io.swagger.v3.oas.annotations.responses.ApiResponse;
 import io.swagger.v3.oas.annotations.servers.Server;
 import io.swagger.v3.oas.annotations.tags.Tag;
+import java.util.List;
 import java.util.Optional;
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
 import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
@@ -45,6 +48,8 @@ import org.openecomp.sdc.be.dao.api.ActionStatus;
 import org.openecomp.sdc.be.datatypes.elements.DataTypeDataDefinition;
 import org.openecomp.sdc.be.exception.BusinessException;
 import org.openecomp.sdc.be.impl.ComponentsUtils;
+import org.openecomp.sdc.be.model.PropertyDefinition;
+import org.openecomp.sdc.be.model.dto.PropertyDefinitionDto;
 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException;
 import org.openecomp.sdc.be.model.operations.impl.DataTypeOperation;
 import org.openecomp.sdc.common.api.Constants;
@@ -99,4 +104,19 @@ public class DataTypeServlet extends BeGenericServlet {
         return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), dataType);
     }
 
+    @GET
+    @Path("{id}/properties")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    @Operation(description = "Get a data type properties", method = "GET", summary = "Returns the data type properties", responses = {
+        @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = PropertyDefinition.class)))),
+        @ApiResponse(responseCode = "200", description = "Data type found, properties may be empty"),
+        @ApiResponse(responseCode = "403", description = "Restricted operation"),
+        @ApiResponse(responseCode = "404", description = "Data type not found")})
+    @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
+    public Response fetchProperties(@PathParam("id") final String id) {
+        final List<PropertyDefinition> allProperties = dataTypeOperation.findAllProperties(id);
+        return buildOkResponse(allProperties);
+    }
+
 }
index d916fff..d2380fa 100644 (file)
@@ -25,6 +25,8 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 import javax.servlet.ServletContext;
 import javax.ws.rs.core.MediaType;
@@ -44,6 +46,7 @@ import org.openecomp.sdc.be.dao.api.ActionStatus;
 import org.openecomp.sdc.be.datatypes.elements.DataTypeDataDefinition;
 import org.openecomp.sdc.be.impl.ComponentsUtils;
 import org.openecomp.sdc.be.impl.WebAppContextWrapper;
+import org.openecomp.sdc.be.model.PropertyDefinition;
 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException;
 import org.openecomp.sdc.be.model.operations.impl.DataTypeOperation;
 import org.openecomp.sdc.common.api.Constants;
@@ -56,6 +59,7 @@ class DataTypeServletTest extends JerseySpringBaseTest {
     private static final String USER_ID = "cs0008";
     private static final String DATA_TYPE_UID = "ETSI SOL001 v2.5.1.tosca.datatypes.nfv.L3AddressData.datatype";
     private static final String PATH = "/v1/catalog/data-types/" + DATA_TYPE_UID;
+    private static final String DATA_TYPE_PROPERTIES_PATH = "/v1/catalog/data-types/%s/properties";
 
     @InjectMocks
     private DataTypeServlet dataTypeServlet;
@@ -153,4 +157,27 @@ class DataTypeServletTest extends JerseySpringBaseTest {
         assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
     }
 
+    @Test
+    void fetchDataTypePropertiesTest_Success() {
+        final DataTypeDataDefinition expectedDataType = new DataTypeDataDefinition();
+        final PropertyDefinition expectedProperty1 = new PropertyDefinition();
+        expectedProperty1.setName("property1");
+        final PropertyDefinition expectedProperty2 = new PropertyDefinition();
+        expectedProperty2.setName("property2");
+        expectedDataType.setUniqueId(DATA_TYPE_UID);
+        when(dataTypeOperation.findAllProperties(DATA_TYPE_UID)).thenReturn(List.of(expectedProperty1, expectedProperty2));
+
+        final Response response = target()
+            .path(String.format(DATA_TYPE_PROPERTIES_PATH, DATA_TYPE_UID))
+            .request(MediaType.APPLICATION_JSON)
+            .header("USER_ID", USER_ID)
+            .get(Response.class);
+        assertNotNull(response);
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        final List<Map<String, Object>> actualResponse = response.readEntity(List.class);
+        assertEquals(2, actualResponse.size());
+        assertEquals(expectedProperty1.getName(), actualResponse.get(0).get("name"));
+        assertEquals(expectedProperty2.getName(), actualResponse.get(1).get("name"));
+    }
+
 }
index 1ca0e4d..2c7c724 100644 (file)
@@ -75,7 +75,7 @@ public enum ActionStatus {
     EMPTY_OCCURRENCES_LIST, INVALID_OCCURRENCES, NOT_TOPOLOGY_TOSCA_TEMPLATE, INVALID_NODE_TEMPLATE,
     // Data type related
     DATA_TYPE_ALREADY_EXIST, DATA_TYPE_NOR_PROPERTIES_NEITHER_DERIVED_FROM, DATA_TYPE_PROPERTIES_CANNOT_BE_EMPTY, DATA_TYPE_DERIVED_IS_MISSING, DATA_TYPE_PROPERTY_ALREADY_DEFINED_IN_ANCESTOR, DATA_TYPE_DUPLICATE_PROPERTY, DATA_TYPE_PROEPRTY_CANNOT_HAVE_SAME_TYPE_OF_DATA_TYPE, DATA_TYPE_CANNOT_HAVE_PROPERTIES, DATA_TYPE_CANNOT_BE_EMPTY, DATA_TYPE_CANNOT_BE_UPDATED_BAD_REQUEST,
-    DATA_TYPES_NOT_LOADED, DATA_TYPE_NOT_FOUND,
+    DATA_TYPES_NOT_LOADED, DATA_TYPE_NOT_FOUND, DATA_TYPE_PROPERTIES_NOT_FOUND,
     // Policy Type related
     TARGETS_EMPTY, TARGETS_NON_VALID, POLICY_TYPE_ALREADY_EXIST,
     // Group Type related
diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/exception/OperationException.java b/catalog-model/src/main/java/org/openecomp/sdc/be/exception/OperationException.java
new file mode 100644 (file)
index 0000000..6a647b1
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 Nordix Foundation.
+ *  ================================================================================
+ *  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=========================================================
+ */
+
+package org.openecomp.sdc.be.exception;
+
+public class OperationException extends BusinessException {
+
+    public OperationException(final String message) {
+        super(message);
+    }
+
+    public OperationException(final Throwable cause) {
+        super(cause);
+    }
+
+    public OperationException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+
+}
diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/exception/supplier/DataTypeOperationExceptionSupplier.java b/catalog-model/src/main/java/org/openecomp/sdc/be/exception/supplier/DataTypeOperationExceptionSupplier.java
new file mode 100644 (file)
index 0000000..75cacdd
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 Nordix Foundation.
+ *  ================================================================================
+ *  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=========================================================
+ */
+
+package org.openecomp.sdc.be.exception.supplier;
+
+import java.util.function.Supplier;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.openecomp.sdc.be.exception.OperationException;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class DataTypeOperationExceptionSupplier {
+
+    public static Supplier<OperationException> unexpectedErrorWhileFetchingProperties(final String uniqueId) {
+        final String errorMessage = String.format("An unexpected error has occurred while retrieving the data type '%s' properties", uniqueId);
+        return () -> new OperationException(errorMessage);
+    }
+
+}
diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/dto/PropertyDefinitionDto.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/dto/PropertyDefinitionDto.java
new file mode 100644 (file)
index 0000000..bac73d9
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 Nordix Foundation.
+ *  ================================================================================
+ *  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=========================================================
+ */
+
+package org.openecomp.sdc.be.model.dto;
+
+import java.util.List;
+import lombok.Data;
+import org.openecomp.sdc.be.model.PropertyConstraint;
+
+@Data
+public class PropertyDefinitionDto {
+
+    private String uniqueId;
+    private String type;
+    private String name;
+    private Boolean required;
+    private Object value;
+    private Object defaultValue;
+    private List<PropertyConstraint> constraints;
+
+}
diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/mapper/PropertyDefinitionDtoMapper.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/mapper/PropertyDefinitionDtoMapper.java
new file mode 100644 (file)
index 0000000..8566f55
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 Nordix Foundation.
+ *  ================================================================================
+ *  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=========================================================
+ */
+
+package org.openecomp.sdc.be.model.mapper;
+
+import com.google.gson.Gson;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.collections4.CollectionUtils;
+import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
+import org.openecomp.sdc.be.model.PropertyConstraint;
+import org.openecomp.sdc.be.model.PropertyDefinition;
+import org.openecomp.sdc.be.model.dto.PropertyDefinitionDto;
+
+public class PropertyDefinitionDtoMapper {
+
+    public static PropertyDefinition mapTo(final PropertyDefinitionDto propertyDefinitionDto) {
+        final var propertyDefinition = new PropertyDefinition();
+        propertyDefinition.setUniqueId(propertyDefinitionDto.getUniqueId());
+        propertyDefinition.setType(propertyDefinitionDto.getType());
+        propertyDefinition.setRequired(propertyDefinitionDto.getRequired());
+        propertyDefinition.setName(propertyDefinitionDto.getName());
+        if (CollectionUtils.isNotEmpty(propertyDefinitionDto.getConstraints())) {
+            final List<PropertyConstraint> propertyConstraints = new ArrayList<>();
+            propertyDefinition.setConstraints(propertyConstraints);
+            propertyConstraints.addAll(propertyDefinitionDto.getConstraints());
+        }
+        propertyDefinition.setValue(new Gson().toJson(propertyDefinitionDto.getValue()));
+        propertyDefinition.setDefaultValue(new Gson().toJson(propertyDefinitionDto.getDefaultValue()));
+        return propertyDefinition;
+    }
+
+    public static PropertyDefinitionDto mapFrom(final PropertyDataDefinition propertyDataDefinition) {
+        final var propertyDefinition = new PropertyDefinition(propertyDataDefinition);
+        final var propertyDefinitionDto = new PropertyDefinitionDto();
+        propertyDefinitionDto.setUniqueId(propertyDefinition.getUniqueId());
+        propertyDefinitionDto.setType(propertyDefinition.getType());
+        propertyDefinitionDto.setRequired(propertyDefinition.getRequired());
+        propertyDefinitionDto.setName(propertyDefinition.getName());
+        if (CollectionUtils.isNotEmpty(propertyDefinition.getConstraints())) {
+            final List<PropertyConstraint> propertyConstraints = new ArrayList<>();
+            propertyDefinitionDto.setConstraints(propertyConstraints);
+            propertyConstraints.addAll(propertyDefinition.getConstraints());
+        }
+        propertyDefinitionDto.setValue(new Gson().fromJson(propertyDataDefinition.getValue(), Object.class));
+        propertyDefinitionDto.setDefaultValue(new Gson().fromJson(propertyDataDefinition.getDefaultValue(), Object.class));
+        return propertyDefinitionDto;
+    }
+}
index f75e3cf..4194ab7 100644 (file)
@@ -21,11 +21,13 @@ package org.openecomp.sdc.be.model.operations.impl;
 import fj.data.Either;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections4.MapUtils;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.janusgraph.core.JanusGraph;
@@ -38,6 +40,8 @@ import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
 import org.openecomp.sdc.be.datatypes.elements.DataTypeDataDefinition;
 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
+import org.openecomp.sdc.be.exception.supplier.DataTypeOperationExceptionSupplier;
+import org.openecomp.sdc.be.model.PropertyDefinition;
 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException;
 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
 import org.openecomp.sdc.be.resources.data.DataTypeData;
@@ -53,6 +57,7 @@ public class DataTypeOperation extends AbstractOperation {
     private static final Logger LOGGER = LoggerFactory.getLogger(DataTypeOperation.class);
 
     private ModelOperation modelOperation;
+    private PropertyOperation propertyOperation;
 
     @Autowired
     public DataTypeOperation(final HealingJanusGraphGenericDao janusGraphGenericDao) {
@@ -65,6 +70,11 @@ public class DataTypeOperation extends AbstractOperation {
         this.modelOperation = modelOperation;
     }
 
+    @Autowired
+    public void setPropertyOperation(PropertyOperation propertyOperation) {
+        this.propertyOperation = propertyOperation;
+    }
+
     public List<DataTypeData> getAllDataTypeNodes() {
         final List<DataTypeData> dataTypesFound = new ArrayList<>();
         final Either<List<DataTypeData>, JanusGraphOperationStatus> getAllDataTypesWithNullModel =
@@ -172,4 +182,26 @@ public class DataTypeOperation extends AbstractOperation {
         }
         return Optional.of(dataTypeEither.left().value().getDataTypeDataDefinition());
     }
+
+    public List<PropertyDefinition> findAllProperties(final String uniqueId) {
+        final Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> propertiesEither =
+            propertyOperation.findPropertiesOfNode(NodeTypeEnum.DataType, uniqueId);
+        if (propertiesEither.isRight()) {
+            final JanusGraphOperationStatus status = propertiesEither.right().value();
+            if (status == JanusGraphOperationStatus.NOT_FOUND) {
+                return List.of();
+            }
+            LOGGER.error("Could not retrieve data type '{}' properties. JanusGraphOperationStatus: '{}'", uniqueId, status);
+
+            throw DataTypeOperationExceptionSupplier.unexpectedErrorWhileFetchingProperties(uniqueId).get();
+        }
+        final Map<String, PropertyDefinition> propertyMap = propertiesEither.left().value();
+        if (MapUtils.isEmpty(propertyMap)) {
+            return List.of();
+        }
+        final List<PropertyDefinition> propertyDefinitions = new ArrayList<>(propertyMap.values());
+        propertyDefinitions.sort(Comparator.comparing(PropertyDefinition::getName));
+        return propertyDefinitions;
+    }
+
 }
index 6b58052..9e5c2e4 100644 (file)
@@ -330,13 +330,9 @@ public class PropertyOperation extends AbstractOperation implements IPropertyOpe
         List<PropertyConstraint> constraints = propertyDefinition.getConstraints();
         propertyDefinition.setUniqueId(UniqueIdBuilder.buildPropertyUniqueId(uniqueId, propertyName));
         PropertyData propertyData = new PropertyData(propertyDefinition, convertConstraintsToString(constraints));
-        if (log.isDebugEnabled()) {
-            log.debug(BEFORE_ADDING_PROPERTY_TO_GRAPH, propertyData);
-        }
+        log.debug(BEFORE_ADDING_PROPERTY_TO_GRAPH, propertyData);
         Either<PropertyData, JanusGraphOperationStatus> createNodeResult = janusGraphGenericDao.createNode(propertyData, PropertyData.class);
-        if (log.isDebugEnabled()) {
-            log.debug(AFTER_ADDING_PROPERTY_TO_GRAPH, propertyData);
-        }
+        log.debug(AFTER_ADDING_PROPERTY_TO_GRAPH, propertyData);
         if (createNodeResult.isRight()) {
             JanusGraphOperationStatus operationStatus = createNodeResult.right().value();
             log.error("Failed to add property {} to graph. status is {}", propertyName, operationStatus);
@@ -346,8 +342,8 @@ public class PropertyOperation extends AbstractOperation implements IPropertyOpe
         props.put(GraphPropertiesDictionary.NAME.getProperty(), propertyName);
         UniqueIdData uniqueIdData = new UniqueIdData(nodeType, uniqueId);
         log.debug("Before associating {} to property {}", uniqueIdData, propertyName);
-        Either<GraphRelation, JanusGraphOperationStatus> createRelResult = janusGraphGenericDao
-            .createRelation(uniqueIdData, propertyData, GraphEdgeLabels.PROPERTY, props);
+        Either<GraphRelation, JanusGraphOperationStatus> createRelResult =
+            janusGraphGenericDao.createRelation(uniqueIdData, propertyData, GraphEdgeLabels.PROPERTY, props);
         if (createRelResult.isRight()) {
             JanusGraphOperationStatus operationStatus = createNodeResult.right().value();
             log.error(FAILED_TO_ASSOCIATE_RESOURCE_TO_PROPERTY_IN_GRAPH_STATUS_IS, uniqueId, propertyName, operationStatus);
index 0efb751..1f448fd 100644 (file)
@@ -20,6 +20,7 @@ package org.openecomp.sdc.be.model.operations.impl;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
@@ -43,8 +44,11 @@ import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
 import org.openecomp.sdc.be.datatypes.elements.DataTypeDataDefinition;
 import org.openecomp.sdc.be.datatypes.enums.ModelTypeEnum;
 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
+import org.openecomp.sdc.be.exception.OperationException;
+import org.openecomp.sdc.be.exception.supplier.DataTypeOperationExceptionSupplier;
 import org.openecomp.sdc.be.model.DataTypeDefinition;
 import org.openecomp.sdc.be.model.Model;
+import org.openecomp.sdc.be.model.PropertyDefinition;
 import org.openecomp.sdc.be.resources.data.DataTypeData;
 import org.springframework.test.context.ContextConfiguration;
 
@@ -57,6 +61,8 @@ class DataTypeOperationTest {
     private ModelOperation modelOperation;
     @Mock
     private HealingJanusGraphGenericDao janusGraphGenericDao;
+    @Mock
+    private PropertyOperation propertyOperation;
 
     private final String modelName = "ETSI-SDC-MODEL-TEST";
     private final List<DataTypeData> dataTypesWithoutModel = new ArrayList<>();
@@ -69,6 +75,7 @@ class DataTypeOperationTest {
     void beforeEachInit() {
         MockitoAnnotations.openMocks(this);
         dataTypeOperation.setModelOperation(modelOperation);
+        dataTypeOperation.setPropertyOperation(propertyOperation);
         initTestData();
     }
 
@@ -135,6 +142,51 @@ class DataTypeOperationTest {
         assertTrue(result.isEmpty());
     }
 
+    @Test
+    void findAllPropertiesTest_Success() {
+        final PropertyDefinition property1 = new PropertyDefinition();
+        property1.setName("property1");
+        final PropertyDefinition property2 = new PropertyDefinition();
+        property2.setName("property2");
+        final PropertyDefinition property3 = new PropertyDefinition();
+        property3.setName("property3");
+
+        when(propertyOperation.findPropertiesOfNode(NodeTypeEnum.DataType, "uniqueId"))
+            .thenReturn(Either.left(Map.of(property3.getName(), property3, property1.getName(), property1, property2.getName(), property2)));
+        final List<PropertyDefinition> dataTypeProperties = dataTypeOperation.findAllProperties("uniqueId");
+        assertEquals(3, dataTypeProperties.size());
+        assertEquals(property1.getName(), dataTypeProperties.get(0).getName());
+        assertEquals(property2.getName(), dataTypeProperties.get(1).getName());
+        assertEquals(property3.getName(), dataTypeProperties.get(2).getName());
+    }
+
+    @Test
+    void findAllPropertiesTest_propertiesNotFoundSuccess() {
+        when(propertyOperation.findPropertiesOfNode(NodeTypeEnum.DataType, "uniqueId"))
+            .thenReturn(Either.right(JanusGraphOperationStatus.NOT_FOUND));
+        final List<PropertyDefinition> dataTypeProperties = dataTypeOperation.findAllProperties("uniqueId");
+        assertTrue(dataTypeProperties.isEmpty());
+    }
+
+    @Test
+    void findAllPropertiesTest_emptyPropertiesSuccess() {
+        when(propertyOperation.findPropertiesOfNode(NodeTypeEnum.DataType, "uniqueId"))
+            .thenReturn(Either.left(Map.of()));
+        final List<PropertyDefinition> dataTypeProperties = dataTypeOperation.findAllProperties("uniqueId");
+        assertTrue(dataTypeProperties.isEmpty());
+    }
+
+    @Test
+    void findAllPropertiesTest_unknownError() {
+        final String uniqueId = "uniqueId";
+        when(propertyOperation.findPropertiesOfNode(NodeTypeEnum.DataType, uniqueId))
+            .thenReturn(Either.right(JanusGraphOperationStatus.GENERAL_ERROR));
+        final OperationException actualException = assertThrows(OperationException.class, () -> dataTypeOperation.findAllProperties(uniqueId));
+        final OperationException expectedException =
+            DataTypeOperationExceptionSupplier.unexpectedErrorWhileFetchingProperties(uniqueId).get();
+        assertEquals(expectedException.getMessage(), actualException.getMessage());
+    }
+
     private void initTestData() {
         model = new Model(modelName, ModelTypeEnum.NORMATIVE);
         final String TEST_DATA_TYPE_001 = "test.data.type001";
index 4b462b7..5a7e165 100644 (file)
@@ -302,6 +302,7 @@ const SDC_MENU_CONFIG = {
         ],
         "DataType": [
             {"text": "General", "action": "onMenuItemPressed", "state": "general"},
+            {"text": "Properties", "action": "onMenuItemPressed", "state": "properties"},
         ]
     }
 
index 097bbb2..b8cccdd 100644 (file)
@@ -197,5 +197,17 @@ export class PropertyBEModel {
     public isToscaFunction(): boolean {
         return this.toscaFunction != null;
     }
+
+    /**
+     * Gets the schema type, if there is a schema. Otherwise, returns undefined.
+     *
+     * @return the schema type.
+     */
+    public getSchemaType(): string {
+        if (this.schema && this.schema.property) {
+            return this.schema.property.type;
+        }
+        return undefined;
+    }
 }
 
diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.html b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.html
new file mode 100644 (file)
index 0000000..61c319e
--- /dev/null
@@ -0,0 +1,62 @@
+<!--
+  ~ -
+  ~  ============LICENSE_START=======================================================
+  ~  Copyright (C) 2022 Nordix Foundation.
+  ~  ================================================================================
+  ~  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=========================================================
+  -->
+
+<div class="workspace-properties">
+  <div id="left-top-bar">
+    <span id="properties-count">{{'PROPERTY_SHOWING_LABEL' | translate}}: {{filteredProperties.length}} of {{properties.length}}</span>
+    <input id="search-by-name" type="search" [placeholder]="'SEARCH_LABEL' | translate" [ngModel]="tableFilterTerm" (ngModelChange)="this.tableSearchTermUpdate.next($event)"/>
+    <span class="sprite magnification-glass search-button"></span>
+  </div>
+  <div class="table-container-flex">
+    <div class="table" [ngClass]="{'view-mode': isViewOnly}">
+      <div class="head flex-container">
+        <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">
+            <div class="table-col-general flex-item text" [title]="property.name">
+              <a [attr.data-tests-id]="'property-name-' + property.name" [ngClass]="{'disabled': isViewOnly}">{{property.name}}</a>
+            </div>
+
+            <div class="table-col-general flex-item text" [title]="property.type">
+              <span [attr.data-tests-id]="'property-type-' + property.name">{{property.type}}</span>
+            </div>
+            <div class="table-col-general flex-item text" [title]="property.getSchemaType() || ''">
+              <span [attr.data-tests-id]="'property-schema-' + property.name">{{property.getSchemaType() || ''}}</span>
+            </div>
+            <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"></div>
+          </div>
+      </div>
+
+    </div>
+  </div>
+
+</div>
diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.less b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.less
new file mode 100644 (file)
index 0000000..9c101e8
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 Nordix Foundation.
+ *  ================================================================================
+ *  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/sprite-old";
+@import "../../../../../assets/styles/mixins_old";
+
+.workspace-properties {
+
+    width: 93%;
+    display: inline-block;
+
+    #left-top-bar {
+        float: left;
+        width: 186px;
+
+        ::-webkit-input-placeholder {
+            font-style: italic;
+        }
+
+        :-moz-placeholder {
+            font-style: italic;
+        }
+
+        ::-moz-placeholder {
+            font-style: italic;
+        }
+
+        :-ms-input-placeholder {
+            font-style: italic;
+        }
+
+        #properties-count {
+            font-weight: bold;
+            float: left;
+        }
+
+        #search-by-name {
+            -webkit-border-radius: 2px;
+            -moz-border-radius: 2px;
+            border-radius: 2px;
+            width: 270px;
+            height: 32px;
+            line-height: 32px;
+            border: 1px solid @main_color_o;
+            text-indent: 10px;
+        }
+
+        .search-button {
+            .hand;
+            cursor: pointer;
+            float: right;
+            position: relative;
+            top: -22px;
+            right: -80px;
+        }
+    }
+
+    .delete-col-header {
+        .sprite();
+        .sprite.e-sdc-small-icon-delete();
+    }
+
+    .table {
+        height: 100%;
+        min-height: 500px;
+        margin-bottom: 0;
+    }
+
+    .data-row {
+        .table-delete-btn {
+            display: none !important;
+        }
+
+        &:hover {
+            .table-delete-btn {
+                display: inline-block !important;
+            }
+        }
+    }
+
+    .table-container-flex {
+        margin-top: 0;
+        overflow: scroll;
+        &::-webkit-scrollbar-track {
+            border: 0;
+        }
+
+        .text {
+            overflow: hidden;
+            text-overflow: ellipsis;
+            display: inline-block;
+            white-space: nowrap;
+        }
+
+        .flex-item:nth-child(1) {
+            flex-grow: 15;
+
+            a {
+                .hand
+            }
+        }
+
+        .flex-item:nth-child(2) {
+            flex-grow: 6;
+        }
+
+        .flex-item:nth-child(3) {
+            flex-grow: 6;
+        }
+
+        .flex-item:nth-child(4) {
+            flex-grow: 20;
+            white-space: normal;
+        }
+
+        .flex-item:nth-child(5) {
+            flex-grow: 3;
+            padding-top: 10px;
+        }
+
+    }
+
+}
diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.spec.ts b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.spec.ts
new file mode 100644 (file)
index 0000000..6be572d
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 Nordix Foundation.
+ *  ================================================================================
+ *  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 {async, ComponentFixture, TestBed} from '@angular/core/testing';
+
+import {TypeWorkspacePropertiesComponent} from './type-workspace-properties.component';
+import {FormsModule} from "@angular/forms";
+import {TranslateModule} from "../../../shared/translator/translate.module";
+import {TranslateService} from "../../../shared/translator/translate.service";
+import {DataTypeService} from "../../../services/data-type.service";
+import {Observable} from "rxjs/Observable";
+import {DataTypeModel} from "../../../../models/data-types";
+import {Component, ViewChild} from "@angular/core";
+import {PropertyBEModel} from "../../../../models/properties-inputs/property-be-model";
+
+describe('TypeWorkspacePropertiesComponent', () => {
+    const messages = require("../../../../../assets/languages/en_US.json");
+    let testHostComponent: TestHostComponent;
+    let testHostFixture: ComponentFixture<TestHostComponent>;
+    let dataTypeServiceMock: Partial<DataTypeService> = {
+        findAllProperties: jest.fn( (dataTypeId) => {
+            if (dataTypeId === 'dataTypeId') {
+                const property1 = new PropertyBEModel();
+                property1.name = 'property1'
+                property1.type = 'string'
+                return Observable.of([property1]);
+            }
+            return Observable.of([]);
+        })
+    };
+
+    let translateServiceMock: Partial<TranslateService> = {
+        'translate': jest.fn( (translateKey: string) => {
+            return messages[translateKey];
+        })
+    };
+
+    beforeEach(async(() => {
+        TestBed.configureTestingModule({
+            declarations: [TypeWorkspacePropertiesComponent, TestHostComponent],
+            imports: [
+                TranslateModule,
+                FormsModule
+            ],
+            providers: [
+                {provide: DataTypeService, useValue: dataTypeServiceMock},
+                {provide: TranslateService, useValue: translateServiceMock}
+            ]
+        })
+        .compileComponents();
+    }));
+
+    beforeEach(() => {
+        testHostFixture = TestBed.createComponent(TestHostComponent);
+        testHostComponent = testHostFixture.componentInstance;
+        testHostFixture.detectChanges();
+    });
+
+    it('should create', () => {
+        expect(testHostComponent).toBeTruthy();
+    });
+
+    it('empty property list', () => {
+        const element = testHostFixture.nativeElement;
+        const div: HTMLDivElement = element.querySelector('.no-row-text');
+        expect(div.textContent).toContain(messages.PROPERTY_LIST_EMPTY_MESSAGE);
+    });
+
+    it('test property list', () => {
+        testHostFixture = TestBed.createComponent(TestHostComponent);
+        testHostComponent = testHostFixture.componentInstance;
+        const dataType = new DataTypeModel();
+        dataType.uniqueId = 'dataTypeId';
+        testHostComponent.typeWorkspacePropertiesComponent.dataType = dataType;
+        testHostFixture.detectChanges();
+
+        const element = testHostFixture.nativeElement;
+        expect(element.querySelector('.no-row-text')).toBeFalsy();
+        const expectedPropertyName = 'property1';
+        const propertyNameLink: HTMLAnchorElement = element.querySelector(`a[data-tests-id^="property-name-${expectedPropertyName}"]`);
+        expect(propertyNameLink.textContent).toContain(expectedPropertyName);
+    });
+
+    @Component({
+        selector: 'host-component',
+        template: `<app-type-workspace-properties></app-type-workspace-properties>`
+    })
+    class TestHostComponent {
+        @ViewChild(TypeWorkspacePropertiesComponent)
+        public typeWorkspacePropertiesComponent: TypeWorkspacePropertiesComponent;
+    }
+
+});
diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.ts b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.ts
new file mode 100644 (file)
index 0000000..931fd3d
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 Nordix Foundation.
+ *  ================================================================================
+ *  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, OnInit} from '@angular/core';
+import {DataTypeModel} from "../../../../models/data-types";
+import {DataTypeService} from "../../../services/data-type.service";
+import {PropertyBEModel} from "../../../../models/properties-inputs/property-be-model";
+import { Subject } from "rxjs";
+import {debounceTime, distinctUntilChanged} from "rxjs/operators";
+
+@Component({
+  selector: 'app-type-workspace-properties',
+  templateUrl: './type-workspace-properties.component.html',
+  styleUrls: ['./type-workspace-properties.component.less']
+})
+export class TypeWorkspacePropertiesComponent implements OnInit {
+  @Input() isViewOnly = true;
+  @Input() dataType: DataTypeModel = new DataTypeModel();
+
+  properties: Array<PropertyBEModel> = [];
+  filteredProperties: Array<PropertyBEModel> = [];
+  tableHeadersList: Array<TableHeader> = [];
+  tableSortBy: string = 'name';
+  tableColumnReverse: boolean = false;
+  tableFilterTerm: string = undefined;
+  tableSearchTermUpdate = new Subject<string>();
+
+  constructor(private dataTypeService: DataTypeService) { }
+
+  ngOnInit(): void {
+    this.initTable();
+    this.initProperties();
+    this.tableSearchTermUpdate.pipe(
+        debounceTime(400),
+        distinctUntilChanged())
+    .subscribe(searchTerm => {
+      this.filter(searchTerm);
+    });
+  }
+
+  private initTable(): void {
+    this.tableHeadersList = [
+      {title: 'Name', property: 'name'},
+      {title: 'Type', property: 'type'},
+      {title: 'Schema', property: 'schema.property.type'},
+      {title: 'Description', property: 'description'},
+    ];
+
+    this.tableSortBy = this.tableHeadersList[0].property;
+  }
+
+  private initProperties(): void {
+    this.dataTypeService.findAllProperties(this.dataType.uniqueId).subscribe(properties => {
+      this.properties = properties.map(value => new PropertyBEModel(value));
+      this.filteredProperties = Array.from(this.properties);
+      this.sort();
+    });
+  }
+
+  onUpdateSort(property: string): void {
+    if (this.tableSortBy === property) {
+      this.tableColumnReverse = !this.tableColumnReverse;
+    } else {
+      this.tableColumnReverse = false;
+      this.tableSortBy = property;
+    }
+    this.sort();
+  }
+
+  private sort(): void {
+    const field = this.tableSortBy;
+    this.filteredProperties = this.filteredProperties.sort((property1, property2) => {
+      const result = property1[field] > property2[field] ? 1 : property1[field] < property2[field] ? -1 : 0;
+      return this.tableColumnReverse ? result * -1 : result;
+    });
+  }
+
+  private filter(searchTerm: string): void {
+    if (searchTerm) {
+      searchTerm = searchTerm.toLowerCase();
+      this.filteredProperties = this.properties.filter(property =>
+          property.name.toLowerCase().includes(searchTerm)
+          || property.type.toLowerCase().includes(searchTerm)
+          || (property.getSchemaType() && property.getSchemaType().toLowerCase().includes(searchTerm))
+          || (property.description && property.description.toLowerCase().includes(searchTerm))
+      );
+    } else {
+      this.filteredProperties = Array.from(this.properties);
+    }
+    this.sort();
+  }
+}
+
+interface TableHeader {
+  title: string;
+  property: string;
+}
\ No newline at end of file
index 8d6ae02..193c94e 100644 (file)
             {{currentMenu.text}}
           </div>
         </div>
-        <div class="w-sdc-main-container-body-content">
-          <app-type-workspace-general *ngIf="currentMenu.state === 'general' && dataType" [dataType]="dataType"></app-type-workspace-general>
+        <div class="w-sdc-main-container-body-content" *ngIf="dataType">
+          <app-type-workspace-general *ngIf="currentMenu.state === 'general'" [dataType]="dataType"></app-type-workspace-general>
+          <app-type-workspace-properties *ngIf="currentMenu.state === 'properties'" [dataType]="dataType"></app-type-workspace-properties>
         </div>
+
       </div>
 
     </div>
index 8450da8..fcad472 100644 (file)
@@ -22,7 +22,7 @@
 import {async, ComponentFixture, TestBed} from '@angular/core/testing';
 
 import {TypeWorkspaceComponent} from './type-workspace.component';
-import {ReactiveFormsModule} from "@angular/forms";
+import {FormsModule, ReactiveFormsModule} from "@angular/forms";
 import {TranslateModule} from "../../shared/translator/translate.module";
 import {UiElementsModule} from "../../components/ui/ui-elements.module";
 import {DataTypeService} from "../../services/data-type.service";
@@ -37,6 +37,7 @@ import {ISdcConfig, SdcConfigToken} from "../../config/sdc-config.config";
 import {States} from "../../../utils/constants";
 import {IUserProperties} from "../../../models/user";
 import {Observable} from "rxjs/Observable";
+import {TypeWorkspacePropertiesComponent} from "./type-workspace-properties/type-workspace-properties.component";
 
 describe('TypeWorkspaceComponent', () => {
   let component: TypeWorkspaceComponent;
@@ -88,9 +89,10 @@ describe('TypeWorkspaceComponent', () => {
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      declarations: [ TypeWorkspaceComponent, WorkspaceMenuComponent, TypeWorkspaceGeneralComponent ],
+      declarations: [ TypeWorkspaceComponent, WorkspaceMenuComponent, TypeWorkspaceGeneralComponent, TypeWorkspacePropertiesComponent ],
       imports: [
         ReactiveFormsModule,
+        FormsModule,
         TranslateModule,
         UiElementsModule,
         LayoutModule
index d3f391d..021f84a 100644 (file)
@@ -28,9 +28,10 @@ import {UiElementsModule} from "../../components/ui/ui-elements.module";
 import {LayoutModule} from "../../components/layout/layout.module";
 import {TypeWorkspaceGeneralComponent} from './type-workspace-general/type-workspace-general.component';
 import {UpgradeModule} from "@angular/upgrade/static";
-import {ReactiveFormsModule} from "@angular/forms";
+import {FormsModule, ReactiveFormsModule} from "@angular/forms";
 import {TranslateModule} from "../../shared/translator/translate.module";
 import {DataTypeService} from "../../services/data-type.service";
+import { TypeWorkspacePropertiesComponent } from './type-workspace-properties/type-workspace-properties.component';
 
 @NgModule({
     imports: [
@@ -40,11 +41,13 @@ import {DataTypeService} from "../../services/data-type.service";
         UpgradeModule,
         ReactiveFormsModule,
         TranslateModule,
+        FormsModule,
     ],
     declarations: [
         TypeWorkspaceComponent,
         WorkspaceMenuComponent,
-        TypeWorkspaceGeneralComponent
+        TypeWorkspaceGeneralComponent,
+        TypeWorkspacePropertiesComponent
     ],
     providers: [
         CacheService,
index bf500ec..74d48d3 100644 (file)
@@ -20,7 +20,7 @@
 
 import * as _ from "lodash";
 import {Inject, Injectable} from '@angular/core';
-import { DataTypeModel, DataTypesMap, PropertyFEModel, DerivedFEProperty} from "app/models";
+import {DataTypeModel, DataTypesMap, PropertyFEModel, DerivedFEProperty, PropertyBEModel} 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";
@@ -78,6 +78,11 @@ export class DataTypeService {
         return this.httpClient.get<DataTypeModel>(url);
     }
 
+    public findAllProperties(id: string): Observable<Array<PropertyBEModel>> {
+        const url = `${this.dataTypeUrl}/${id}/properties`
+        return this.httpClient.get<Array<PropertyBEModel>>(url);
+    }
+
     public getConstraintsByParentTypeAndUniqueID(rootPropertyType, propertyName){
         // const property = this.dataTypes[rootPropertyType].properties.filter(property =>
         //     property.name == propertyName);
index 3f5a107..c3a6bc9 100644 (file)
@@ -41,6 +41,7 @@
   "GENERAL_LABEL_SYSTEM_NAME": "System Name:",
   "GENERAL_LABEL_SOURCE_SERVICE_NAME": "Source Service Name:",
   "GENERAL_LABEL_RESOURCE_CUSTOMIZATION_UUID": "Resource Customization UUID:",
+  "SEARCH_LABEL": "Search",
   "=========== GENERAL_TAB ===========": "",
   "GENERAL_TAB_LABEL_RESOURCE_MODEL_NUMBER": "Vendor Model Number",
   "GENERAL_TAB_LABEL_SERVICE_TYPE": "Service Type",
   "MODIFIED_LABEL": "Modified",
   "UNIQUE_ID_LABEL": "Unique Id",
   "=========== SERVICE IMPORT ===========": "",
-  "IMPORT_FAILURE_MESSAGE_TEXT": "Import Failure - error reading CSAR"
+  "IMPORT_FAILURE_MESSAGE_TEXT": "Import Failure - error reading CSAR",
+  "=========== PROPERTIES ===========": "",
+  "PROPERTY_LIST_EMPTY_MESSAGE": "There are no properties to display",
+  "PROPERTY_SHOWING_LABEL": "Showing Properties"
 }