@openmfp/portal-ui-lib 0.183.0 → 0.183.1

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.
@@ -230,8 +230,9 @@ class ConfigService {
230
230
  this.entityConfigCache[entity] = {};
231
231
  }
232
232
  const entityCacheKey = JSON.stringify(context);
233
- if (this.entityConfigCache[entity][entityCacheKey]) {
234
- return this.entityConfigCache[entity][entityCacheKey];
233
+ const cachedConfig = this.entityConfigCache[entity][entityCacheKey];
234
+ if (cachedConfig) {
235
+ return cachedConfig;
235
236
  }
236
237
  const options = this.requestHeadersService.createOptionsWithAuthHeader();
237
238
  const entityConfig = firstValueFrom(this.http.get(`/rest/config/${entity}`, {
@@ -671,6 +672,9 @@ const localDevelopmentSettingsLocalStorage = {
671
672
  return null;
672
673
  }
673
674
  try {
675
+ if (!localDevelopmentSettingsFromLocalStore) {
676
+ return null;
677
+ }
674
678
  return JSON.parse(localDevelopmentSettingsFromLocalStore);
675
679
  }
676
680
  catch (e) {
@@ -797,7 +801,7 @@ class IframeService {
797
801
  allow += ';';
798
802
  }
799
803
  permissions.allow.forEach((policy) => {
800
- if (this.isIFrameFeaturePolicyAllowed(policy, iframe.getAttribute('src'))) {
804
+ if (this.isIFrameFeaturePolicyAllowed(policy, this.getIframeSrc(iframe))) {
801
805
  // feature policies are separated by semicolon
802
806
  allow += ` ${policy};`;
803
807
  }
@@ -807,7 +811,7 @@ class IframeService {
807
811
  if (permissions.sandbox) {
808
812
  let sandbox = (iframe.getAttribute('sandbox') || '').trim();
809
813
  permissions.sandbox.forEach((permission) => {
810
- if (this.isIFrameSandboxPermissionAllowed(permission, iframe.getAttribute('src'))) {
814
+ if (this.isIFrameSandboxPermissionAllowed(permission, this.getIframeSrc(iframe))) {
811
815
  // sandbox permission are separated by whitespace
812
816
  sandbox += ' ' + permission;
813
817
  }
@@ -815,6 +819,17 @@ class IframeService {
815
819
  iframe.setAttribute('sandbox', sandbox.trim());
816
820
  }
817
821
  }
822
+ getIframeSrc(iframe) {
823
+ const src = iframe.getAttribute('src');
824
+ if (!src) {
825
+ this.luigiCoreService.showAlert({
826
+ text: 'Iframe source not found',
827
+ type: 'error',
828
+ });
829
+ throw new Error('Iframe source not found');
830
+ }
831
+ return src;
832
+ }
818
833
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: IframeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
819
834
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: IframeService, providedIn: 'root' }); }
820
835
  }
@@ -1004,7 +1019,7 @@ class UserSettingsConfigService {
1004
1019
  this.applyNewTheme(settings, previous);
1005
1020
  this.changeToSelectedLanguage(settings, previous);
1006
1021
  this.saveLocalDevelopmentSettings(settings, previous);
1007
- if (envConfig.uiOptions.includes('enableFeatureToggleSetting')) {
1022
+ if (envConfig.uiOptions?.includes('enableFeatureToggleSetting')) {
1008
1023
  this.saveFeatureToggleSettings(settings);
1009
1024
  }
1010
1025
  },
@@ -1017,7 +1032,7 @@ class UserSettingsConfigService {
1017
1032
  await this.addUserSettings(settings);
1018
1033
  await this.addThemingSettings(settings);
1019
1034
  this.addLocalDevelopmentSettings(settings);
1020
- if (envConfig.uiOptions.includes('enableFeatureToggleSetting')) {
1035
+ if (envConfig.uiOptions?.includes('enableFeatureToggleSetting')) {
1021
1036
  this.addFeatureToggleSettings(settings);
1022
1037
  }
1023
1038
  this.addInfoSettings(settings);
@@ -1025,10 +1040,12 @@ class UserSettingsConfigService {
1025
1040
  }
1026
1041
  saveFeatureToggleSettings(settings) {
1027
1042
  const currentFeatureToggleSettings = settings?.frame_featureToggle?.featureToggleSettings;
1028
- featureToggleLocalStorage.store(currentFeatureToggleSettings);
1029
- this.luigiCoreService.unsetAllFeatureToggles();
1030
- this.luigiCoreService.setFeatureToggles(currentFeatureToggleSettings);
1031
- globalThis.location.reload();
1043
+ if (currentFeatureToggleSettings) {
1044
+ featureToggleLocalStorage.store(currentFeatureToggleSettings);
1045
+ this.luigiCoreService.unsetAllFeatureToggles();
1046
+ this.luigiCoreService.setFeatureToggles(currentFeatureToggleSettings);
1047
+ globalThis.location.reload();
1048
+ }
1032
1049
  }
1033
1050
  saveLocalDevelopmentSettings(settings, previous) {
1034
1051
  const currentLocalDevelopmentSettings = settings?.frame_development?.localDevelopmentSettings;
@@ -1081,10 +1098,10 @@ class UserSettingsConfigService {
1081
1098
  const user = this.authService.getUserInfo();
1082
1099
  const userSettings = await userSettingsLocalStorage.read(user);
1083
1100
  const selectedTheme = userSettings?.frame_appearance?.selectedTheme ||
1084
- this.luigiThemingService.getDefaultThemeId();
1085
- return this.luigiThemingService
1086
- .getAvailableThemes()
1087
- .find((t) => t.id === selectedTheme)?.name;
1101
+ this.luigiThemingService?.getDefaultThemeId();
1102
+ return (this.luigiThemingService
1103
+ ?.getAvailableThemes()
1104
+ ?.find((t) => t.id === selectedTheme)?.name || '');
1088
1105
  }
1089
1106
  async addThemingSettings(settings) {
1090
1107
  if (this.luigiThemingService) {
@@ -1265,8 +1282,8 @@ class AppSwitcherConfigServiceImpl {
1265
1282
  })
1266
1283
  .map((node) => {
1267
1284
  const nodeConfig = {
1268
- title: node.label,
1269
- icon: node.icon,
1285
+ title: node.label || '',
1286
+ icon: node.icon || '',
1270
1287
  link: '/' + node.pathSegment,
1271
1288
  };
1272
1289
  return nodeConfig;
@@ -1493,9 +1510,9 @@ class LocalConfigurationServiceImpl {
1493
1510
  this.luigiCoreService.showAlert({
1494
1511
  text: `
1495
1512
  Your local development configuration contains error(s).
1496
- You will not be able to see your local changes and local development results unless you correct the data and reload the page.
1513
+ You will not be able to see your local changes and local development results unless you correct the data and reload the page.
1497
1514
  Please see below the detailed information: <br/><br/>
1498
-
1515
+
1499
1516
  ${message}
1500
1517
  `,
1501
1518
  type: 'error',
@@ -1546,8 +1563,8 @@ class LocalConfigurationServiceImpl {
1546
1563
  const localEntityTypes = [...new Set(localNodes.map((n) => n.entityType))]
1547
1564
  .filter(Boolean)
1548
1565
  .join(',');
1549
- console.debug(`Found '${serverLuigiNodes.length}' server nodes.
1550
- Found '${localNodes.length}' local luigi nodes.
1566
+ console.debug(`Found '${serverLuigiNodes.length}' server nodes.
1567
+ Found '${localNodes.length}' local luigi nodes.
1551
1568
  The entities of the server node are: [${serverEntityTypes}]
1552
1569
  The entities of local nodes are: [${localEntityTypes}]`);
1553
1570
  }
@@ -1557,10 +1574,10 @@ class LocalConfigurationServiceImpl {
1557
1574
  }
1558
1575
  async getLocalConfigurations(localDevelopmentSettings) {
1559
1576
  const initialConfigurations = localDevelopmentSettings.configs
1560
- .filter((config) => config.data)
1577
+ .filter((config) => !!config.data)
1561
1578
  .map((config) => config.data);
1562
1579
  const configurations = (await Promise.allSettled(localDevelopmentSettings.configs
1563
- .filter((config) => config.url)
1580
+ .filter((config) => !!config.url)
1564
1581
  .map((config) => lastValueFrom(this.http.get(config.url)).then((contentConfiguration) => ({
1565
1582
  ...contentConfiguration,
1566
1583
  url: config.url,
@@ -1584,6 +1601,7 @@ class LuigiNodesService {
1584
1601
  constructor() {
1585
1602
  this.i18nService = inject(I18nService);
1586
1603
  this.configService = inject(ConfigService);
1604
+ this.luigiCoreService = inject(LuigiCoreService);
1587
1605
  this.localConfigurationService = inject(LocalConfigurationServiceImpl);
1588
1606
  this.errorComponentConfig = inject(ERROR_COMPONENT_CONFIG, {
1589
1607
  optional: true,
@@ -1620,18 +1638,19 @@ class LuigiNodesService {
1620
1638
  let configsForEntity;
1621
1639
  const entityType = entityDefinition.dynamicFetchId;
1622
1640
  try {
1641
+ if (!entityType) {
1642
+ throw new Error('Entity type is required');
1643
+ }
1623
1644
  configsForEntity = await this.configService.getEntityConfig(entityType, additionalContext);
1645
+ return configsForEntity.providers.flatMap((p) => p.nodes);
1624
1646
  }
1625
1647
  catch (e) {
1626
1648
  errorCode = e.status || 500;
1627
1649
  console.warn(`Could not retrieve nodes for entity: ${entityType}, error: `, e);
1650
+ return this.createErrorNodes(entityDefinition, errorCode, additionalContext);
1628
1651
  }
1629
- if (errorCode) {
1630
- return this.createErrorNodes(entityDefinition, additionalContext, errorCode);
1631
- }
1632
- return configsForEntity.providers.flatMap((p) => p.nodes);
1633
1652
  }
1634
- createErrorNodes(entityDefinition, additionalContext, errorCode) {
1653
+ createErrorNodes(entityDefinition, errorCode, additionalContext) {
1635
1654
  return [
1636
1655
  {
1637
1656
  pathSegment: 'error',
@@ -1956,10 +1975,10 @@ function logJMESException(context, jmesPathExpression, error) {
1956
1975
 
1957
1976
  const visibleForContext = (ctx, node) => {
1958
1977
  // visibleForEntityContext is deprecated
1959
- if (!isMatch(ctx.entityContext, node.visibleForEntityContext)) {
1978
+ if (!isMatch(ctx?.entityContext, node.visibleForEntityContext)) {
1960
1979
  return false;
1961
1980
  }
1962
- return matchesJMESPath(ctx, node.visibleForContext);
1981
+ return matchesJMESPath(ctx, node.visibleForContext ?? '');
1963
1982
  };
1964
1983
  const computeDynamicFetchContext = (entityNode, ctx) => {
1965
1984
  const contextForEntityConfig = new Map();
@@ -2057,6 +2076,9 @@ class NodeSortingService {
2057
2076
  const sortedOther = otherChildren.sort(this.nodeComparison);
2058
2077
  if (slotNodes.length > 0) {
2059
2078
  slotNodes.forEach((slotNode) => {
2079
+ if (!slotNode.defineSlot) {
2080
+ return;
2081
+ }
2060
2082
  if (slottedChildrenMap[slotNode.defineSlot]) {
2061
2083
  this.appendChildrenToSlot(sortedNodes, slotNode, slottedChildrenMap[slotNode.defineSlot].sort(this.nodeComparison));
2062
2084
  delete slottedChildrenMap[slotNode.defineSlot];
@@ -2119,7 +2141,7 @@ class ChildrenNodesService {
2119
2141
  entityContext[dynamicFetchId] = (await this.configService.getEntityConfig(dynamicFetchId, context)).entityContext;
2120
2142
  }
2121
2143
  catch (error) {
2122
- console.error(entityNode.defineEntity.id, 'does not exist', context);
2144
+ console.error(entityNode.defineEntity?.id, 'does not exist', context);
2123
2145
  }
2124
2146
  }));
2125
2147
  childrenNodes.forEach((child) => {
@@ -2188,6 +2210,7 @@ class CommonGlobalLuigiNodesService {
2188
2210
  label: 'Content not found',
2189
2211
  order: '1000',
2190
2212
  hideFromNav: true,
2213
+ context: {},
2191
2214
  children: [
2192
2215
  {
2193
2216
  pathSegment: ':id',
@@ -2221,6 +2244,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
2221
2244
  class NodesProcessingService {
2222
2245
  constructor() {
2223
2246
  this.nodeContextProcessingService = inject(LUIGI_CUSTOM_NODE_CONTEXT_PROCESSING_SERVICE_INJECTION_TOKEN, { optional: true });
2247
+ this.luigiCoreService = inject(LuigiCoreService);
2224
2248
  this.luigiNodesService = inject(LuigiNodesService);
2225
2249
  this.localConfigurationService = inject(LocalConfigurationServiceImpl);
2226
2250
  this.nodeSortingService = inject(NodeSortingService);
@@ -2270,6 +2294,13 @@ class NodesProcessingService {
2270
2294
  }
2271
2295
  }
2272
2296
  processNodeDefineEntity(node, childrenByEntity, parentEntityPath, directChildren) {
2297
+ if (!node.defineEntity) {
2298
+ this.luigiCoreService.showAlert({
2299
+ text: 'Node defineEntity is missing',
2300
+ type: 'error',
2301
+ });
2302
+ throw new Error('Node defineEntity is missing');
2303
+ }
2273
2304
  let newEntityPath = parentEntityPath;
2274
2305
  if (parentEntityPath?.length > 0) {
2275
2306
  newEntityPath = parentEntityPath + '.' + node.defineEntity.id;
@@ -2310,10 +2341,11 @@ class NodesProcessingService {
2310
2341
  entityChildrenProvider(entityNode, ctx, childrenByEntity, directChildren, entityPath) {
2311
2342
  return new Promise(async (resolve, reject) => {
2312
2343
  const entityTypeId = entityPath || entityNode?.defineEntity?.id;
2313
- const entityId = ctx[entityNode?.defineEntity?.contextKey];
2344
+ const contextKey = entityNode?.defineEntity?.contextKey;
2345
+ const entityId = contextKey ? ctx[contextKey] : undefined;
2314
2346
  const staticChildren = [
2315
2347
  ...(directChildren || []),
2316
- ...(childrenByEntity[entityTypeId] || []),
2348
+ ...(childrenByEntity[entityTypeId ?? ''] || []),
2317
2349
  ];
2318
2350
  await this.nodeContextProcessingService?.processNodeContext(entityId, entityNode, ctx);
2319
2351
  if (!entityTypeId || !entityNode.defineEntity?.dynamicFetchId) {
@@ -2334,7 +2366,7 @@ class NodesProcessingService {
2334
2366
  }
2335
2367
  catch (error) {
2336
2368
  dynamicRetrievedChildren = staticChildren;
2337
- staticRetrievedChildren = null;
2369
+ staticRetrievedChildren = undefined;
2338
2370
  }
2339
2371
  const childrenList = await this.createChildrenList(entityNode, ctx, childrenByEntity, entityPath, dynamicRetrievedChildren, staticRetrievedChildren);
2340
2372
  resolve(childrenList);
@@ -2419,7 +2451,7 @@ class NavigationConfigService {
2419
2451
  };
2420
2452
  }
2421
2453
  initFeatureToggles(configFeatureToggles, envConfig) {
2422
- if (envConfig.uiOptions.includes('enableFeatureToggleSetting')) {
2454
+ if (envConfig.uiOptions?.includes('enableFeatureToggleSetting')) {
2423
2455
  const featureToggleSettings = featureToggleLocalStorage.read();
2424
2456
  this.luigiCoreService.setFeatureToggles({
2425
2457
  ...configFeatureToggles,
@@ -2511,7 +2543,7 @@ class LifecycleHooksConfigService {
2511
2543
  this.luigiCoreService.ux().hideAppLoadingIndicator();
2512
2544
  }
2513
2545
  openErrorDialog() {
2514
- const appTitle = this.luigiCoreService.config.settings.header.title;
2546
+ const appTitle = this.luigiCoreService.config?.settings?.header?.title;
2515
2547
  this.luigiCoreService.showAlert({
2516
2548
  text: $localize `There was an error loading the ${appTitle}`,
2517
2549
  type: 'error',