Download data type from UI 23/132923/5
authorKrupaNagabhushan <krupa.nagabhushan@est.tech>
Wed, 26 Oct 2022 16:26:54 +0000 (17:26 +0100)
committerKrupaNagabhushan <krupa.nagabhushan@est.tech>
Thu, 19 Jan 2023 15:23:12 +0000 (15:23 +0000)
Issue-ID: SDC-4332
Signed-off-by: KrupaNagabhushan <krupa.nagabhushan@est.tech>
Change-Id: If31f7a95eb2d568e716760a33ef2641bad09cf68

16 files changed:
catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesFetchServlet.java
catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java
catalog-be/src/test/java/org/openecomp/sdc/be/servlets/TypesFetchServletTest.java
catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaExportHandlerTest.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperation.java
catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperationTest.java
catalog-ui/configurations/menu.js
catalog-ui/src/app/ng2/components/ui/download-artifact/download-artifact.component.ts
catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-tosca-artifacts/type-workspace-tosca-artifact-page.component.html [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-tosca-artifacts/type-workspace-tosca-artifact-page.component.less [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-tosca-artifacts/type-workspace-tosca-artifact-page.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/pages/workspace/tosca-artifacts/tosca-artifact-page.component.ts
catalog-ui/src/app/services/data-types-service.ts

index fd8b618..efdae4d 100644 (file)
@@ -33,6 +33,7 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.stream.Collectors;
 import javax.inject.Inject;
 import javax.servlet.http.HttpServletRequest;
@@ -46,6 +47,7 @@ import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.collections4.ListUtils;
 import org.openecomp.sdc.be.components.impl.ArtifactTypeBusinessLogic;
 import org.openecomp.sdc.be.components.impl.CapabilitiesBusinessLogic;
@@ -57,6 +59,8 @@ import org.openecomp.sdc.be.components.impl.ResourceBusinessLogic;
 import org.openecomp.sdc.be.components.impl.ResourceImportManager;
 import org.openecomp.sdc.be.components.impl.aaf.AafPermission;
 import org.openecomp.sdc.be.components.impl.aaf.PermissionAllowed;
+import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
+import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
 import org.openecomp.sdc.be.config.BeEcompErrorManager;
 import org.openecomp.sdc.be.dao.api.ActionStatus;
 import org.openecomp.sdc.be.datamodel.api.HighestFilterEnum;
@@ -65,6 +69,7 @@ import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
 import org.openecomp.sdc.be.exception.BusinessException;
 import org.openecomp.sdc.be.impl.ComponentsUtils;
 import org.openecomp.sdc.be.impl.ServletUtils;
+import org.openecomp.sdc.be.model.ArtifactUiDownloadData;
 import org.openecomp.sdc.be.model.CapabilityTypeDefinition;
 import org.openecomp.sdc.be.model.Component;
 import org.openecomp.sdc.be.model.DataTypeDefinition;
@@ -72,7 +77,9 @@ import org.openecomp.sdc.be.model.InterfaceDefinition;
 import org.openecomp.sdc.be.model.Model;
 import org.openecomp.sdc.be.model.RelationshipTypeDefinition;
 import org.openecomp.sdc.be.model.User;
+import org.openecomp.sdc.be.model.operations.impl.DataTypeOperation;
 import org.openecomp.sdc.be.model.operations.impl.ModelOperation;
+import org.openecomp.sdc.be.tosca.ToscaExportHandler;
 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
 import org.openecomp.sdc.common.api.Constants;
 import org.openecomp.sdc.common.datastructure.Wrapper;
@@ -92,12 +99,15 @@ public class TypesFetchServlet extends AbstractValidationsServlet {
     private static final Logger log = Logger.getLogger(TypesFetchServlet.class);
     private static final String FAILED_TO_GET_ALL_NON_ABSTRACT = "failed to get all non abstract {}";
     private static final String START_HANDLE_REQUEST_OF_MODIFIER_ID_IS = "Start handle request of {} | modifier id is {}";
+    private static final String DATATYPE_FILE_TYPE = ".yml";
     private final RelationshipTypeBusinessLogic relationshipTypeBusinessLogic;
     private final CapabilitiesBusinessLogic capabilitiesBusinessLogic;
     private final InterfaceOperationBusinessLogic interfaceOperationBusinessLogic;
     private final ResourceBusinessLogic resourceBusinessLogic;
     private final ArtifactTypeBusinessLogic artifactTypeBusinessLogic;
     private final ModelOperation modelOperation;
+    private final DataTypeOperation dataTypeOperation;
+    private final ToscaExportHandler toscaExportUtils;
 
     @Inject
     public TypesFetchServlet(
@@ -110,7 +120,9 @@ public class TypesFetchServlet extends AbstractValidationsServlet {
         InterfaceOperationBusinessLogic interfaceOperationBusinessLogic,
         ResourceBusinessLogic resourceBusinessLogic,
         ArtifactTypeBusinessLogic artifactTypeBusinessLogic,
-        ModelOperation modelOperation
+        ModelOperation modelOperation,
+        DataTypeOperation dataTypeOperation,
+        ToscaExportHandler toscaExportUtils
     ) {
         super(
             componentInstanceBL,
@@ -124,6 +136,8 @@ public class TypesFetchServlet extends AbstractValidationsServlet {
         this.resourceBusinessLogic = resourceBusinessLogic;
         this.artifactTypeBusinessLogic = artifactTypeBusinessLogic;
         this.modelOperation = modelOperation;
+        this.dataTypeOperation = dataTypeOperation;
+        this.toscaExportUtils = toscaExportUtils;
     }
 
     @GET
@@ -197,6 +211,35 @@ public class TypesFetchServlet extends AbstractValidationsServlet {
         return responseWrapper.getInnerElement();
     }
 
+    @GET
+    @Path("downloadDataType")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    @Operation(description = "Get data types", method = "GET", summary = "Returns all data types from all models", responses = {
+        @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
+        @ApiResponse(responseCode = "200", description = "allDataTypes"), @ApiResponse(responseCode = "403", description = "Restricted operation"),
+        @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
+        @ApiResponse(responseCode = "404", description = "Data types not found")})
+    @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
+    public Response downloadDataType(@Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId,
+                                     @Parameter(description = "dataTypeId") @QueryParam("dataTypeId") String dataTypeId) {
+        Wrapper<Response> responseWrapper = new Wrapper<>();
+        Wrapper<User> userWrapper = new Wrapper<>();
+        init();
+        validateUserExist(responseWrapper, userWrapper, userId);
+        Response response;
+        try {
+            String url = request.getMethod() + " " + request.getRequestURI();
+            log.info(START_HANDLE_REQUEST_OF_MODIFIER_ID_IS, url, userId);
+            response = handleDataTypeDownloadRequest(dataTypeId);
+        } catch (Exception e) {
+            BeEcompErrorManager.getInstance().logBeRestApiGeneralError("downloadResourceArtifactBase64");
+            log.debug("downloadResourceArtifactBase64 unexpected exception", e);
+            throw e;
+        }
+        return response;
+    }
+
     @GET
     @Path("interfaceLifecycleTypes")
     @Consumes(MediaType.APPLICATION_JSON)
@@ -422,4 +465,24 @@ public class TypesFetchServlet extends AbstractValidationsServlet {
                 component -> ((ResourceMetadataDataDefinition) component.getComponentMetadataDefinition().getMetadataDataDefinition())
                     .getToscaResourceName(), component -> component, (component1, component2) -> component1)));
     }
+
+    private Response handleDataTypeDownloadRequest(final String dataTypeId) {
+        Optional<DataTypeDefinition> dataTypeDefinition = dataTypeOperation.handleDataTypeDownloadRequestById(dataTypeId);
+        Either<byte[], ComponentException> toscaExportDataType = toscaExportUtils.exportDataType(dataTypeDefinition.get()).left()
+            .map(toscaRepresentation -> {
+                log.debug("Tosca yaml exported for Datatype {} ", dataTypeDefinition.get().getUniqueId());
+                return toscaRepresentation.getMainYaml();
+            }).right().map(toscaError -> {
+                log.debug("Failed export tosca yaml for DataType {} error {}", dataTypeDefinition.get().getUniqueId(), toscaError);
+                return new ByActionStatusComponentException(componentsUtils.convertFromToscaError(toscaError));
+            });
+        byte[] file = toscaExportDataType.left().value();
+        String base64Contents = new String(Base64.encodeBase64(file));
+        String artifactName = dataTypeDefinition.get().getName() + DATATYPE_FILE_TYPE;
+        ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
+        ArtifactUiDownloadData artifactUiDownloadData = new ArtifactUiDownloadData();
+        artifactUiDownloadData.setArtifactName(artifactName);
+        artifactUiDownloadData.setBase64Contents(base64Contents);
+        return buildOkResponse(responseFormat, artifactUiDownloadData);
+    }
 }
index 68795e1..313bef5 100644 (file)
@@ -226,6 +226,10 @@ public class ToscaExportHandler {
         return convertToToscaTemplate(component).left().map(this::createToscaRepresentation);
     }
 
+    public Either<ToscaRepresentation, ToscaError> exportDataType(DataTypeDefinition dataTypeDefinition) {
+        return convertDataTypeToToscaTemplate(dataTypeDefinition).left().map(this::createToscaRepresentation);
+    }
+
     public Either<ToscaRepresentation, ToscaError> exportComponentInterface(final Component component, final boolean isAssociatedComponent) {
         final List<Map<String, Map<String, String>>> imports = new ArrayList<>(getDefaultToscaImports(component.getModel()));
         if (CollectionUtils.isEmpty(imports)) {
@@ -316,6 +320,39 @@ public class ToscaExportHandler {
         }
     }
 
+    private Either<ToscaTemplate, ToscaError> convertDataTypeToToscaTemplate(final DataTypeDefinition dataTypeDefinition) {
+        final ToscaTemplate toscaTemplate = new ToscaTemplate(TOSCA_VERSION);
+        return convertDataTypeTosca(dataTypeDefinition, toscaTemplate);
+    }
+
+    private Either<ToscaTemplate, ToscaError> convertDataTypeTosca(final DataTypeDefinition dataTypeDefinition, final ToscaTemplate toscaTemplate) {
+        final var dataTypesEither = applicationDataTypeCache.getAll(dataTypeDefinition.getModel());
+        if (dataTypesEither.isRight()) {
+            log.debug("Failed to fetch all data types :", dataTypesEither.right().value());
+            return Either.right(ToscaError.GENERAL_ERROR);
+        }
+        Map<String, DataTypeDefinition> dataTypes = dataTypesEither.left().value();
+        if (!dataTypeDefinition.isEmpty()) {
+            Map<String, ToscaDataType> toscaDataTypeMap = new HashMap<>();
+            ToscaDataType toscaDataType = new ToscaDataType();
+            toscaDataType.setDerived_from(dataTypeDefinition.getDerivedFromName());
+            toscaDataType.setDescription(dataTypeDefinition.getDescription());
+            toscaDataType.setVersion(dataTypeDefinition.getVersion());
+            if (CollectionUtils.isNotEmpty(dataTypeDefinition.getProperties())) {
+                toscaDataType.setProperties(dataTypeDefinition.getProperties().stream()
+                    .collect(Collectors.toMap(
+                        PropertyDataDefinition::getName,
+                        s -> propertyConvertor.convertProperty(dataTypes, s, PropertyType.PROPERTY),
+                        (toscaPropertyTobeValidated, toscaProperty) -> validateToscaProperty((List<DataTypeDefinition>) dataTypeDefinition, toscaPropertyTobeValidated,
+                            toscaProperty)
+                    )));
+            }
+            toscaDataTypeMap.put(dataTypeDefinition.getName(), toscaDataType);
+            toscaTemplate.setData_types(toscaDataTypeMap);
+        }
+        return Either.left(toscaTemplate);
+    }
+
     private List<Map<String, Map<String, String>>> getDefaultToscaImports(final String modelId) {
         if (modelId == null) {
             return getDefaultToscaImportConfig();
index d7f23f1..3de087f 100644 (file)
@@ -63,9 +63,11 @@ import org.openecomp.sdc.be.impl.WebAppContextWrapper;
 import org.openecomp.sdc.be.model.Component;
 import org.openecomp.sdc.be.model.Resource;
 import org.openecomp.sdc.be.model.User;
+import org.openecomp.sdc.be.model.operations.impl.DataTypeOperation;
 import org.openecomp.sdc.be.model.operations.impl.ModelOperation;
 import org.openecomp.sdc.be.servlets.builder.ServletResponseBuilder;
 import org.openecomp.sdc.be.servlets.exception.OperationExceptionMapper;
+import org.openecomp.sdc.be.tosca.ToscaExportHandler;
 import org.openecomp.sdc.be.user.Role;
 import org.openecomp.sdc.be.user.UserBusinessLogic;
 import org.openecomp.sdc.common.api.ConfigurationSource;
@@ -119,6 +121,10 @@ class TypesFetchServletTest extends JerseyTest {
     private ResponseFormatManager responseFormatManager;
     @Mock
     private ModelOperation modelOperation;
+    @Mock
+    private DataTypeOperation dataTypeOperation;
+    @Mock
+    private ToscaExportHandler toscaExportHandler;
 
     private final Path rootPath = Path.of("/v1/catalog");
     private final Path nodeTypesPath = rootPath.resolve("nodeTypes");
@@ -218,6 +224,8 @@ class TypesFetchServletTest extends JerseyTest {
                     bind(interfaceOperationBusinessLogic).to(InterfaceOperationBusinessLogic.class);
                     bind(artifactTypeBusinessLogic).to(ArtifactTypeBusinessLogic.class);
                     bind(modelOperation).to(ModelOperation.class);
+                    bind(dataTypeOperation).to(DataTypeOperation.class);
+                    bind(toscaExportHandler).to(ToscaExportHandler.class);
                 }
             })
             .register(new OperationExceptionMapper(
@@ -264,6 +272,10 @@ class TypesFetchServletTest extends JerseyTest {
             .thenReturn(artifactTypeBusinessLogic);
         when(webApplicationContext.getBean(ModelOperation.class))
             .thenReturn(modelOperation);
+        when(webApplicationContext.getBean(DataTypeOperation.class))
+            .thenReturn(dataTypeOperation);
+        when(webApplicationContext.getBean(ToscaExportHandler.class))
+            .thenReturn(toscaExportHandler);
     }
 
     void initConfig() {
index 736fcbc..7d16c90 100644 (file)
@@ -290,6 +290,16 @@ class ToscaExportHandlerTest extends BaseConfDependent {
         assertNotNull(result);
     }
 
+    @Test
+    void testExportDataType() {
+        DataTypeDefinition dataTypeDefinition = new DataTypeDefinition();
+        dataTypeDefinition.setUniqueId("uniqueId");
+        Either<ToscaRepresentation, ToscaError> result;
+        when(applicationDataTypeCache.getAll(null)).thenReturn(Either.left(new HashMap<>()));
+        result = testSubject.exportDataType(dataTypeDefinition);
+        assertNotNull(result);
+    }
+
     @Test
     void testConvertInterfaceNodeTypeProperties() {
 
index 7cd042a..d75302f 100644 (file)
@@ -28,6 +28,7 @@ import java.util.Map;
 import java.util.Optional;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.collections4.MapUtils;
+import org.apache.commons.lang.StringUtils;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.janusgraph.core.JanusGraph;
@@ -42,6 +43,7 @@ import org.openecomp.sdc.be.datatypes.elements.DataTypeDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
 import org.openecomp.sdc.be.exception.supplier.DataTypeOperationExceptionSupplier;
+import org.openecomp.sdc.be.model.DataTypeDefinition;
 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;
@@ -208,6 +210,18 @@ public class DataTypeOperation extends AbstractOperation {
         return propertyDefinitions;
     }
 
+    public Optional<DataTypeDefinition> handleDataTypeDownloadRequestById(final String dataTypeId) {
+        if (StringUtils.isNotEmpty(dataTypeId)) {
+            Optional<DataTypeDataDefinition> dataTypeDataDefinition = getDataTypeByUid(dataTypeId);
+            if (dataTypeDataDefinition.isPresent()) {
+                DataTypeDefinition dataTypeDefinition = new DataTypeDefinition(dataTypeDataDefinition.get());
+                dataTypeDefinition.setProperties(findAllProperties(dataTypeId));
+                return Optional.of(dataTypeDefinition);
+            }
+        }
+        return Optional.empty();
+    }
+
     public PropertyDefinitionDto createProperty(final String dataTypeId, final PropertyDefinitionDto propertyDefinitionDto) {
         final String propertyName = propertyDefinitionDto.getName();
         LOGGER.debug("Adding property '{}' to data type '{}'.", propertyName, dataTypeId);
index 26fb765..034269b 100644 (file)
@@ -268,6 +268,34 @@ class DataTypeOperationTest {
         assertArrayEquals(expectedException.getParams(), actualException.getParams());
     }
 
+    @Test
+    void handleDataTypeDownloadRequestById_Success() {
+        final PropertyDefinition property1 = new PropertyDefinition();
+        property1.setName("property1");
+        final PropertyDefinition property2 = new PropertyDefinition();
+        property2.setName("property2");
+
+        when(janusGraphGenericDao.getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.DataType), "test.data.type00099", DataTypeData.class))
+            .thenReturn(Either.left(createDataTypeData("test.data.type99", "test.data.type00099", 888L, 999L, modelName)));
+        when(propertyOperation.findPropertiesOfNode(NodeTypeEnum.DataType, "test.data.type00099"))
+            .thenReturn(Either.left(Map.of(property1.getName(), property1, property2.getName(), property2)));
+
+        final Optional<DataTypeDefinition> dataType = dataTypeOperation.handleDataTypeDownloadRequestById("test.data.type00099");
+        assertTrue(dataType.isPresent());
+        assertEquals("test.data.type99", dataType.get().getName());
+        assertEquals("test.data.type00099", dataType.get().getUniqueId());
+        assertEquals(modelName, dataType.get().getModel());
+        assertEquals(2, dataType.get().getProperties().size());
+        assertEquals(property1.getName(), dataType.get().getProperties().get(0).getName());
+        assertEquals(property2.getName(), dataType.get().getProperties().get(1).getName());
+    }
+
+    @Test
+    void handleDataTypeDownloadRequestById_Fail() {
+        final Optional<DataTypeDefinition> dataType = dataTypeOperation.handleDataTypeDownloadRequestById("");
+        assertTrue(dataType.isEmpty());
+    }
+
     private void initTestData() {
         model = new Model(modelName, ModelTypeEnum.NORMATIVE);
         final String TEST_DATA_TYPE_001 = "test.data.type001";
index 5a7e165..a5114d8 100644 (file)
@@ -303,6 +303,7 @@ const SDC_MENU_CONFIG = {
         "DataType": [
             {"text": "General", "action": "onMenuItemPressed", "state": "general"},
             {"text": "Properties", "action": "onMenuItemPressed", "state": "properties"},
+            {"text": "TOSCA Artifacts", "action": "onMenuItemPressed", "state": "tosca_artifacts"}
         ]
     }
 
index 8f47456..fee2e0e 100644 (file)
@@ -1,5 +1,5 @@
 import { Component, Input } from "@angular/core";
-import {IFileDownload, Component as TopologyTemplate, ArtifactModel, FullComponentInstance} from "app/models";
+import {IFileDownload, ArtifactModel} from "app/models";
 import {EventListenerService} from "app/services";
 import {CacheService} from "app/services-ng2";
 import {EVENTS} from "app/utils";
@@ -59,8 +59,8 @@ export class DownloadArtifactComponent {
 
     public download = (event) => {
         event.stopPropagation();
-        let onFaild = (response):void => {
-            console.info('onFaild', response);
+        let onFailed = (response):void => {
+            console.info('onFailed', response);
             this.removeDownloadedFileLoader();
         };
 
@@ -72,9 +72,9 @@ export class DownloadArtifactComponent {
         this.setDownloadedFileLoader();
 
         if (this.isInstance) {
-            this.componentInstanceService.downloadInstanceArtifact(this.workspaceService.metadata.componentType, this.workspaceService.metadata.uniqueId, this.componentId, this.artifact.uniqueId).subscribe(onSuccess, onFaild);
+            this.componentInstanceService.downloadInstanceArtifact(this.workspaceService.metadata.componentType, this.workspaceService.metadata.uniqueId, this.componentId, this.artifact.uniqueId).subscribe(onSuccess, onFailed);
         } else {
-            this.topologyTemplateService.downloadArtifact(this.componentType, this.componentId, this.artifact.uniqueId).subscribe(onSuccess, onFaild);
+            this.topologyTemplateService.downloadArtifact(this.componentType, this.componentId, this.artifact.uniqueId).subscribe(onSuccess, onFailed);
         }
     };
 
diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-tosca-artifacts/type-workspace-tosca-artifact-page.component.html b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-tosca-artifacts/type-workspace-tosca-artifact-page.component.html
new file mode 100644 (file)
index 0000000..902b772
--- /dev/null
@@ -0,0 +1,40 @@
+<div class="tosca-artifact-page">
+    <ngx-datatable
+            columnMode="flex"
+            [headerHeight]="40"
+            [rowHeight]="35"
+            [reorderable]="false"
+            [swapColumns]="false"
+            [rows]="toscaArtifacts"
+            [sorts]="[{prop: 'artifactDisplayName', dir: 'desc'}]"
+            #toscaArtifactsTable
+            (activate)="onActivate($event)">
+        <ngx-datatable-column [resizeable]="false" name="Name" [flexGrow]="3"
+                              [prop]="'artifactDisplayName'">
+            <ng-template ngx-datatable-cell-template let-row="row">
+                <div class="expand-collapse-cell">
+                    <span>{{row.artifactDisplayName }}</span>
+                </div>
+            </ng-template>
+        </ngx-datatable-column>
+        <ngx-datatable-column [resizeable]="false"name="Type" [flexGrow]="3">
+            <ng-template ngx-datatable-cell-template let-row="row">
+                {{row.artifactType}}
+            </ng-template>
+        </ngx-datatable-column>
+        <ngx-datatable-column [resizeable]="false" name="Version" [flexGrow]="1">
+            <ng-template ngx-datatable-cell-template let-row="row">
+                {{ row.artifactVersion }}
+            </ng-template>
+        </ngx-datatable-column>
+        <ngx-datatable-column [resizeable]="false"[flexGrow]="1">
+            <ng-template ngx-datatable-cell-template let-row="row">
+                <div class="download-artifact-button">
+                    <svg-icon [mode]="'primary2'" [disabled]="disabled" [clickable]="!disabled" [name]="iconType"
+                              [testId]="testId" mode="info" clickable="true" size="medium" (click)="download($event)">
+                    </svg-icon>
+                </div>
+            </ng-template>
+        </ngx-datatable-column>
+    </ngx-datatable>
+</div>
\ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-tosca-artifacts/type-workspace-tosca-artifact-page.component.less b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-tosca-artifacts/type-workspace-tosca-artifact-page.component.less
new file mode 100644 (file)
index 0000000..9c5dd47
--- /dev/null
@@ -0,0 +1,7 @@
+.tosca-artifact-page {
+  .download-artifact-button {
+    text-align: center;
+    padding-top: 4px;
+
+  }
+}
\ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-tosca-artifacts/type-workspace-tosca-artifact-page.component.ts b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-tosca-artifacts/type-workspace-tosca-artifact-page.component.ts
new file mode 100644 (file)
index 0000000..f68ec8b
--- /dev/null
@@ -0,0 +1,117 @@
+import {Component, Input, OnInit, ViewChild} from "@angular/core";
+import {ArtifactModel, DataTypeModel, IFileDownload} from "../../../../models";
+import {Store} from "@ngxs/store";
+import {DataTypesService} from "../../../../services/data-types-service";
+
+@Component({
+    selector: 'app-type-workspace-tosca-artifact',
+    templateUrl: './type-workspace-tosca-artifact-page.component.html',
+    styleUrls: ['./type-workspace-tosca-artifact-page.component.less', '../../../../../assets/styles/table-style.less']
+})
+export class TypeWorkspaceToscaArtifactPageComponent implements OnInit {
+
+    @Input() dataType: DataTypeModel = new DataTypeModel();
+    @ViewChild('toscaArtifactsTable') table: any;
+    public toscaArtifacts: Array<ArtifactModel> = [];
+    public componentId: string;
+    public componentType: string;
+    public disabled: boolean;
+    public iconType: string;
+    public testId: string;
+
+    private DOWNLOAD_CSS_CLASSES = {
+        DOWNLOAD_ICON: "download-o",
+        LOADER_ICON: "spinner"
+    }
+
+    private DATATYPE_ARTIFACT = {
+        ARTIFACT_NAME : "Tosca Template",
+        ARTIFACT_TYPE : "TOSCA_TEMPLATE",
+        ARTIFACT_VERSION : "1"
+    }
+
+    constructor(private store: Store, private dataTypesService: DataTypesService) {
+    }
+
+    ngOnInit(): void {
+        this.iconType = this.DOWNLOAD_CSS_CLASSES.DOWNLOAD_ICON;
+        this.componentId = this.dataType.uniqueId;
+        this.componentType = 'datatype';
+
+        const artifactTemplateForDataType: ArtifactModel = new ArtifactModel();
+        artifactTemplateForDataType.artifactDisplayName = this.DATATYPE_ARTIFACT.ARTIFACT_NAME;
+        artifactTemplateForDataType.artifactType = this.DATATYPE_ARTIFACT.ARTIFACT_NAME;
+        artifactTemplateForDataType.artifactVersion = this.DATATYPE_ARTIFACT.ARTIFACT_VERSION;
+        this.toscaArtifacts.push(artifactTemplateForDataType);
+    }
+
+    onActivate(event) {
+        if (event.type === 'click') {
+            this.table.rowDetail.toggleExpandRow(event.row);
+        }
+    }
+
+    public download = (event) => {
+        event.stopPropagation();
+        this.dataTypesService.downloadDataType(this.componentId).then(
+            (file) => {
+                console.log("file", file.data);
+                if (file.data) {
+                    let blob = this.base64toBlob(file.data.base64Contents, '');
+                    let fileName = file.data.artifactName;
+                    this.triggerFileDownload(blob, fileName);
+                }
+            }
+        );
+    };
+
+    private downloadFile = (file:IFileDownload):void => {
+        if (file) {
+            let blob = this.base64toBlob(file.base64Contents, '');
+            let fileName = file.artifactName;
+            this.triggerFileDownload(blob, fileName);
+        }
+    };
+
+    public base64toBlob = (base64Data, contentType):any => {
+        let byteCharacters = atob(base64Data);
+        return this.byteCharactersToBlob(byteCharacters, contentType);
+    };
+
+    public byteCharactersToBlob = (byteCharacters, contentType):any => {
+        contentType = contentType || '';
+        let sliceSize = 1024;
+        let bytesLength = byteCharacters.length;
+        let slicesCount = Math.ceil(bytesLength / sliceSize);
+        let byteArrays = new Array(slicesCount);
+
+        for (let sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
+            let begin = sliceIndex * sliceSize;
+            let end = Math.min(begin + sliceSize, bytesLength);
+
+            let bytes = new Array(end - begin);
+            for (let offset = begin, i = 0; offset < end; ++i, ++offset) {
+                bytes[i] = byteCharacters[offset].charCodeAt(0);
+            }
+            byteArrays[sliceIndex] = new Uint8Array(bytes);
+        }
+        return new Blob(byteArrays, {type: contentType});
+    };
+
+    public triggerFileDownload = (blob, fileName):void=> {
+        let url = window.URL.createObjectURL(blob);
+        let downloadLink = document.createElement("a");
+
+        downloadLink.setAttribute('href', url);
+        downloadLink.setAttribute('download', fileName);
+        document.body.appendChild(downloadLink);
+
+        var clickEvent = new MouseEvent("click", {
+            "view": window,
+            "bubbles": true,
+            "cancelable": true
+        });
+        downloadLink.dispatchEvent(clickEvent);
+
+    }
+}
\ No newline at end of file
index 4d29e86..6151627 100644 (file)
@@ -45,6 +45,7 @@
         <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" [isViewOnly]="false"></app-type-workspace-properties>
+          <app-type-workspace-tosca-artifact *ngIf="currentMenu.state === 'tosca_artifacts'" [dataType]="dataType"></app-type-workspace-tosca-artifact>
         </div>
 
       </div>
index fcad472..3db2504 100644 (file)
@@ -38,6 +38,9 @@ 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";
+import {TypeWorkspaceToscaArtifactPageComponent} from "./type-workspace-tosca-artifacts/type-workspace-tosca-artifact-page.component";
+import {NgxDatatableModule} from "@swimlane/ngx-datatable";
+import {SvgIconModule} from "onap-ui-angular/dist/svg-icon/svg-icon.module";
 
 describe('TypeWorkspaceComponent', () => {
   let component: TypeWorkspaceComponent;
@@ -89,13 +92,15 @@ describe('TypeWorkspaceComponent', () => {
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      declarations: [ TypeWorkspaceComponent, WorkspaceMenuComponent, TypeWorkspaceGeneralComponent, TypeWorkspacePropertiesComponent ],
+      declarations: [ TypeWorkspaceComponent, WorkspaceMenuComponent, TypeWorkspaceGeneralComponent, TypeWorkspacePropertiesComponent, TypeWorkspaceToscaArtifactPageComponent ],
       imports: [
         ReactiveFormsModule,
         FormsModule,
         TranslateModule,
         UiElementsModule,
-        LayoutModule
+        LayoutModule,
+        NgxDatatableModule,
+        SvgIconModule
       ],
       providers: [
         {provide: DataTypeService, useValue: dataTypeServiceMock},
index 5b2d3bf..87b29b6 100644 (file)
@@ -31,13 +31,16 @@ import {UpgradeModule} from "@angular/upgrade/static";
 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';
+import { TypeWorkspacePropertiesComponent } from './type-workspace-properties/type-workspace-properties.component';
+import {NgxDatatableModule} from "@swimlane/ngx-datatable";
+import {SvgIconModule} from "onap-ui-angular/dist/svg-icon/svg-icon.module";
+import {TypeWorkspaceToscaArtifactPageComponent} from "./type-workspace-tosca-artifacts/type-workspace-tosca-artifact-page.component";
 import {ModalService} from "../../services/modal.service";
 import {AddPropertyComponent} from './type-workspace-properties/add-property/add-property.component';
 import {InterfaceOperationHandlerModule} from "../composition/interface-operatons/operation-creator/interface-operation-handler.module";
 
 @NgModule({
-    imports: [
+   imports: [
         CommonModule,
         UiElementsModule,
         LayoutModule,
@@ -46,12 +49,15 @@ import {InterfaceOperationHandlerModule} from "../composition/interface-operaton
         TranslateModule,
         FormsModule,
         InterfaceOperationHandlerModule,
+        NgxDatatableModule,
+        SvgIconModule,
     ],
     declarations: [
         TypeWorkspaceComponent,
         WorkspaceMenuComponent,
         TypeWorkspaceGeneralComponent,
         TypeWorkspacePropertiesComponent,
+        TypeWorkspaceToscaArtifactPageComponent,
         AddPropertyComponent,
     ],
     providers: [
index e74e5db..ef4112c 100644 (file)
@@ -4,12 +4,10 @@ import {SdcUiServices} from "onap-ui-angular";
 import {ArtifactModel} from "../../../../models";
 import {Select, Store} from "@ngxs/store";
 import {WorkspaceState} from "../../../store/states/workspace.state";
-import * as _ from "lodash";
-import {ArtifactGroupType, COMPONENT_FIELDS} from "../../../../utils";
+import {ArtifactGroupType} from "../../../../utils";
 import {GetArtifactsByTypeAction} from "../../../store/actions/artifacts.action";
 import {Observable} from "rxjs/index";
 import {ArtifactsState} from "../../../store/states/artifacts.state";
-import {ArtifactType} from "../../../../utils/constants";
 import {map} from "rxjs/operators";
 
 @Component({
index f3d02a2..09ece87 100644 (file)
@@ -24,7 +24,7 @@ import {
     ComponentInstance,
     DataTypeModel,
     DataTypesMap,
-    IAppConfigurtaion, InputModel,
+    IAppConfigurtaion, IFileDownload, InputModel,
     InputPropertyBase,
     PropertyModel,
     SchemaProperty
@@ -206,4 +206,9 @@ export class DataTypesService implements IDataTypesService {
         }
         return true;
     };
+
+    public downloadDataType = (dataTypeId: string): angular.IHttpPromise<IFileDownload> => {
+        console.log("dataTypeId", dataTypeId);
+        return this.$http.get<IFileDownload>(this.baseUrl + "downloadDataType" + ((dataTypeId) ? '?dataTypeId=' + dataTypeId : ''))
+    }
 }