diff options
16 files changed, 358 insertions, 14 deletions
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesFetchServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesFetchServlet.java index fd8b61887a..efdae4de96 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesFetchServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesFetchServlet.java @@ -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 @@ -198,6 +212,35 @@ public class TypesFetchServlet extends AbstractValidationsServlet { } @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) @Produces(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); + } } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java index 68795e1003..313bef57aa 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java @@ -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(); diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/TypesFetchServletTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/TypesFetchServletTest.java index d7f23f1b21..3de087ff32 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/TypesFetchServletTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/TypesFetchServletTest.java @@ -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() { diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaExportHandlerTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaExportHandlerTest.java index 736fcbcd7f..7d16c906c4 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaExportHandlerTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaExportHandlerTest.java @@ -291,6 +291,16 @@ class ToscaExportHandlerTest extends BaseConfDependent { } @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() { Resource component = getNewResource(); diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperation.java index 7cd042a27d..d75302fc5d 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperation.java @@ -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); diff --git a/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperationTest.java b/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperationTest.java index 26fb7658f1..034269b715 100644 --- a/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperationTest.java +++ b/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperationTest.java @@ -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"; diff --git a/catalog-ui/configurations/menu.js b/catalog-ui/configurations/menu.js index 5a7e165a9a..a5114d857a 100644 --- a/catalog-ui/configurations/menu.js +++ b/catalog-ui/configurations/menu.js @@ -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"} ] } diff --git a/catalog-ui/src/app/ng2/components/ui/download-artifact/download-artifact.component.ts b/catalog-ui/src/app/ng2/components/ui/download-artifact/download-artifact.component.ts index 8f47456a8f..fee2e0e91d 100644 --- a/catalog-ui/src/app/ng2/components/ui/download-artifact/download-artifact.component.ts +++ b/catalog-ui/src/app/ng2/components/ui/download-artifact/download-artifact.component.ts @@ -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 index 0000000000..902b772276 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-tosca-artifacts/type-workspace-tosca-artifact-page.component.html @@ -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 index 0000000000..9c5dd47585 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-tosca-artifacts/type-workspace-tosca-artifact-page.component.less @@ -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 index 0000000000..f68ec8b43c --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-tosca-artifacts/type-workspace-tosca-artifact-page.component.ts @@ -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 diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.html b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.html index 4d29e8673a..61516278da 100644 --- a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.html +++ b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.html @@ -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> diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.spec.ts b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.spec.ts index fcad472890..3db2504564 100644 --- a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.spec.ts +++ b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.spec.ts @@ -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}, diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.module.ts b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.module.ts index 5b2d3bf030..87b29b615d 100644 --- a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.module.ts +++ b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.module.ts @@ -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: [ diff --git a/catalog-ui/src/app/ng2/pages/workspace/tosca-artifacts/tosca-artifact-page.component.ts b/catalog-ui/src/app/ng2/pages/workspace/tosca-artifacts/tosca-artifact-page.component.ts index e74e5db668..ef4112c30c 100644 --- a/catalog-ui/src/app/ng2/pages/workspace/tosca-artifacts/tosca-artifact-page.component.ts +++ b/catalog-ui/src/app/ng2/pages/workspace/tosca-artifacts/tosca-artifact-page.component.ts @@ -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({ diff --git a/catalog-ui/src/app/services/data-types-service.ts b/catalog-ui/src/app/services/data-types-service.ts index f3d02a20c0..09ece87907 100644 --- a/catalog-ui/src/app/services/data-types-service.ts +++ b/catalog-ui/src/app/services/data-types-service.ts @@ -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 : '')) + } } |