@platform-mesh/portal-server-lib 0.5.41 → 0.5.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/portal-options/service-providers/content-configuration-service-providers.service.js +10 -4
- package/dist/portal-options/service-providers/content-configuration-service-providers.service.js.map +1 -1
- package/dist/portal-options/service-providers/contentconfigurations-query.js +5 -3
- package/dist/portal-options/service-providers/contentconfigurations-query.js.map +1 -1
- package/dist/portal-options/service-providers/kubernetes-service-providers.service.js +7 -2
- package/dist/portal-options/service-providers/kubernetes-service-providers.service.js.map +1 -1
- package/dist/portal-options/service-providers/models/contentconfigurations.d.ts +3 -1
- package/dist/portal-options/services/kcp-k8s.service.js.map +1 -1
- package/dist/portal-options/utils/account-hierarchy-resolver.d.ts +4 -0
- package/dist/portal-options/utils/account-hierarchy-resolver.js +31 -0
- package/dist/portal-options/utils/account-hierarchy-resolver.js.map +1 -0
- package/package.json +2 -2
- package/src/portal-options/service-providers/content-configuration-service-providers.service.spec.ts +209 -29
- package/src/portal-options/service-providers/content-configuration-service-providers.service.ts +51 -41
- package/src/portal-options/service-providers/contentconfigurations-query.ts +5 -3
- package/src/portal-options/service-providers/kubernetes-service-providers.service.spec.ts +142 -0
- package/src/portal-options/service-providers/kubernetes-service-providers.service.ts +15 -5
- package/src/portal-options/service-providers/models/contentconfigurations.ts +1 -1
- package/src/portal-options/services/kcp-k8s.service.ts +1 -0
- package/src/portal-options/utils/account-hierarchy-resolver.spec.ts +347 -0
- package/src/portal-options/utils/account-hierarchy-resolver.ts +56 -0
package/dist/portal-options/service-providers/content-configuration-service-providers.service.js
CHANGED
|
@@ -4,6 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
+
import { processContentConfigurationForAccountHierarchy } from '../utils/account-hierarchy-resolver.js';
|
|
7
8
|
import { contentConfigurationsQuery } from './contentconfigurations-query.js';
|
|
8
9
|
import { welcomeNodeConfig } from './models/welcome-node-config.js';
|
|
9
10
|
import { Injectable } from '@nestjs/common';
|
|
@@ -20,9 +21,9 @@ let ContentConfigurationServiceProvidersService = class ContentConfigurationServ
|
|
|
20
21
|
throw new Error('Context with organization is required');
|
|
21
22
|
}
|
|
22
23
|
let url = context.crdGatewayApiUrl.replace('kubernetes-graphql-gateway/root', 'kubernetes-graphql-gateway/virtual-workspace/contentconfigurations/root');
|
|
23
|
-
const
|
|
24
|
-
if (
|
|
25
|
-
url = url.replace('/graphql', `:${
|
|
24
|
+
const accountPath = context?.accountPath ?? context?.['core_platform-mesh_io_account'];
|
|
25
|
+
if (accountPath) {
|
|
26
|
+
url = url.replace('/graphql', `:${accountPath}/graphql`);
|
|
26
27
|
}
|
|
27
28
|
console.log(`Calculated crd gateway api url: ${url}`);
|
|
28
29
|
const client = new GraphQLClient(url, {
|
|
@@ -36,7 +37,9 @@ let ContentConfigurationServiceProvidersService = class ContentConfigurationServ
|
|
|
36
37
|
throw new Error('Invalid response structure: missing ContentConfigurations');
|
|
37
38
|
}
|
|
38
39
|
const entity = !entities || !entities.length ? 'main' : entities[0];
|
|
39
|
-
const contentConfigurations = response.ui_platform_mesh_io.ContentConfigurations.
|
|
40
|
+
const contentConfigurations = response.ui_platform_mesh_io.ContentConfigurations.items
|
|
41
|
+
.filter((item) => item.metadata.labels?.['ui.platform-mesh.io/entity'] === entity)
|
|
42
|
+
.map((item) => {
|
|
40
43
|
try {
|
|
41
44
|
if (!item.status?.configurationResult) {
|
|
42
45
|
throw new Error(`Missing configurationResult for item: ${item.metadata?.name || 'unknown'}`);
|
|
@@ -45,6 +48,9 @@ let ContentConfigurationServiceProvidersService = class ContentConfigurationServ
|
|
|
45
48
|
if (!contentConfiguration.url) {
|
|
46
49
|
contentConfiguration.url = item.spec.remoteConfiguration?.url;
|
|
47
50
|
}
|
|
51
|
+
if (context.accountPath) {
|
|
52
|
+
processContentConfigurationForAccountHierarchy(contentConfiguration, context.accountPath);
|
|
53
|
+
}
|
|
48
54
|
return contentConfiguration;
|
|
49
55
|
}
|
|
50
56
|
catch (parseError) {
|
package/dist/portal-options/service-providers/content-configuration-service-providers.service.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content-configuration-service-providers.service.js","sourceRoot":"","sources":["../../../src/portal-options/service-providers/content-configuration-service-providers.service.ts"],"names":[],"mappings":";;;;;;AACA,OAAO,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AAE9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAM5C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGzC,IAAM,2CAA2C,GAAjD,MAAM,2CAA2C;
|
|
1
|
+
{"version":3,"file":"content-configuration-service-providers.service.js","sourceRoot":"","sources":["../../../src/portal-options/service-providers/content-configuration-service-providers.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { gql } from 'graphql-request';
|
|
2
2
|
export const contentConfigurationsQuery = gql `
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
query {
|
|
4
|
+
ui_platform_mesh_io {
|
|
5
|
+
ContentConfigurations {
|
|
6
|
+
items {
|
|
6
7
|
metadata {
|
|
7
8
|
name
|
|
8
9
|
labels
|
|
@@ -18,5 +19,6 @@ export const contentConfigurationsQuery = gql `
|
|
|
18
19
|
}
|
|
19
20
|
}
|
|
20
21
|
}
|
|
22
|
+
}
|
|
21
23
|
`;
|
|
22
24
|
//# sourceMappingURL=contentconfigurations-query.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contentconfigurations-query.js","sourceRoot":"","sources":["../../../src/portal-options/service-providers/contentconfigurations-query.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAEtC,MAAM,CAAC,MAAM,0BAA0B,GAAG,GAAG,CAAA
|
|
1
|
+
{"version":3,"file":"contentconfigurations-query.js","sourceRoot":"","sources":["../../../src/portal-options/service-providers/contentconfigurations-query.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAEtC,MAAM,CAAC,MAAM,0BAA0B,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;CAqB5C,CAAC"}
|
|
@@ -8,6 +8,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
8
8
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
9
|
};
|
|
10
10
|
import { KcpKubernetesService } from '../services/kcp-k8s.service.js';
|
|
11
|
+
import { processContentConfigurationForAccountHierarchy } from '../utils/account-hierarchy-resolver.js';
|
|
11
12
|
import { welcomeNodeConfig } from './models/welcome-node-config.js';
|
|
12
13
|
import { PromiseMiddlewareWrapper } from '@kubernetes/client-node/dist/gen/middleware.js';
|
|
13
14
|
import { Injectable } from '@nestjs/common';
|
|
@@ -52,6 +53,9 @@ let KubernetesServiceProvidersService = class KubernetesServiceProvidersService
|
|
|
52
53
|
if (!contentConfiguration.url) {
|
|
53
54
|
contentConfiguration.url = item.spec.remoteConfiguration?.url;
|
|
54
55
|
}
|
|
56
|
+
if (context.accountPath) {
|
|
57
|
+
processContentConfigurationForAccountHierarchy(contentConfiguration, context.accountPath);
|
|
58
|
+
}
|
|
55
59
|
return contentConfiguration;
|
|
56
60
|
});
|
|
57
61
|
return {
|
|
@@ -77,9 +81,10 @@ let KubernetesServiceProvidersService = class KubernetesServiceProvidersService
|
|
|
77
81
|
middleware: [
|
|
78
82
|
new PromiseMiddlewareWrapper({
|
|
79
83
|
pre: async (context) => {
|
|
80
|
-
const
|
|
84
|
+
const accountPath = requestContext?.accountPath ??
|
|
85
|
+
requestContext?.['core_platform-mesh_io_account'];
|
|
86
|
+
const kcpUrl = this.kcpKubernetesService.getKcpVirtualWorkspaceUrl(requestContext.organization, accountPath);
|
|
81
87
|
const path = `${kcpUrl}/apis/${gvr.group}/${gvr.version}/${gvr.plural}`;
|
|
82
|
-
console.log('kcp url: ', path);
|
|
83
88
|
context.setUrl(path);
|
|
84
89
|
context.setHeaderParam('Authorization', `Bearer ${token}`);
|
|
85
90
|
return context;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kubernetes-service-providers.service.js","sourceRoot":"","sources":["../../../src/portal-options/service-providers/kubernetes-service-providers.service.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,wBAAwB,EAAE,MAAM,gDAAgD,CAAC;AAC1F,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAQrC,IAAM,iCAAiC,GAAvC,MAAM,iCAAiC;
|
|
1
|
+
{"version":3,"file":"kubernetes-service-providers.service.js","sourceRoot":"","sources":["../../../src/portal-options/service-providers/kubernetes-service-providers.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,9 @@ export interface ContentConfigurationQueryResponse {
|
|
|
2
2
|
ui_platform_mesh_io: ContentConfigurationsResponse;
|
|
3
3
|
}
|
|
4
4
|
export interface ContentConfigurationsResponse {
|
|
5
|
-
ContentConfigurations:
|
|
5
|
+
ContentConfigurations: {
|
|
6
|
+
items: ContentConfigurationResponse[];
|
|
7
|
+
};
|
|
6
8
|
}
|
|
7
9
|
export interface ContentConfigurationResponse {
|
|
8
10
|
metadata: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kcp-k8s.service.js","sourceRoot":"","sources":["../../../src/portal-options/services/kcp-k8s.service.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAIrC,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;IACd,MAAM,CAAmB;IACzB,OAAO,CAAM;IAE9B;QACE,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;QACjD,MAAM,EAAE,GAAG,IAAI,UAAU,EAAE,CAAC;QAC5B,EAAE,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;QAE/B,EAAE,CAAC,OAAO,CAAC;YACT,IAAI,EAAE,MAAM;SACb,CAAC,CAAC;QACH,EAAE,CAAC,UAAU,CAAC;YACZ,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,EAAE,CAAC,iBAAiB,EAAE,EAAE,IAAI,IAAI,EAAE;SAC5C,CAAC,CAAC;QACH,EAAE,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC7B,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC,iBAAiB,EAAE,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC;QAC7D,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IACnD,CAAC;IAED,kBAAkB;QAChB,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAEO,kBAAkB,CAAC,YAAoB,EAAE,OAAgB;QAC/D,IAAI,IAAI,GAAG,aAAa,YAAY,EAAE,CAAC;QACvC,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,IAAI,IAAI,OAAO,EAAE,CAAC;QACxB,CAAC;
|
|
1
|
+
{"version":3,"file":"kcp-k8s.service.js","sourceRoot":"","sources":["../../../src/portal-options/services/kcp-k8s.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ContentConfiguration } from '@openmfp/portal-server-lib';
|
|
2
|
+
export declare const updateEntityTypeFromAccountPath: (contentConfiguration: ContentConfiguration, accountPath: string) => ContentConfiguration;
|
|
3
|
+
export declare const updateAccountNodeChildren: (contentConfiguration: ContentConfiguration, accountPath: string) => ContentConfiguration;
|
|
4
|
+
export declare const processContentConfigurationForAccountHierarchy: (contentConfiguration: ContentConfiguration, accountPath: string) => ContentConfiguration;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const ACCOUNT_ENTITY_TYPE = 'core_platform-mesh_io_account';
|
|
2
|
+
export const updateEntityTypeFromAccountPath = (contentConfiguration, accountPath) => {
|
|
3
|
+
contentConfiguration.luigiConfigFragment.data.nodes.forEach((node) => {
|
|
4
|
+
const accountPathParts = accountPath
|
|
5
|
+
.split(':')
|
|
6
|
+
.map((_, i) => `${ACCOUNT_ENTITY_TYPE}:${i + 1}`)
|
|
7
|
+
.join('.');
|
|
8
|
+
node.entityType = node.entityType.replace(ACCOUNT_ENTITY_TYPE, accountPathParts);
|
|
9
|
+
});
|
|
10
|
+
return contentConfiguration;
|
|
11
|
+
};
|
|
12
|
+
export const updateAccountNodeChildren = (contentConfiguration, accountPath) => {
|
|
13
|
+
const accountChildrenNode = contentConfiguration.luigiConfigFragment.data.nodes[0]?.children?.[0];
|
|
14
|
+
const nextHierarchyLevel = accountPath.split(':').length + 1;
|
|
15
|
+
if (accountChildrenNode) {
|
|
16
|
+
accountChildrenNode.defineEntity.id = `${ACCOUNT_ENTITY_TYPE}:${nextHierarchyLevel}`;
|
|
17
|
+
accountChildrenNode.context.accountId = `:${ACCOUNT_ENTITY_TYPE}Id:${nextHierarchyLevel}`;
|
|
18
|
+
accountChildrenNode.context[`${ACCOUNT_ENTITY_TYPE}Id`] =
|
|
19
|
+
`:${ACCOUNT_ENTITY_TYPE}Id:${nextHierarchyLevel}`;
|
|
20
|
+
accountChildrenNode.context.resourceId = `:${ACCOUNT_ENTITY_TYPE}Id:${nextHierarchyLevel}`;
|
|
21
|
+
accountChildrenNode.pathSegment = `:${ACCOUNT_ENTITY_TYPE}Id:${nextHierarchyLevel}`;
|
|
22
|
+
}
|
|
23
|
+
return contentConfiguration;
|
|
24
|
+
};
|
|
25
|
+
export const processContentConfigurationForAccountHierarchy = (contentConfiguration, accountPath) => {
|
|
26
|
+
if (contentConfiguration.name === 'accounts') {
|
|
27
|
+
updateAccountNodeChildren(contentConfiguration, accountPath);
|
|
28
|
+
}
|
|
29
|
+
return updateEntityTypeFromAccountPath(contentConfiguration, accountPath);
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=account-hierarchy-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-hierarchy-resolver.js","sourceRoot":"","sources":["../../../src/portal-options/utils/account-hierarchy-resolver.ts"],"names":[],"mappings":"AAKA,MAAM,mBAAmB,GAAG,+BAA+B,CAAC;AAE5D,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAC7C,oBAA0C,EAC1C,WAAmB,EACG,EAAE;IACxB,oBAAoB,CAAC,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QACnE,MAAM,gBAAgB,GAAG,WAAW;aACjC,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,mBAAmB,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;aAChD,IAAI,CAAC,GAAG,CAAC,CAAC;QAEb,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CACvC,mBAAmB,EACnB,gBAAgB,CACjB,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO,oBAAoB,CAAC;AAC9B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACvC,oBAA0C,EAC1C,WAAmB,EACG,EAAE;IACxB,MAAM,mBAAmB,GACvB,oBAAoB,CAAC,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;IACxE,MAAM,kBAAkB,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IAE7D,IAAI,mBAAmB,EAAE,CAAC;QACxB,mBAAmB,CAAC,YAAY,CAAC,EAAE,GAAG,GAAG,mBAAmB,IAAI,kBAAkB,EAAE,CAAC;QACrF,mBAAmB,CAAC,OAAO,CAAC,SAAS,GAAG,IAAI,mBAAmB,MAAM,kBAAkB,EAAE,CAAC;QAC1F,mBAAmB,CAAC,OAAO,CAAC,GAAG,mBAAmB,IAAI,CAAC;YACrD,IAAI,mBAAmB,MAAM,kBAAkB,EAAE,CAAC;QACpD,mBAAmB,CAAC,OAAO,CAAC,UAAU,GAAG,IAAI,mBAAmB,MAAM,kBAAkB,EAAE,CAAC;QAC3F,mBAAmB,CAAC,WAAW,GAAG,IAAI,mBAAmB,MAAM,kBAAkB,EAAE,CAAC;IACtF,CAAC;IAED,OAAO,oBAAoB,CAAC;AAC9B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,8CAA8C,GAAG,CAC5D,oBAA0C,EAC1C,WAAmB,EACG,EAAE;IACxB,IAAI,oBAAoB,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAC7C,yBAAyB,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAC;IAC/D,CAAC;IAED,OAAO,+BAA+B,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAC;AAC5E,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platform-mesh/portal-server-lib",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.43",
|
|
4
4
|
"author": "Platform Mesh",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"publishConfig": {
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"@types/supertest": "6.0.3",
|
|
62
62
|
"eslint": "9.39.2",
|
|
63
63
|
"eslint-config-prettier": "10.1.8",
|
|
64
|
-
"globals": "
|
|
64
|
+
"globals": "17.0.0",
|
|
65
65
|
"jest": "30.2.0",
|
|
66
66
|
"jest-junit": "16.0.0",
|
|
67
67
|
"jest-mock-extended": "4.0.0",
|
package/src/portal-options/service-providers/content-configuration-service-providers.service.spec.ts
CHANGED
|
@@ -70,18 +70,20 @@ describe('ContentConfigurationServiceProvidersService', () => {
|
|
|
70
70
|
it('returns parsed content configurations', async () => {
|
|
71
71
|
mockClient.request.mockResolvedValue({
|
|
72
72
|
ui_platform_mesh_io: {
|
|
73
|
-
ContentConfigurations:
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
73
|
+
ContentConfigurations: {
|
|
74
|
+
items: [
|
|
75
|
+
{
|
|
76
|
+
metadata: {
|
|
77
|
+
name: 'conf1',
|
|
78
|
+
labels: { 'ui.platform-mesh.io/entity': 'entity' },
|
|
79
|
+
},
|
|
80
|
+
spec: { remoteConfiguration: { url: 'http://remote' } },
|
|
81
|
+
status: {
|
|
82
|
+
configurationResult: JSON.stringify({ url: 'http://parsed' }),
|
|
83
|
+
},
|
|
78
84
|
},
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
configurationResult: JSON.stringify({ url: 'http://parsed' }),
|
|
82
|
-
},
|
|
83
|
-
},
|
|
84
|
-
],
|
|
85
|
+
],
|
|
86
|
+
},
|
|
85
87
|
},
|
|
86
88
|
});
|
|
87
89
|
const result = await service.getServiceProviders(
|
|
@@ -97,16 +99,18 @@ describe('ContentConfigurationServiceProvidersService', () => {
|
|
|
97
99
|
it('falls back to spec.remoteConfiguration.url if missing in parsed config', async () => {
|
|
98
100
|
mockClient.request.mockResolvedValue({
|
|
99
101
|
ui_platform_mesh_io: {
|
|
100
|
-
ContentConfigurations:
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
102
|
+
ContentConfigurations: {
|
|
103
|
+
items: [
|
|
104
|
+
{
|
|
105
|
+
metadata: {
|
|
106
|
+
name: 'conf1',
|
|
107
|
+
labels: { 'ui.platform-mesh.io/entity': 'entity' },
|
|
108
|
+
},
|
|
109
|
+
spec: { remoteConfiguration: { url: 'http://remote' } },
|
|
110
|
+
status: { configurationResult: JSON.stringify({}) },
|
|
105
111
|
},
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
},
|
|
109
|
-
],
|
|
112
|
+
],
|
|
113
|
+
},
|
|
110
114
|
},
|
|
111
115
|
});
|
|
112
116
|
const result = await service.getServiceProviders(
|
|
@@ -122,16 +126,18 @@ describe('ContentConfigurationServiceProvidersService', () => {
|
|
|
122
126
|
it('throws on missing configurationResult', async () => {
|
|
123
127
|
mockClient.request.mockResolvedValue({
|
|
124
128
|
ui_platform_mesh_io: {
|
|
125
|
-
ContentConfigurations:
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
129
|
+
ContentConfigurations: {
|
|
130
|
+
items: [
|
|
131
|
+
{
|
|
132
|
+
metadata: {
|
|
133
|
+
name: 'conf1',
|
|
134
|
+
labels: { 'ui.platform-mesh.io/entity': 'entity' },
|
|
135
|
+
},
|
|
136
|
+
spec: { remoteConfiguration: { url: 'http://remote' } },
|
|
137
|
+
status: {},
|
|
130
138
|
},
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
},
|
|
134
|
-
],
|
|
139
|
+
],
|
|
140
|
+
},
|
|
135
141
|
},
|
|
136
142
|
});
|
|
137
143
|
await expect(
|
|
@@ -154,4 +160,178 @@ describe('ContentConfigurationServiceProvidersService', () => {
|
|
|
154
160
|
service.getServiceProviders('token', ['entity'], context),
|
|
155
161
|
).rejects.toThrow('Failed to fetch content configurations: network error');
|
|
156
162
|
});
|
|
163
|
+
|
|
164
|
+
it('applies processContentConfigurationForAccountHierarchy when accountPath is provided', async () => {
|
|
165
|
+
context.accountPath = 'acc1';
|
|
166
|
+
mockClient.request.mockResolvedValue({
|
|
167
|
+
ui_platform_mesh_io: {
|
|
168
|
+
ContentConfigurations: {
|
|
169
|
+
items: [
|
|
170
|
+
{
|
|
171
|
+
metadata: {
|
|
172
|
+
name: 'conf1',
|
|
173
|
+
labels: { 'ui.platform-mesh.io/entity': 'entity' },
|
|
174
|
+
},
|
|
175
|
+
spec: { remoteConfiguration: { url: 'http://remote' } },
|
|
176
|
+
status: {
|
|
177
|
+
configurationResult: JSON.stringify({
|
|
178
|
+
name: 'test-config',
|
|
179
|
+
luigiConfigFragment: {
|
|
180
|
+
data: {
|
|
181
|
+
nodes: [{ entityType: 'core_platform-mesh_io_account' }],
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
}),
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
],
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
const result = await service.getServiceProviders(
|
|
193
|
+
'token',
|
|
194
|
+
['entity'],
|
|
195
|
+
context,
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
expect(
|
|
199
|
+
result.rawServiceProviders[0].contentConfiguration[0].luigiConfigFragment
|
|
200
|
+
.data.nodes[0].entityType,
|
|
201
|
+
).toBe('core_platform-mesh_io_account:1');
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('applies processContentConfigurationForAccountHierarchy with multi-level accountPath', async () => {
|
|
205
|
+
context.accountPath = 'acc1:acc2:acc3';
|
|
206
|
+
mockClient.request.mockResolvedValue({
|
|
207
|
+
ui_platform_mesh_io: {
|
|
208
|
+
ContentConfigurations: {
|
|
209
|
+
items: [
|
|
210
|
+
{
|
|
211
|
+
metadata: {
|
|
212
|
+
name: 'conf1',
|
|
213
|
+
labels: { 'ui.platform-mesh.io/entity': 'entity' },
|
|
214
|
+
},
|
|
215
|
+
spec: { remoteConfiguration: { url: 'http://remote' } },
|
|
216
|
+
status: {
|
|
217
|
+
configurationResult: JSON.stringify({
|
|
218
|
+
name: 'test-config',
|
|
219
|
+
luigiConfigFragment: {
|
|
220
|
+
data: {
|
|
221
|
+
nodes: [{ entityType: 'core_platform-mesh_io_account' }],
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
}),
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
],
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const result = await service.getServiceProviders(
|
|
233
|
+
'token',
|
|
234
|
+
['entity'],
|
|
235
|
+
context,
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
expect(
|
|
239
|
+
result.rawServiceProviders[0].contentConfiguration[0].luigiConfigFragment
|
|
240
|
+
.data.nodes[0].entityType,
|
|
241
|
+
).toBe(
|
|
242
|
+
'core_platform-mesh_io_account:1.core_platform-mesh_io_account:2.core_platform-mesh_io_account:3',
|
|
243
|
+
);
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it('updates account children nodes for accounts configuration with accountPath', async () => {
|
|
247
|
+
context.accountPath = 'acc1';
|
|
248
|
+
mockClient.request.mockResolvedValue({
|
|
249
|
+
ui_platform_mesh_io: {
|
|
250
|
+
ContentConfigurations: {
|
|
251
|
+
items: [
|
|
252
|
+
{
|
|
253
|
+
metadata: {
|
|
254
|
+
name: 'accounts-config',
|
|
255
|
+
labels: { 'ui.platform-mesh.io/entity': 'entity' },
|
|
256
|
+
},
|
|
257
|
+
spec: { remoteConfiguration: { url: 'http://remote' } },
|
|
258
|
+
status: {
|
|
259
|
+
configurationResult: JSON.stringify({
|
|
260
|
+
name: 'accounts',
|
|
261
|
+
luigiConfigFragment: {
|
|
262
|
+
data: {
|
|
263
|
+
nodes: [
|
|
264
|
+
{
|
|
265
|
+
entityType: 'core_platform-mesh_io_account',
|
|
266
|
+
children: [
|
|
267
|
+
{
|
|
268
|
+
defineEntity: { id: 'old-id' },
|
|
269
|
+
context: {},
|
|
270
|
+
pathSegment: 'old-path',
|
|
271
|
+
},
|
|
272
|
+
],
|
|
273
|
+
},
|
|
274
|
+
],
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
}),
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
],
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
const result = await service.getServiceProviders(
|
|
286
|
+
'token',
|
|
287
|
+
['entity'],
|
|
288
|
+
context,
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
const childNode =
|
|
292
|
+
result.rawServiceProviders[0].contentConfiguration[0].luigiConfigFragment
|
|
293
|
+
.data.nodes[0].children[0];
|
|
294
|
+
|
|
295
|
+
expect(childNode.defineEntity.id).toBe('core_platform-mesh_io_account:2');
|
|
296
|
+
expect(childNode.pathSegment).toBe(':core_platform-mesh_io_accountId:2');
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it('does not apply processContentConfigurationForAccountHierarchy when accountPath is not provided', async () => {
|
|
300
|
+
mockClient.request.mockResolvedValue({
|
|
301
|
+
ui_platform_mesh_io: {
|
|
302
|
+
ContentConfigurations: {
|
|
303
|
+
items: [
|
|
304
|
+
{
|
|
305
|
+
metadata: {
|
|
306
|
+
name: 'conf1',
|
|
307
|
+
labels: { 'ui.platform-mesh.io/entity': 'entity' },
|
|
308
|
+
},
|
|
309
|
+
spec: { remoteConfiguration: { url: 'http://remote' } },
|
|
310
|
+
status: {
|
|
311
|
+
configurationResult: JSON.stringify({
|
|
312
|
+
name: 'test-config',
|
|
313
|
+
luigiConfigFragment: {
|
|
314
|
+
data: {
|
|
315
|
+
nodes: [{ entityType: 'core_platform-mesh_io_account' }],
|
|
316
|
+
},
|
|
317
|
+
},
|
|
318
|
+
}),
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
],
|
|
322
|
+
},
|
|
323
|
+
},
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
const result = await service.getServiceProviders(
|
|
327
|
+
'token',
|
|
328
|
+
['entity'],
|
|
329
|
+
context,
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
expect(
|
|
333
|
+
result.rawServiceProviders[0].contentConfiguration[0].luigiConfigFragment
|
|
334
|
+
.data.nodes[0].entityType,
|
|
335
|
+
).toBe('core_platform-mesh_io_account');
|
|
336
|
+
});
|
|
157
337
|
});
|
package/src/portal-options/service-providers/content-configuration-service-providers.service.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { RequestContext } from '../pm-request-context-provider.js';
|
|
2
|
+
import { processContentConfigurationForAccountHierarchy } from '../utils/account-hierarchy-resolver.js';
|
|
2
3
|
import { contentConfigurationsQuery } from './contentconfigurations-query.js';
|
|
3
4
|
import { ContentConfigurationQueryResponse } from './models/contentconfigurations.js';
|
|
4
5
|
import { welcomeNodeConfig } from './models/welcome-node-config.js';
|
|
@@ -11,9 +12,7 @@ import {
|
|
|
11
12
|
import { GraphQLClient } from 'graphql-request';
|
|
12
13
|
|
|
13
14
|
@Injectable()
|
|
14
|
-
export class ContentConfigurationServiceProvidersService
|
|
15
|
-
implements ServiceProviderService
|
|
16
|
-
{
|
|
15
|
+
export class ContentConfigurationServiceProvidersService implements ServiceProviderService {
|
|
17
16
|
async getServiceProviders(
|
|
18
17
|
token: string,
|
|
19
18
|
entities: string[],
|
|
@@ -37,9 +36,10 @@ export class ContentConfigurationServiceProvidersService
|
|
|
37
36
|
'kubernetes-graphql-gateway/virtual-workspace/contentconfigurations/root',
|
|
38
37
|
);
|
|
39
38
|
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
const accountPath =
|
|
40
|
+
context?.accountPath ?? context?.['core_platform-mesh_io_account'];
|
|
41
|
+
if (accountPath) {
|
|
42
|
+
url = url.replace('/graphql', `:${accountPath}/graphql`);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
console.log(`Calculated crd gateway api url: ${url}`);
|
|
@@ -64,45 +64,55 @@ export class ContentConfigurationServiceProvidersService
|
|
|
64
64
|
|
|
65
65
|
const entity = !entities || !entities.length ? 'main' : entities[0];
|
|
66
66
|
const contentConfigurations =
|
|
67
|
-
response.ui_platform_mesh_io.ContentConfigurations.
|
|
68
|
-
(
|
|
69
|
-
item
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
67
|
+
response.ui_platform_mesh_io.ContentConfigurations.items
|
|
68
|
+
.filter(
|
|
69
|
+
(item) =>
|
|
70
|
+
item.metadata.labels?.['ui.platform-mesh.io/entity'] === entity,
|
|
71
|
+
)
|
|
72
|
+
.map((item) => {
|
|
73
|
+
try {
|
|
74
|
+
// Validate required fields
|
|
75
|
+
if (!item.status?.configurationResult) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
`Missing configurationResult for item: ${item.metadata?.name || 'unknown'}`,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
78
80
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
81
|
+
const contentConfiguration = JSON.parse(
|
|
82
|
+
item.status.configurationResult,
|
|
83
|
+
) as ContentConfiguration;
|
|
82
84
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
85
|
+
if (!contentConfiguration.url) {
|
|
86
|
+
contentConfiguration.url = item.spec.remoteConfiguration?.url;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (context.accountPath) {
|
|
90
|
+
processContentConfigurationForAccountHierarchy(
|
|
91
|
+
contentConfiguration,
|
|
92
|
+
context.accountPath,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
93
95
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
96
|
+
return contentConfiguration;
|
|
97
|
+
} catch (parseError) {
|
|
98
|
+
// Log the error but don't fail the entire operation
|
|
99
|
+
console.error(
|
|
100
|
+
`Failed to parse configuration for item ${item.metadata?.name || 'unknown'}:`,
|
|
101
|
+
parseError,
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
// Re-throw specific errors as-is, others as JSON parse errors
|
|
105
|
+
if (
|
|
106
|
+
parseError instanceof Error &&
|
|
107
|
+
parseError.message.includes('Missing configurationResult')
|
|
108
|
+
) {
|
|
109
|
+
throw parseError;
|
|
110
|
+
}
|
|
111
|
+
throw new Error(
|
|
112
|
+
`Invalid JSON in configurationResult for item: ${item.metadata?.name || 'unknown'}`,
|
|
113
|
+
);
|
|
100
114
|
}
|
|
101
|
-
|
|
102
|
-
`Invalid JSON in configurationResult for item: ${item.metadata?.name || 'unknown'}`,
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
});
|
|
115
|
+
});
|
|
106
116
|
|
|
107
117
|
return {
|
|
108
118
|
rawServiceProviders: [
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { gql } from 'graphql-request';
|
|
2
2
|
|
|
3
3
|
export const contentConfigurationsQuery = gql`
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
query {
|
|
5
|
+
ui_platform_mesh_io {
|
|
6
|
+
ContentConfigurations {
|
|
7
|
+
items {
|
|
7
8
|
metadata {
|
|
8
9
|
name
|
|
9
10
|
labels
|
|
@@ -19,4 +20,5 @@ export const contentConfigurationsQuery = gql`
|
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
22
|
}
|
|
23
|
+
}
|
|
22
24
|
`;
|
|
@@ -194,4 +194,146 @@ describe('KubernetesServiceProvidersService', () => {
|
|
|
194
194
|
errSpy.mockRestore();
|
|
195
195
|
jest.useRealTimers();
|
|
196
196
|
});
|
|
197
|
+
|
|
198
|
+
it('should apply processContentConfigurationForAccountHierarchy when accountPath is provided', async () => {
|
|
199
|
+
listClusterCustomObject.mockResolvedValue({
|
|
200
|
+
items: [
|
|
201
|
+
{
|
|
202
|
+
status: {
|
|
203
|
+
configurationResult: JSON.stringify({
|
|
204
|
+
name: 'test-config',
|
|
205
|
+
luigiConfigFragment: {
|
|
206
|
+
data: {
|
|
207
|
+
nodes: [{ entityType: 'core_platform-mesh_io_account' }],
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
}),
|
|
211
|
+
},
|
|
212
|
+
spec: { remoteConfiguration: { url: 'http://example.com' } },
|
|
213
|
+
},
|
|
214
|
+
],
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
const svc = new KubernetesServiceProvidersService(kcpKubernetesServiceMock);
|
|
218
|
+
const res = await svc.getServiceProviders('token', ['main'], {
|
|
219
|
+
organization: 'org',
|
|
220
|
+
isSubDomain: true,
|
|
221
|
+
accountPath: 'acc1',
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
expect(
|
|
225
|
+
res.rawServiceProviders[0].contentConfiguration[0].luigiConfigFragment
|
|
226
|
+
.data.nodes[0].entityType,
|
|
227
|
+
).toBe('core_platform-mesh_io_account:1');
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('should apply processContentConfigurationForAccountHierarchy with multi-level accountPath', async () => {
|
|
231
|
+
listClusterCustomObject.mockResolvedValue({
|
|
232
|
+
items: [
|
|
233
|
+
{
|
|
234
|
+
status: {
|
|
235
|
+
configurationResult: JSON.stringify({
|
|
236
|
+
name: 'test-config',
|
|
237
|
+
luigiConfigFragment: {
|
|
238
|
+
data: {
|
|
239
|
+
nodes: [{ entityType: 'core_platform-mesh_io_account' }],
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
}),
|
|
243
|
+
},
|
|
244
|
+
spec: { remoteConfiguration: { url: 'http://example.com' } },
|
|
245
|
+
},
|
|
246
|
+
],
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
const svc = new KubernetesServiceProvidersService(kcpKubernetesServiceMock);
|
|
250
|
+
const res = await svc.getServiceProviders('token', ['main'], {
|
|
251
|
+
organization: 'org',
|
|
252
|
+
isSubDomain: true,
|
|
253
|
+
accountPath: 'acc1:acc2:acc3',
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
expect(
|
|
257
|
+
res.rawServiceProviders[0].contentConfiguration[0].luigiConfigFragment
|
|
258
|
+
.data.nodes[0].entityType,
|
|
259
|
+
).toBe(
|
|
260
|
+
'core_platform-mesh_io_account:1.core_platform-mesh_io_account:2.core_platform-mesh_io_account:3',
|
|
261
|
+
);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it('should update account children nodes for accounts configuration with accountPath', async () => {
|
|
265
|
+
listClusterCustomObject.mockResolvedValue({
|
|
266
|
+
items: [
|
|
267
|
+
{
|
|
268
|
+
status: {
|
|
269
|
+
configurationResult: JSON.stringify({
|
|
270
|
+
name: 'accounts',
|
|
271
|
+
luigiConfigFragment: {
|
|
272
|
+
data: {
|
|
273
|
+
nodes: [
|
|
274
|
+
{
|
|
275
|
+
entityType: 'core_platform-mesh_io_account',
|
|
276
|
+
children: [
|
|
277
|
+
{
|
|
278
|
+
defineEntity: { id: 'old-id' },
|
|
279
|
+
context: {},
|
|
280
|
+
pathSegment: 'old-path',
|
|
281
|
+
},
|
|
282
|
+
],
|
|
283
|
+
},
|
|
284
|
+
],
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
}),
|
|
288
|
+
},
|
|
289
|
+
spec: { remoteConfiguration: { url: 'http://example.com' } },
|
|
290
|
+
},
|
|
291
|
+
],
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
const svc = new KubernetesServiceProvidersService(kcpKubernetesServiceMock);
|
|
295
|
+
const res = await svc.getServiceProviders('token', ['main'], {
|
|
296
|
+
organization: 'org',
|
|
297
|
+
isSubDomain: true,
|
|
298
|
+
accountPath: 'acc1',
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
const childNode =
|
|
302
|
+
res.rawServiceProviders[0].contentConfiguration[0].luigiConfigFragment
|
|
303
|
+
.data.nodes[0].children[0];
|
|
304
|
+
|
|
305
|
+
expect(childNode.defineEntity.id).toBe('core_platform-mesh_io_account:2');
|
|
306
|
+
expect(childNode.pathSegment).toBe(':core_platform-mesh_io_accountId:2');
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it('should not apply processContentConfigurationForAccountHierarchy when accountPath is not provided', async () => {
|
|
310
|
+
listClusterCustomObject.mockResolvedValue({
|
|
311
|
+
items: [
|
|
312
|
+
{
|
|
313
|
+
status: {
|
|
314
|
+
configurationResult: JSON.stringify({
|
|
315
|
+
name: 'test-config',
|
|
316
|
+
luigiConfigFragment: {
|
|
317
|
+
data: {
|
|
318
|
+
nodes: [{ entityType: 'core_platform-mesh_io_account' }],
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
}),
|
|
322
|
+
},
|
|
323
|
+
spec: { remoteConfiguration: { url: 'http://example.com' } },
|
|
324
|
+
},
|
|
325
|
+
],
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
const svc = new KubernetesServiceProvidersService(kcpKubernetesServiceMock);
|
|
329
|
+
const res = await svc.getServiceProviders('token', ['main'], {
|
|
330
|
+
organization: 'org',
|
|
331
|
+
isSubDomain: true,
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
expect(
|
|
335
|
+
res.rawServiceProviders[0].contentConfiguration[0].luigiConfigFragment
|
|
336
|
+
.data.nodes[0].entityType,
|
|
337
|
+
).toBe('core_platform-mesh_io_account');
|
|
338
|
+
});
|
|
197
339
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { KcpKubernetesService } from '../services/kcp-k8s.service.js';
|
|
2
|
+
import { processContentConfigurationForAccountHierarchy } from '../utils/account-hierarchy-resolver.js';
|
|
2
3
|
import { welcomeNodeConfig } from './models/welcome-node-config.js';
|
|
3
4
|
import { PromiseMiddlewareWrapper } from '@kubernetes/client-node/dist/gen/middleware.js';
|
|
4
5
|
import { Injectable } from '@nestjs/common';
|
|
@@ -9,9 +10,7 @@ import {
|
|
|
9
10
|
} from '@openmfp/portal-server-lib';
|
|
10
11
|
|
|
11
12
|
@Injectable()
|
|
12
|
-
export class KubernetesServiceProvidersService
|
|
13
|
-
implements ServiceProviderService
|
|
14
|
-
{
|
|
13
|
+
export class KubernetesServiceProvidersService implements ServiceProviderService {
|
|
15
14
|
constructor(private kcpKubernetesService: KcpKubernetesService) {}
|
|
16
15
|
|
|
17
16
|
async getServiceProviders(
|
|
@@ -64,6 +63,14 @@ export class KubernetesServiceProvidersService
|
|
|
64
63
|
if (!contentConfiguration.url) {
|
|
65
64
|
contentConfiguration.url = item.spec.remoteConfiguration?.url;
|
|
66
65
|
}
|
|
66
|
+
|
|
67
|
+
if (context.accountPath) {
|
|
68
|
+
processContentConfigurationForAccountHierarchy(
|
|
69
|
+
contentConfiguration,
|
|
70
|
+
context.accountPath,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
67
74
|
return contentConfiguration;
|
|
68
75
|
});
|
|
69
76
|
|
|
@@ -96,12 +103,15 @@ export class KubernetesServiceProvidersService
|
|
|
96
103
|
middleware: [
|
|
97
104
|
new PromiseMiddlewareWrapper({
|
|
98
105
|
pre: async (context) => {
|
|
106
|
+
const accountPath =
|
|
107
|
+
requestContext?.accountPath ??
|
|
108
|
+
requestContext?.['core_platform-mesh_io_account'];
|
|
109
|
+
|
|
99
110
|
const kcpUrl = this.kcpKubernetesService.getKcpVirtualWorkspaceUrl(
|
|
100
111
|
requestContext.organization,
|
|
101
|
-
|
|
112
|
+
accountPath,
|
|
102
113
|
);
|
|
103
114
|
const path = `${kcpUrl}/apis/${gvr.group}/${gvr.version}/${gvr.plural}`;
|
|
104
|
-
console.log('kcp url: ', path);
|
|
105
115
|
|
|
106
116
|
context.setUrl(path);
|
|
107
117
|
context.setHeaderParam('Authorization', `Bearer ${token}`);
|
|
@@ -3,7 +3,7 @@ export interface ContentConfigurationQueryResponse {
|
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
export interface ContentConfigurationsResponse {
|
|
6
|
-
|
|
6
|
+
ContentConfigurations: { items: ContentConfigurationResponse[] };
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export interface ContentConfigurationResponse {
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
import {
|
|
2
|
+
processContentConfigurationForAccountHierarchy,
|
|
3
|
+
updateAccountNodeChildren,
|
|
4
|
+
updateEntityTypeFromAccountPath,
|
|
5
|
+
} from './account-hierarchy-resolver.js';
|
|
6
|
+
import { ContentConfiguration } from '@openmfp/portal-server-lib';
|
|
7
|
+
|
|
8
|
+
const createMockContentConfiguration = (
|
|
9
|
+
overrides: Partial<ContentConfiguration> = {},
|
|
10
|
+
): ContentConfiguration => ({
|
|
11
|
+
name: 'test-config',
|
|
12
|
+
creationTimestamp: '2024-01-01T00:00:00Z',
|
|
13
|
+
luigiConfigFragment: {
|
|
14
|
+
data: {
|
|
15
|
+
nodes: [],
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
...overrides,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('updateEntityTypeFromAccountPath', () => {
|
|
22
|
+
it('should update single entity type for single-level account path', () => {
|
|
23
|
+
const config = createMockContentConfiguration({
|
|
24
|
+
luigiConfigFragment: {
|
|
25
|
+
data: {
|
|
26
|
+
nodes: [{ entityType: 'core_platform-mesh_io_account' }],
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const result = updateEntityTypeFromAccountPath(config, 'acc1');
|
|
32
|
+
|
|
33
|
+
expect(result.luigiConfigFragment.data.nodes[0].entityType).toBe(
|
|
34
|
+
'core_platform-mesh_io_account:1',
|
|
35
|
+
);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should update entity type for multi-level account path', () => {
|
|
39
|
+
const config = createMockContentConfiguration({
|
|
40
|
+
luigiConfigFragment: {
|
|
41
|
+
data: {
|
|
42
|
+
nodes: [{ entityType: 'core_platform-mesh_io_account' }],
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const result = updateEntityTypeFromAccountPath(config, 'acc1:acc2:acc3');
|
|
48
|
+
|
|
49
|
+
expect(result.luigiConfigFragment.data.nodes[0].entityType).toBe(
|
|
50
|
+
'core_platform-mesh_io_account:1.core_platform-mesh_io_account:2.core_platform-mesh_io_account:3',
|
|
51
|
+
);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should update entity types for multiple nodes', () => {
|
|
55
|
+
const config = createMockContentConfiguration({
|
|
56
|
+
luigiConfigFragment: {
|
|
57
|
+
data: {
|
|
58
|
+
nodes: [
|
|
59
|
+
{ entityType: 'core_platform-mesh_io_account' },
|
|
60
|
+
{ entityType: 'core_platform-mesh_io_account' },
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const result = updateEntityTypeFromAccountPath(config, 'acc1:acc2');
|
|
67
|
+
|
|
68
|
+
expect(result.luigiConfigFragment.data.nodes[0].entityType).toBe(
|
|
69
|
+
'core_platform-mesh_io_account:1.core_platform-mesh_io_account:2',
|
|
70
|
+
);
|
|
71
|
+
expect(result.luigiConfigFragment.data.nodes[1].entityType).toBe(
|
|
72
|
+
'core_platform-mesh_io_account:1.core_platform-mesh_io_account:2',
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should not modify entity types that do not match account entity type', () => {
|
|
77
|
+
const config = createMockContentConfiguration({
|
|
78
|
+
luigiConfigFragment: {
|
|
79
|
+
data: {
|
|
80
|
+
nodes: [{ entityType: 'other_entity_type' }],
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const result = updateEntityTypeFromAccountPath(config, 'acc1');
|
|
86
|
+
|
|
87
|
+
expect(result.luigiConfigFragment.data.nodes[0].entityType).toBe(
|
|
88
|
+
'other_entity_type',
|
|
89
|
+
);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should return the same configuration object', () => {
|
|
93
|
+
const config = createMockContentConfiguration({
|
|
94
|
+
luigiConfigFragment: {
|
|
95
|
+
data: {
|
|
96
|
+
nodes: [{ entityType: 'core_platform-mesh_io_account' }],
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const result = updateEntityTypeFromAccountPath(config, 'acc1');
|
|
102
|
+
|
|
103
|
+
expect(result).toBe(config);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
describe('updateAccountNodeChildren', () => {
|
|
108
|
+
it('should update children node for single-level account path', () => {
|
|
109
|
+
const config = createMockContentConfiguration({
|
|
110
|
+
luigiConfigFragment: {
|
|
111
|
+
data: {
|
|
112
|
+
nodes: [
|
|
113
|
+
{
|
|
114
|
+
children: [
|
|
115
|
+
{
|
|
116
|
+
defineEntity: { id: 'old-id' },
|
|
117
|
+
context: {},
|
|
118
|
+
pathSegment: 'old-path',
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
},
|
|
122
|
+
],
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const result = updateAccountNodeChildren(config, 'acc1');
|
|
128
|
+
const childNode = result.luigiConfigFragment.data.nodes[0]
|
|
129
|
+
.children?.[0] as any;
|
|
130
|
+
|
|
131
|
+
expect(childNode.defineEntity.id).toBe('core_platform-mesh_io_account:2');
|
|
132
|
+
expect(childNode.context.accountId).toBe(
|
|
133
|
+
':core_platform-mesh_io_accountId:2',
|
|
134
|
+
);
|
|
135
|
+
expect(childNode.context['core_platform-mesh_io_accountId']).toBe(
|
|
136
|
+
':core_platform-mesh_io_accountId:2',
|
|
137
|
+
);
|
|
138
|
+
expect(childNode.context.resourceId).toBe(
|
|
139
|
+
':core_platform-mesh_io_accountId:2',
|
|
140
|
+
);
|
|
141
|
+
expect(childNode.pathSegment).toBe(':core_platform-mesh_io_accountId:2');
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('should update children node for multi-level account path', () => {
|
|
145
|
+
const config = createMockContentConfiguration({
|
|
146
|
+
luigiConfigFragment: {
|
|
147
|
+
data: {
|
|
148
|
+
nodes: [
|
|
149
|
+
{
|
|
150
|
+
children: [
|
|
151
|
+
{
|
|
152
|
+
defineEntity: { id: 'old-id' },
|
|
153
|
+
context: {},
|
|
154
|
+
pathSegment: 'old-path',
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
},
|
|
158
|
+
],
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const result = updateAccountNodeChildren(config, 'acc1:acc2:acc3');
|
|
164
|
+
const childNode = result.luigiConfigFragment.data.nodes[0]
|
|
165
|
+
.children?.[0] as any;
|
|
166
|
+
|
|
167
|
+
expect(childNode.defineEntity.id).toBe('core_platform-mesh_io_account:4');
|
|
168
|
+
expect(childNode.context.accountId).toBe(
|
|
169
|
+
':core_platform-mesh_io_accountId:4',
|
|
170
|
+
);
|
|
171
|
+
expect(childNode.pathSegment).toBe(':core_platform-mesh_io_accountId:4');
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('should not fail when there are no nodes', () => {
|
|
175
|
+
const config = createMockContentConfiguration({
|
|
176
|
+
luigiConfigFragment: {
|
|
177
|
+
data: {
|
|
178
|
+
nodes: [],
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const result = updateAccountNodeChildren(config, 'acc1');
|
|
184
|
+
|
|
185
|
+
expect(result).toBe(config);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('should not fail when first node has no children', () => {
|
|
189
|
+
const config = createMockContentConfiguration({
|
|
190
|
+
luigiConfigFragment: {
|
|
191
|
+
data: {
|
|
192
|
+
nodes: [{ entityType: 'test' }],
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
const result = updateAccountNodeChildren(config, 'acc1');
|
|
198
|
+
|
|
199
|
+
expect(result).toBe(config);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it('should not fail when children array is empty', () => {
|
|
203
|
+
const config = createMockContentConfiguration({
|
|
204
|
+
luigiConfigFragment: {
|
|
205
|
+
data: {
|
|
206
|
+
nodes: [{ children: [] }],
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
const result = updateAccountNodeChildren(config, 'acc1');
|
|
212
|
+
|
|
213
|
+
expect(result).toBe(config);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('should return the same configuration object', () => {
|
|
217
|
+
const config = createMockContentConfiguration({
|
|
218
|
+
luigiConfigFragment: {
|
|
219
|
+
data: {
|
|
220
|
+
nodes: [
|
|
221
|
+
{
|
|
222
|
+
children: [
|
|
223
|
+
{
|
|
224
|
+
defineEntity: { id: 'old-id' },
|
|
225
|
+
context: {},
|
|
226
|
+
pathSegment: 'old-path',
|
|
227
|
+
},
|
|
228
|
+
],
|
|
229
|
+
},
|
|
230
|
+
],
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
const result = updateAccountNodeChildren(config, 'acc1');
|
|
236
|
+
|
|
237
|
+
expect(result).toBe(config);
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
describe('processContentConfigurationForAccountHierarchy', () => {
|
|
242
|
+
it('should call updateAccountNodeChildren for accounts configuration', () => {
|
|
243
|
+
const config = createMockContentConfiguration({
|
|
244
|
+
name: 'accounts',
|
|
245
|
+
luigiConfigFragment: {
|
|
246
|
+
data: {
|
|
247
|
+
nodes: [
|
|
248
|
+
{
|
|
249
|
+
entityType: 'core_platform-mesh_io_account',
|
|
250
|
+
children: [
|
|
251
|
+
{
|
|
252
|
+
defineEntity: { id: 'old-id' },
|
|
253
|
+
context: {},
|
|
254
|
+
pathSegment: 'old-path',
|
|
255
|
+
},
|
|
256
|
+
],
|
|
257
|
+
},
|
|
258
|
+
],
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
const result = processContentConfigurationForAccountHierarchy(
|
|
264
|
+
config,
|
|
265
|
+
'acc1',
|
|
266
|
+
);
|
|
267
|
+
const childNode = result.luigiConfigFragment.data.nodes[0]
|
|
268
|
+
.children?.[0] as any;
|
|
269
|
+
|
|
270
|
+
expect(childNode.defineEntity.id).toBe('core_platform-mesh_io_account:2');
|
|
271
|
+
expect(result.luigiConfigFragment.data.nodes[0].entityType).toBe(
|
|
272
|
+
'core_platform-mesh_io_account:1',
|
|
273
|
+
);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it('should not call updateAccountNodeChildren for non-accounts configuration', () => {
|
|
277
|
+
const config = createMockContentConfiguration({
|
|
278
|
+
name: 'other-config',
|
|
279
|
+
luigiConfigFragment: {
|
|
280
|
+
data: {
|
|
281
|
+
nodes: [
|
|
282
|
+
{
|
|
283
|
+
entityType: 'core_platform-mesh_io_account',
|
|
284
|
+
children: [
|
|
285
|
+
{
|
|
286
|
+
defineEntity: { id: 'old-id' },
|
|
287
|
+
context: {},
|
|
288
|
+
pathSegment: 'old-path',
|
|
289
|
+
},
|
|
290
|
+
],
|
|
291
|
+
},
|
|
292
|
+
],
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
const result = processContentConfigurationForAccountHierarchy(
|
|
298
|
+
config,
|
|
299
|
+
'acc1',
|
|
300
|
+
);
|
|
301
|
+
const childNode = result.luigiConfigFragment.data.nodes[0]
|
|
302
|
+
.children?.[0] as any;
|
|
303
|
+
|
|
304
|
+
expect(childNode.defineEntity.id).toBe('old-id');
|
|
305
|
+
expect(result.luigiConfigFragment.data.nodes[0].entityType).toBe(
|
|
306
|
+
'core_platform-mesh_io_account:1',
|
|
307
|
+
);
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it('should always call updateEntityTypeFromAccountPath', () => {
|
|
311
|
+
const config = createMockContentConfiguration({
|
|
312
|
+
name: 'any-config',
|
|
313
|
+
luigiConfigFragment: {
|
|
314
|
+
data: {
|
|
315
|
+
nodes: [{ entityType: 'core_platform-mesh_io_account' }],
|
|
316
|
+
},
|
|
317
|
+
},
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
const result = processContentConfigurationForAccountHierarchy(
|
|
321
|
+
config,
|
|
322
|
+
'acc1:acc2',
|
|
323
|
+
);
|
|
324
|
+
|
|
325
|
+
expect(result.luigiConfigFragment.data.nodes[0].entityType).toBe(
|
|
326
|
+
'core_platform-mesh_io_account:1.core_platform-mesh_io_account:2',
|
|
327
|
+
);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
it('should return the same configuration object', () => {
|
|
331
|
+
const config = createMockContentConfiguration({
|
|
332
|
+
name: 'test-config',
|
|
333
|
+
luigiConfigFragment: {
|
|
334
|
+
data: {
|
|
335
|
+
nodes: [{ entityType: 'core_platform-mesh_io_account' }],
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
const result = processContentConfigurationForAccountHierarchy(
|
|
341
|
+
config,
|
|
342
|
+
'acc1',
|
|
343
|
+
);
|
|
344
|
+
|
|
345
|
+
expect(result).toBe(config);
|
|
346
|
+
});
|
|
347
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ContentConfiguration } from '@openmfp/portal-server-lib';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
const ACCOUNT_ENTITY_TYPE = 'core_platform-mesh_io_account';
|
|
7
|
+
|
|
8
|
+
export const updateEntityTypeFromAccountPath = (
|
|
9
|
+
contentConfiguration: ContentConfiguration,
|
|
10
|
+
accountPath: string,
|
|
11
|
+
): ContentConfiguration => {
|
|
12
|
+
contentConfiguration.luigiConfigFragment.data.nodes.forEach((node) => {
|
|
13
|
+
const accountPathParts = accountPath
|
|
14
|
+
.split(':')
|
|
15
|
+
.map((_, i) => `${ACCOUNT_ENTITY_TYPE}:${i + 1}`)
|
|
16
|
+
.join('.');
|
|
17
|
+
|
|
18
|
+
node.entityType = node.entityType.replace(
|
|
19
|
+
ACCOUNT_ENTITY_TYPE,
|
|
20
|
+
accountPathParts,
|
|
21
|
+
);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
return contentConfiguration;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const updateAccountNodeChildren = (
|
|
28
|
+
contentConfiguration: ContentConfiguration,
|
|
29
|
+
accountPath: string,
|
|
30
|
+
): ContentConfiguration => {
|
|
31
|
+
const accountChildrenNode =
|
|
32
|
+
contentConfiguration.luigiConfigFragment.data.nodes[0]?.children?.[0];
|
|
33
|
+
const nextHierarchyLevel = accountPath.split(':').length + 1;
|
|
34
|
+
|
|
35
|
+
if (accountChildrenNode) {
|
|
36
|
+
accountChildrenNode.defineEntity.id = `${ACCOUNT_ENTITY_TYPE}:${nextHierarchyLevel}`;
|
|
37
|
+
accountChildrenNode.context.accountId = `:${ACCOUNT_ENTITY_TYPE}Id:${nextHierarchyLevel}`;
|
|
38
|
+
accountChildrenNode.context[`${ACCOUNT_ENTITY_TYPE}Id`] =
|
|
39
|
+
`:${ACCOUNT_ENTITY_TYPE}Id:${nextHierarchyLevel}`;
|
|
40
|
+
accountChildrenNode.context.resourceId = `:${ACCOUNT_ENTITY_TYPE}Id:${nextHierarchyLevel}`;
|
|
41
|
+
accountChildrenNode.pathSegment = `:${ACCOUNT_ENTITY_TYPE}Id:${nextHierarchyLevel}`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return contentConfiguration;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const processContentConfigurationForAccountHierarchy = (
|
|
48
|
+
contentConfiguration: ContentConfiguration,
|
|
49
|
+
accountPath: string,
|
|
50
|
+
): ContentConfiguration => {
|
|
51
|
+
if (contentConfiguration.name === 'accounts') {
|
|
52
|
+
updateAccountNodeChildren(contentConfiguration, accountPath);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return updateEntityTypeFromAccountPath(contentConfiguration, accountPath);
|
|
56
|
+
};
|