@platform-mesh/portal-server-lib 0.5.41 → 0.5.42

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.
Files changed (21) hide show
  1. package/dist/portal-options/service-providers/content-configuration-service-providers.service.js +10 -4
  2. package/dist/portal-options/service-providers/content-configuration-service-providers.service.js.map +1 -1
  3. package/dist/portal-options/service-providers/contentconfigurations-query.js +5 -3
  4. package/dist/portal-options/service-providers/contentconfigurations-query.js.map +1 -1
  5. package/dist/portal-options/service-providers/kubernetes-service-providers.service.js +7 -2
  6. package/dist/portal-options/service-providers/kubernetes-service-providers.service.js.map +1 -1
  7. package/dist/portal-options/service-providers/models/contentconfigurations.d.ts +3 -1
  8. package/dist/portal-options/services/kcp-k8s.service.js.map +1 -1
  9. package/dist/portal-options/utils/account-hierarchy-resolver.d.ts +4 -0
  10. package/dist/portal-options/utils/account-hierarchy-resolver.js +31 -0
  11. package/dist/portal-options/utils/account-hierarchy-resolver.js.map +1 -0
  12. package/package.json +1 -1
  13. package/src/portal-options/service-providers/content-configuration-service-providers.service.spec.ts +209 -29
  14. package/src/portal-options/service-providers/content-configuration-service-providers.service.ts +51 -41
  15. package/src/portal-options/service-providers/contentconfigurations-query.ts +5 -3
  16. package/src/portal-options/service-providers/kubernetes-service-providers.service.spec.ts +142 -0
  17. package/src/portal-options/service-providers/kubernetes-service-providers.service.ts +15 -5
  18. package/src/portal-options/service-providers/models/contentconfigurations.ts +1 -1
  19. package/src/portal-options/services/kcp-k8s.service.ts +1 -0
  20. package/src/portal-options/utils/account-hierarchy-resolver.spec.ts +347 -0
  21. package/src/portal-options/utils/account-hierarchy-resolver.ts +56 -0
@@ -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 platformMeshAccountId = context?.['core_platform-mesh_io_account'];
24
- if (platformMeshAccountId) {
25
- url = url.replace('/graphql', `:${platformMeshAccountId}/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.filter((item) => item.metadata.labels?.['ui.platform-mesh.io/entity'] === entity).map((item) => {
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) {
@@ -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":"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"}
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,8CAA8C,EAAE,MAAM,wCAAwC,CAAC;AACxG,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;IACtD,KAAK,CAAC,mBAAmB,CACvB,KAAa,EACb,QAAkB,EAClB,OAAuB;QAGvB,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACvC,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;YACzB,OAAO,iBAAiB,CAAC;QAC3B,CAAC;QAED,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAC3D,CAAC;QAED,IAAI,GAAG,GAAG,OAAO,CAAC,gBAAgB,CAAC,OAAO,CACxC,iCAAiC,EACjC,yEAAyE,CAC1E,CAAC;QAEF,MAAM,WAAW,GACf,OAAO,EAAE,WAAW,IAAI,OAAO,EAAE,CAAC,+BAA+B,CAAC,CAAC;QACrE,IAAI,WAAW,EAAE,CAAC;YAChB,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,WAAW,UAAU,CAAC,CAAC;QAC3D,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,mCAAmC,GAAG,EAAE,CAAC,CAAC;QACtD,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,GAAG,EAAE;YACpC,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,KAAK,EAAE;aACjC;SACF,CAAC,CAAC;QAEH,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,OAAO,CACnC,0BAA0B,EAC1B,EAAE,CACH,CAAC;YAGF,IAAI,CAAC,QAAQ,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,CAAC;gBAC1D,MAAM,IAAI,KAAK,CACb,2DAA2D,CAC5D,CAAC;YACJ,CAAC;YAED,MAAM,MAAM,GAAG,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YACpE,MAAM,qBAAqB,GACzB,QAAQ,CAAC,mBAAmB,CAAC,qBAAqB,CAAC,KAAK;iBACrD,MAAM,CACL,CAAC,IAAI,EAAE,EAAE,CACP,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,4BAA4B,CAAC,KAAK,MAAM,CAClE;iBACA,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;gBACZ,IAAI,CAAC;oBAEH,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,mBAAmB,EAAE,CAAC;wBACtC,MAAM,IAAI,KAAK,CACb,yCAAyC,IAAI,CAAC,QAAQ,EAAE,IAAI,IAAI,SAAS,EAAE,CAC5E,CAAC;oBACJ,CAAC;oBAED,MAAM,oBAAoB,GAAG,IAAI,CAAC,KAAK,CACrC,IAAI,CAAC,MAAM,CAAC,mBAAmB,CACR,CAAC;oBAE1B,IAAI,CAAC,oBAAoB,CAAC,GAAG,EAAE,CAAC;wBAC9B,oBAAoB,CAAC,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,GAAG,CAAC;oBAChE,CAAC;oBAED,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;wBACxB,8CAA8C,CAC5C,oBAAoB,EACpB,OAAO,CAAC,WAAW,CACpB,CAAC;oBACJ,CAAC;oBAED,OAAO,oBAAoB,CAAC;gBAC9B,CAAC;gBAAC,OAAO,UAAU,EAAE,CAAC;oBAEpB,OAAO,CAAC,KAAK,CACX,0CAA0C,IAAI,CAAC,QAAQ,EAAE,IAAI,IAAI,SAAS,GAAG,EAC7E,UAAU,CACX,CAAC;oBAGF,IACE,UAAU,YAAY,KAAK;wBAC3B,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,6BAA6B,CAAC,EAC1D,CAAC;wBACD,MAAM,UAAU,CAAC;oBACnB,CAAC;oBACD,MAAM,IAAI,KAAK,CACb,iDAAiD,IAAI,CAAC,QAAQ,EAAE,IAAI,IAAI,SAAS,EAAE,CACpF,CAAC;gBACJ,CAAC;YACH,CAAC,CAAC,CAAC;YAEP,OAAO;gBACL,mBAAmB,EAAE;oBACnB;wBACE,IAAI,EAAE,sBAAsB;wBAC5B,WAAW,EAAE,EAAE;wBACf,iBAAiB,EAAE,EAAE;wBACrB,oBAAoB,EAAE,qBAAqB;qBAC5C;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAEf,IACE,KAAK,YAAY,KAAK;gBACtB,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAC7C,CAAC;gBACD,MAAM,KAAK,CAAC;YACd,CAAC;YACD,MAAM,IAAI,KAAK,CACb,2CAA2C,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE,CACtG,CAAC;QACJ,CAAC;IACH,CAAC;CACF,CAAA;AA7HY,2CAA2C;IADvD,UAAU,EAAE;GACA,2CAA2C,CA6HvD"}
@@ -1,8 +1,9 @@
1
1
  import { gql } from 'graphql-request';
2
2
  export const contentConfigurationsQuery = gql `
3
- query {
4
- ui_platform_mesh_io {
5
- ContentConfigurations {
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;;;;;;;;;;;;;;;;;;;CAmB5C,CAAC"}
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 kcpUrl = this.kcpKubernetesService.getKcpVirtualWorkspaceUrl(requestContext.organization, requestContext?.['core_platform-mesh_io_account']);
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":"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"}
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: ContentConfigurationResponse[];
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;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,yBAAyB,CAAC,YAAoB,EAAE,OAAe;QAC7D,MAAM,IAAI,GAAG,IAAI,CAAC,kBAAkB,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QAC5D,OAAO,IAAI,GAAG,CACZ,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,4CAA4C,IAAI,EAAE,CACzE,CAAC;IACJ,CAAC;IAED,kBAAkB,CAAC,YAAoB,EAAE,OAAe;QACtD,MAAM,IAAI,GAAG,IAAI,CAAC,kBAAkB,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QAC5D,OAAO,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,aAAa,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,wBAAwB,CAAC,OAAgB;QACvC,MAAM,YAAY,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,+BAA+B,CAAC,CAAC;QACjE,MAAM,IAAI,GAAG,IAAI,CAAC,kBAAkB,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QAE5D,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;QACpD,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAEtC,OAAO,mBAAmB,UAAU,GAAG,IAAI,aAAa,IAAI,EAAE,CAAC;IACjE,CAAC;IAEO,UAAU,CAAC,OAAgB;QACjC,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;QAC1D,MAAM,kBAAkB,GAAG,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC;YACrD,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;YAClB,CAAC,CAAC,aAAa,CAAC;QAClB,MAAM,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5D,MAAM,eAAe,GACnB,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,kBAAkB,IAAI,eAAe,IAAI,EAAE,CAAC;QAE3E,MAAM,qBAAqB,GACzB,eAAe,KAAK,IAAI,IAAI,eAAe,KAAK,KAAK,IAAI,CAAC,eAAe,CAAC;QAC5E,OAAO,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,eAAe,EAAE,CAAC;IAC5D,CAAC;CACF,CAAA;AAtEY,oBAAoB;IADhC,UAAU,EAAE;;GACA,oBAAoB,CAsEhC"}
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.41",
3
+ "version": "0.5.42",
4
4
  "author": "Platform Mesh",
5
5
  "license": "Apache-2.0",
6
6
  "publishConfig": {
@@ -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
- metadata: {
76
- name: 'conf1',
77
- labels: { 'ui.platform-mesh.io/entity': 'entity' },
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
- spec: { remoteConfiguration: { url: 'http://remote' } },
80
- status: {
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
- metadata: {
103
- name: 'conf1',
104
- labels: { 'ui.platform-mesh.io/entity': 'entity' },
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
- spec: { remoteConfiguration: { url: 'http://remote' } },
107
- status: { configurationResult: JSON.stringify({}) },
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
- metadata: {
128
- name: 'conf1',
129
- labels: { 'ui.platform-mesh.io/entity': 'entity' },
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
- spec: { remoteConfiguration: { url: 'http://remote' } },
132
- status: {},
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
  });
@@ -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 platformMeshAccountId = context?.['core_platform-mesh_io_account'];
41
- if (platformMeshAccountId) {
42
- url = url.replace('/graphql', `:${platformMeshAccountId}/graphql`);
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.filter(
68
- (item) =>
69
- item.metadata.labels?.['ui.platform-mesh.io/entity'] === entity,
70
- ).map((item) => {
71
- try {
72
- // Validate required fields
73
- if (!item.status?.configurationResult) {
74
- throw new Error(
75
- `Missing configurationResult for item: ${item.metadata?.name || 'unknown'}`,
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
- const contentConfiguration = JSON.parse(
80
- item.status.configurationResult,
81
- ) as ContentConfiguration;
81
+ const contentConfiguration = JSON.parse(
82
+ item.status.configurationResult,
83
+ ) as ContentConfiguration;
82
84
 
83
- if (!contentConfiguration.url) {
84
- contentConfiguration.url = item.spec.remoteConfiguration?.url;
85
- }
86
- return contentConfiguration;
87
- } catch (parseError) {
88
- // Log the error but don't fail the entire operation
89
- console.error(
90
- `Failed to parse configuration for item ${item.metadata?.name || 'unknown'}:`,
91
- parseError,
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
- // Re-throw specific errors as-is, others as JSON parse errors
95
- if (
96
- parseError instanceof Error &&
97
- parseError.message.includes('Missing configurationResult')
98
- ) {
99
- throw parseError;
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
- throw new Error(
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
- query {
5
- ui_platform_mesh_io {
6
- ContentConfigurations {
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
- requestContext?.['core_platform-mesh_io_account'],
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
- ContentConfigurations: ContentConfigurationResponse[];
6
+ ContentConfigurations: { items: ContentConfigurationResponse[] };
7
7
  }
8
8
 
9
9
  export interface ContentConfigurationResponse {
@@ -35,6 +35,7 @@ export class KcpKubernetesService {
35
35
  if (account) {
36
36
  path += `:${account}`; // FIXME: how are nested accounts and paths handled in the portal?
37
37
  }
38
+
38
39
  return path;
39
40
  }
40
41
 
@@ -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
+ };