Skip to content

Commit

Permalink
feat: add slots (#16)
Browse files Browse the repository at this point in the history
* feat: update maven dependencies

* feat: remove old code

* feat: add slots and refactoring methods

* feat: switch to new workspace api

* feat: fix sonar issues
  • Loading branch information
andrejpetras authored Apr 25, 2024
1 parent b9c99d6 commit 7ec4646
Show file tree
Hide file tree
Showing 6 changed files with 541 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ h| Version
| https://github.com/quarkiverse/quarkus-openapi-generator/blob/2.4.1/docs/modules/ROOT/pages/includes/quarkus-openapi-generator.adoc[Link]
| 2.4.1
| quarkus-rest-client-reactive-jackson
| quarkus-rest-client-jackson
| https://quarkus.io/guides/rest-client[Link]
|
Expand Down Expand Up @@ -104,12 +104,6 @@ h| Version
| https://github.com/quarkusio/quarkusio.github.io/blob/develop/_generated-doc/latest/config/quarkus-oidc.adoc[Link]
| 3.9.3
| quarkus-oidc-client-reactive-filter
| https://quarkus.io/guides/security-openid-connect-client-reference[Link]
| https://github.com/quarkusio/quarkusio.github.io/blob/develop/_generated-doc/latest/config/quarkus-oidc-client-reactive-filter.adoc[Link]
| 3.9.3
| onecx-core
| https://onecx.github.io/docs/onecx-quarkus/current/onecx-quarkus/onecx-core.html[Link]
Expand All @@ -129,5 +123,11 @@ h| Version
| 3.9.3
| quarkus-rest-client-oidc-filter
|
|
| 3.9.3
|===
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-client-reactive-jackson</artifactId>
<artifactId>quarkus-rest-client-jackson</artifactId>
</dependency>

<dependency>
Expand Down Expand Up @@ -84,7 +84,7 @@
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc-client-reactive-filter</artifactId>
<artifactId>quarkus-rest-client-oidc-filter</artifactId>
</dependency>
<!-- DEV -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,13 @@
import org.tkit.quarkus.log.cdi.LogService;

import gen.org.tkit.onecx.product.store.client.api.ProductsApi;
import gen.org.tkit.onecx.product.store.client.model.MicrofrontendTypePSV1;
import gen.org.tkit.onecx.product.store.client.model.ProductPSV1;
import gen.org.tkit.onecx.product.store.client.model.*;
import gen.org.tkit.onecx.shell.bff.rs.internal.WorkspaceConfigApiService;
import gen.org.tkit.onecx.shell.bff.rs.internal.model.*;
import gen.org.tkit.onecx.theme.client.api.ThemesApi;
import gen.org.tkit.onecx.theme.client.model.Theme;
import gen.org.tkit.onecx.workspace.client.api.WorkspaceExternalApi;
import gen.org.tkit.onecx.workspace.client.model.Workspace;
import gen.org.tkit.onecx.workspace.client.model.WorkspaceLoad;
import gen.org.tkit.onecx.workspace.client.model.*;

@ApplicationScoped
@Transactional(value = Transactional.TxType.NOT_SUPPORTED)
Expand Down Expand Up @@ -123,6 +121,40 @@ public Response getWorkspaceConfig(GetWorkspaceConfigRequestDTO getWorkspaceConf
}
}

@Override
public Response loadWorkspaceConfig(LoadWorkspaceConfigRequestDTO loadWorkspaceConfigRequestDTO) {

WorkspaceWrapper wrapper;
try (Response response = workspaceClient.loadWorkspaceByRequest(mapper.createRequest(loadWorkspaceConfigRequestDTO))) {
wrapper = response.readEntity(WorkspaceWrapper.class);
}

if (wrapper == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}

var result = mapper.createResponse(wrapper);

// load products and create corresponding module and components
if (wrapper.getProducts() != null) {
try (Response psResponse = productStoreClient.loadProductsByNames(mapper.create(wrapper))) {
var productResponse = psResponse.readEntity(LoadProductResponsePSV1.class);
mapper.createMfeAndComponents(result, wrapper, productResponse);
}
}

// create slots
result.setSlots(mapper.createSlots(wrapper.getSlots()));

//get theme info
try (Response themeResponse = themeClient.getThemeByName(wrapper.getTheme())) {
var theme = themeResponse.readEntity(Theme.class);
result.setTheme(mapper.createTheme(theme, uriInfo.getPath()));
}

return Response.ok(result).build();
}

@Override
public Response getThemeFaviconByName(String name) {
Response.ResponseBuilder responseBuilder;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
package org.tkit.onecx.shell.bff.rs.mappers;

import static gen.org.tkit.onecx.product.store.client.model.MicrofrontendTypePSV1.MODULE;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.mapstruct.AfterMapping;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;

import gen.org.tkit.onecx.product.store.client.model.MicrofrontendPSV1;
import gen.org.tkit.onecx.product.store.client.model.ProductItemSearchCriteriaPSV1;
import gen.org.tkit.onecx.product.store.client.model.ProductPSV1;
import gen.org.tkit.onecx.product.store.client.model.*;
import gen.org.tkit.onecx.shell.bff.rs.internal.model.*;
import gen.org.tkit.onecx.theme.client.model.Theme;
import gen.org.tkit.onecx.workspace.client.model.GetWorkspaceByUrlRequest;
import gen.org.tkit.onecx.workspace.client.model.Microfrontend;
import gen.org.tkit.onecx.workspace.client.model.Workspace;
import gen.org.tkit.onecx.workspace.client.model.WorkspaceAbstract;
import gen.org.tkit.onecx.workspace.client.model.*;

@Mapper
public interface WorkspaceConfigMapper {
Expand All @@ -25,11 +26,6 @@ public interface WorkspaceConfigMapper {
@Mapping(expression = "java( String.valueOf(themeInfo.getProperties()) )", target = "properties")
ThemeDTO mapTheme(Theme themeInfo);

@Mapping(target = "productNames", source = "products")
@Mapping(target = "pageSize", ignore = true)
@Mapping(target = "pageNumber", ignore = true)
ProductItemSearchCriteriaPSV1 map(WorkspaceAbstract workspaceInfo);

default RouteDTO mapRoute(MicrofrontendPSV1 mfe, ProductPSV1 product,
List<Microfrontend> wsMfes, String workspaceUrl) {
RouteDTO route = new RouteDTO();
Expand All @@ -48,4 +44,125 @@ default RouteDTO mapRoute(MicrofrontendPSV1 mfe, ProductPSV1 product,
}
return route;
}

WorkspaceLoadRequest createRequest(LoadWorkspaceConfigRequestDTO dto);

default LoadWorkspaceConfigResponseDTO createResponse(WorkspaceWrapper workspaceWrapper) {
return new LoadWorkspaceConfigResponseDTO().workspace(createWorkspace(workspaceWrapper));
}

WorkspaceDTO createWorkspace(WorkspaceWrapper workspaceWrapper);

@Mapping(target = "name", ignore = true)
@Mapping(target = "baseUrl", source = "mfe.remoteBaseUrl")
@Mapping(target = "remoteEntryUrl", source = "mfe.remoteEntry")
@Mapping(target = "productName", source = "product.name")
RemoteComponentDTO createComponent(LoadProductItemPSV1 product, LoadProductMicrofrontendPSV1 mfe);

@AfterMapping
default void componentName(@MappingTarget RemoteComponentDTO target, LoadProductItemPSV1 product,
LoadProductMicrofrontendPSV1 mfe) {
target.setName(componentName(product, mfe));
}

default String componentName(LoadProductItemPSV1 product, LoadProductMicrofrontendPSV1 mfe) {
String name = "";
if (product != null) {
name = product.getName();
}
if (mfe == null) {
return name;
}
return componentName(name, mfe.getAppId(), mfe.getExposedModule());
}

default String componentName(String productName, String appId, String exposedModule) {
return productName + "#" + appId + "#" + exposedModule;
}

@Mapping(target = "technology", constant = "ANGULAR")
@Mapping(target = "url", source = "mfe.remoteBaseUrl")
@Mapping(target = "pathMatch", constant = "PREFIX")
@Mapping(target = "baseUrl", ignore = true)
@Mapping(target = "remoteEntryUrl", source = "mfe.remoteEntry")
@Mapping(target = "displayName", source = "product.displayName")
@Mapping(target = "productName", source = "product.name")
@Mapping(target = "appId", source = "mfe.appId")
@Mapping(target = "exposedModule", source = "mfe.exposedModule")
@Mapping(target = "remoteName", source = "mfe.remoteName")
RouteDTO createRoute(LoadProductItemPSV1 product, LoadProductMicrofrontendPSV1 mfe, Map<String, String> pathMapping,
WorkspaceWrapper workspace);

@AfterMapping
default void createRouteAfter(@MappingTarget RouteDTO target, Map<String, String> pathMapping, WorkspaceWrapper workspace) {
var modulePath = pathMapping.get(target.getAppId());
if (modulePath != null) {
target.setBaseUrl(workspace.getBaseUrl() + modulePath);
}
}

List<SlotDTO> createSlots(List<WorkspaceWrapperSlot> slots);

default SlotDTO createSlot(WorkspaceWrapperSlot slot) {
if (slot == null) {
return null;
}

SlotDTO result = new SlotDTO().name(slot.getName());
if (slot.getComponents() != null) {
slot.getComponents()
.forEach(c -> result.addComponentsItem(componentName(c.getProductName(), c.getAppId(), c.getName())));
}
return result;
}

@Mapping(target = "properties", ignore = true)
ThemeDTO createTheme(Theme themeInfo, String path);

@AfterMapping
default void createThemeAfter(@MappingTarget ThemeDTO target, Theme themeInfo, String path) {
if (themeInfo != null) {
target.setProperties(String.valueOf(themeInfo.getProperties()));
}
if (target.getFaviconUrl() == null) {
target.setFaviconUrl(path + "/themes/" + target.getName() + "/favicon");
}
if (target.getLogoUrl() == null) {
target.setLogoUrl(path + "/themes/" + target.getName() + "/logo");
}
}

default LoadProductRequestPSV1 create(WorkspaceWrapper wrapper) {
return new LoadProductRequestPSV1().productNames(wrapper.getProducts().stream().map(Product::getProductName).toList());
}

default void createMfeAndComponents(LoadWorkspaceConfigResponseDTO result, WorkspaceWrapper wrapper,
LoadProductResponsePSV1 loadProducts) {
if (loadProducts == null || loadProducts.getProducts() == null) {
return;
}

var workspaceProducts = wrapper.getProducts().stream().collect(Collectors.toMap(Product::getProductName, p -> p));

loadProducts.getProducts().forEach(product -> {

var workspaceProduct = workspaceProducts.get(product.getName());

// create mapping APP_ID -> PATH
var pathMapping = workspaceProduct.getMicrofrontends().stream()
.collect(Collectors.toMap(Microfrontend::getMfeId, Microfrontend::getBasePath));

if (product.getMicrofrontends() != null) {
product.getMicrofrontends().forEach(mfe -> {
if (mfe.getType() == MODULE) {
result.addRoutesItem(createRoute(product, mfe, pathMapping, wrapper));
} else if (mfe.getType() == MicrofrontendTypePSV1.COMPONENT) {
result.addComponentsItem(createComponent(product, mfe));
}
});
}

});
}

}
70 changes: 70 additions & 0 deletions src/main/openapi/openapi-bff.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,32 @@ servers:
- url: http://onecx-shell-bff:8080/

paths:
/workspaceConfig/load:
post:
tags:
- "WorkspaceConfig"
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/LoadWorkspaceConfigRequest'
operationId: loadWorkspaceConfig
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/LoadWorkspaceConfigResponse'
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/ProblemDetailResponse'
'404':
description: 'Not Found'
/workspaceConfig:
post:
tags:
Expand Down Expand Up @@ -135,6 +161,50 @@ paths:

components:
schemas:
LoadWorkspaceConfigRequest:
type: object
required:
- path
properties:
path:
type: string
LoadWorkspaceConfigResponse:
type: object
required:
- 'routes'
- 'theme'
- 'workspace'
- 'components'
- 'slots'
properties:
routes:
type: array
items:
$ref: '#/components/schemas/Route'
theme:
$ref: '#/components/schemas/Theme'
workspace:
$ref: '#/components/schemas/Workspace'
components:
type: array
items:
$ref: '#/components/schemas/RemoteComponent'
slots:
type: array
items:
$ref: '#/components/schemas/Slot'
Slot:
type: object
required:
- 'name'
- 'components'
properties:
name:
type: string
components:
type: array
items:
type: string
GetWorkspaceConfigResponse:
type: object
required:
Expand Down
Loading

0 comments on commit 7ec4646

Please sign in to comment.