@genesislcap/blank-app-seed 3.33.3 → 3.34.0

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 (52) hide show
  1. package/.genx/package.json +1 -1
  2. package/.genx/prompts/api.js +2 -9
  3. package/.genx/static.js +0 -1
  4. package/.genx/versions.json +3 -3
  5. package/.gitignore +1 -0
  6. package/CHANGELOG.md +30 -0
  7. package/README.md +4 -4
  8. package/client-tmp/react/package.json +22 -7
  9. package/client-tmp/react/public/favicon.ico +0 -0
  10. package/client-tmp/react/public/index.html +13 -0
  11. package/client-tmp/react/src/App.tsx +95 -68
  12. package/client-tmp/react/src/config.ts +2 -16
  13. package/client-tmp/react/src/custom-elements.d.ts +3 -1
  14. package/client-tmp/react/src/environments/environment.prod.ts +8 -0
  15. package/client-tmp/react/src/environments/environment.ts +9 -0
  16. package/client-tmp/react/src/guards/ProtectedGuard.tsx +64 -0
  17. package/client-tmp/react/src/helpers/hasPermissionHelper.tsx +10 -0
  18. package/client-tmp/react/src/helpers/isAuthenticatedHelper.tsx +14 -0
  19. package/client-tmp/react/src/helpers/isConnectedHelper.tsx +16 -0
  20. package/client-tmp/react/src/layouts/blank/BlankLayout.tsx +1 -1
  21. package/client-tmp/react/src/layouts/default/DefaultLayout.tsx +26 -15
  22. package/client-tmp/react/src/main.tsx +21 -5
  23. package/client-tmp/react/src/pages/NotFoundPage/NotFoundPage.css +0 -0
  24. package/client-tmp/react/src/pages/NotFoundPage/NotFoundPage.tsx +14 -0
  25. package/client-tmp/react/src/pages/NotPermittedPage/NotPermittedPage.test.tsx +1 -1
  26. package/client-tmp/react/src/pages/NotPermittedPage/NotPermittedPage.tsx +1 -1
  27. package/client-tmp/react/src/pbc/README.md +7 -0
  28. package/client-tmp/react/src/pbc/container.tsx +44 -0
  29. package/client-tmp/react/src/pbc/elementsRenderer.tsx +40 -0
  30. package/client-tmp/react/src/pbc/utils.ts +121 -0
  31. package/client-tmp/react/src/services/store.service.ts +48 -0
  32. package/client-tmp/react/src/share/foundation-login.ts +13 -6
  33. package/client-tmp/react/src/share/genesis-components.ts +49 -23
  34. package/client-tmp/react/src/store/AuthContext.tsx +0 -2
  35. package/client-tmp/react/src/store/RoutesContext.tsx +74 -0
  36. package/client-tmp/react/src/types/LayoutName.ts +3 -0
  37. package/client-tmp/react/src/types/RouteLayouts.ts +3 -1
  38. package/client-tmp/react/src/utils/getLayoutNameByRoute.ts +5 -0
  39. package/client-tmp/react/src/utils/history.ts +4 -2
  40. package/client-tmp/react/src/utils/index.ts +2 -1
  41. package/client-tmp/react/test/e2e/fixture.ts +1 -1
  42. package/client-tmp/react/tsconfig.app.json +1 -22
  43. package/client-tmp/react/tsconfig.json +30 -10
  44. package/client-tmp/react/vite.config.ts +26 -15
  45. package/client-tmp/react/webpack.config.js +103 -0
  46. package/package.json +1 -1
  47. package/testData/excel/.gitkeep +0 -0
  48. package/client-tmp/react/env.development.json +0 -3
  49. package/client-tmp/react/src/guards/AuthGuard.tsx +0 -32
  50. package/client-tmp/react/src/guards/PermissionsGuard.tsx +0 -37
  51. package/client-tmp/react/src/index.ts +0 -21
  52. package/client-tmp/react/src/reportWebVitals.ts +0 -13
@@ -1,24 +1,36 @@
1
1
  import React, { ReactNode, useEffect, useRef } from 'react';
2
- import { configureDesignSystem } from '@genesislcap/foundation-ui';
2
+ import { RouteObject } from 'react-router';
3
+ import { configureDesignSystem, getNavItems } from '@genesislcap/foundation-ui';
3
4
  import { useNavigate } from 'react-router-dom';
4
5
  import {
5
6
  baseLayerLuminance,
6
7
  StandardLuminance,
7
8
  } from '@microsoft/fast-components';
8
9
  import styles from './DefaultLayout.module.css';
9
- import { mainMenu } from '../../config';
10
- import * as designTokens from '../../styles/design-tokens.json';
10
+ import PBCElementsRenderer from '@/pbc/elementsRenderer';
11
+ import * as designTokens from '@/styles/design-tokens.json';
12
+ import { useRoutesContext } from '@/store/RoutesContext';
11
13
 
12
14
  interface DefaultLayoutProps {
13
15
  children: ReactNode;
14
16
  }
15
17
 
18
+ type ExtendedRouteObject = RouteObject & {
19
+ data?: {
20
+ navItems?: any;
21
+ };
22
+ path: string;
23
+ }
24
+
16
25
  const DefaultLayout: React.FC<DefaultLayoutProps> = ({ children }) => {
17
26
  const navigate = useNavigate();
18
-
19
27
  const designSystemProviderRef = useRef<HTMLElement>(null);
20
28
  const foundationHeaderRef = useRef<HTMLElement>(null);
21
- const allRoutes = mainMenu;
29
+ const routes = useRoutesContext() as ExtendedRouteObject[];
30
+ const navItems = getNavItems(routes.flatMap((route) => ({
31
+ path: route.path || '',
32
+ navItems: route.data?.navItems,
33
+ })));
22
34
 
23
35
  const onLuminanceToggle = (): void => {
24
36
  if (designSystemProviderRef.current) {
@@ -57,22 +69,21 @@ const DefaultLayout: React.FC<DefaultLayoutProps> = ({ children }) => {
57
69
 
58
70
  return (
59
71
  <rapid-design-system-provider ref={designSystemProviderRef} class={className}>
72
+ <PBCElementsRenderer target={['layout-start']} />
60
73
  <foundation-header
61
74
  ref={foundationHeaderRef}
62
75
  show-luminance-toggle-button
63
76
  show-misc-toggle-button
64
- navigateTo={(path) => navigate(path)}
77
+ routeNavItems={navItems}
78
+ navigateTo={(path: string) => navigate(path)}
65
79
  >
66
- <section className={styles['routes-wrapper']} slot="routes">
67
- {allRoutes.map((route, index) => (
68
- <rapid-button key={index} onClick={() => navigate(route.path)}>
69
- <rapid-icon name={route.icon}></rapid-icon>
70
- {route.title}
71
- </rapid-button>
72
- ))}
73
- </section>
74
80
  </foundation-header>
75
- <section className={styles['content']}>{children}</section>
81
+ <section className={styles['content']}>
82
+ <PBCElementsRenderer target={['content-start']} />
83
+ {children}
84
+ <PBCElementsRenderer target={['content', 'content-end']} />
85
+ </section>
86
+ <PBCElementsRenderer target={['layout', 'layout-end']} />
76
87
  </rapid-design-system-provider>
77
88
  );
78
89
  };
@@ -1,10 +1,26 @@
1
1
  import React from 'react'
2
2
  import ReactDOM from 'react-dom/client'
3
3
  import App from './App.tsx'
4
+
5
+ import { registerPBCs } from '@/pbc/utils';
6
+ import { createLogger } from '@genesislcap/foundation-logger';
7
+
4
8
  import './styles/styles.css'
5
9
 
6
- ReactDOM.createRoot(document.getElementById('root')!).render(
7
- <React.StrictMode>
8
- <App />
9
- </React.StrictMode>,
10
- )
10
+ const logger = createLogger('main');
11
+
12
+ function bootstrapApp() {
13
+ const rootEelement = document.getElementById('root');
14
+ if (rootEelement) {
15
+ ReactDOM.createRoot(rootEelement!).render(
16
+ <React.StrictMode>
17
+ <App rootElement={rootEelement} />
18
+ </React.StrictMode>,
19
+ )
20
+ }
21
+ }
22
+
23
+ registerPBCs()
24
+ .then(hasAssets => logger.debug(hasAssets ? 'PBCs registered' : 'No PBCs detected'))
25
+ .catch((err) => logger.error(err))
26
+ .finally(bootstrapApp)
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import ErrorMessage from '@/components/ErrorMessage/ErrorMessage';
3
+ import './NotFoundPage.css';
4
+
5
+ const NotFoundPage: React.FC = () => {
6
+ return (
7
+ <ErrorMessage
8
+ elementType="h1"
9
+ message="Page Not Found 404"
10
+ />
11
+ );
12
+ };
13
+
14
+ export default NotFoundPage;
@@ -1,7 +1,7 @@
1
1
  import { render, screen } from '@testing-library/react';
2
2
  import NotPermittedPage from './NotPermittedPage';
3
3
 
4
- jest.mock('../../components/ErrorMessage/ErrorMessage', () => {
4
+ jest.mock('@/components/ErrorMessage/ErrorMessage', () => {
5
5
  return jest.fn((props: { message: string }) => <h1 data-testid="error-message">{props.message}</h1>);
6
6
  });
7
7
 
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import ErrorMessage from '../../components/ErrorMessage/ErrorMessage';
2
+ import ErrorMessage from '@/components/ErrorMessage/ErrorMessage';
3
3
  import './NotPermittedPage.css';
4
4
 
5
5
  const NotPermittedPage: React.FC = () => {
@@ -0,0 +1,7 @@
1
+ # PBC
2
+
3
+ This directory contains PBC `genx add` output.
4
+
5
+ The app will reload if you remove, add, or customise a packaged business capability.
6
+
7
+ See the expanded README.md in `@genesislcap/foundation-shell`.
@@ -0,0 +1,44 @@
1
+ import React, { useEffect, useRef, RouteObject } from 'react';
2
+ import { deriveElementTag } from './utils';
3
+ import { useRoutesContext } from '@/store/RoutesContext';
4
+ import { useLocation } from 'react-router-dom';
5
+
6
+ type ExtendedRouteObject = RouteObject & {
7
+ data?: {
8
+ pbcElementTag?: string;
9
+ pbcElement?: any;
10
+ };
11
+ path: string;
12
+ }
13
+
14
+ const PBCContainer: React.FC = () => {
15
+ const containerRef = useRef<HTMLDivElement>(null);
16
+ const routes = useRoutesContext() as ExtendedRouteObject[];
17
+ const location = useLocation();
18
+
19
+ useEffect(() => {
20
+ const loadElement = async () => {
21
+ const route = routes.find(({ path }) => path === location.pathname);
22
+ const { data } = route || {};
23
+ const { pbcElement, pbcElementTag } = data || {};
24
+
25
+ if (!pbcElement) {
26
+ return;
27
+ }
28
+ const element = pbcElement.define ? pbcElement : await pbcElement();
29
+ const tagName = pbcElementTag || deriveElementTag(element.name);
30
+ const customElement = document.createElement(tagName);
31
+
32
+ if (containerRef.current) {
33
+ containerRef.current.replaceChildren();
34
+ containerRef.current.appendChild(customElement);
35
+ }
36
+ };
37
+
38
+ loadElement();
39
+ }, [location.pathname, routes]);
40
+
41
+ return <div ref={containerRef} className="container" style=\{{ width: '100%', height: '100%' }}></div>;
42
+ };
43
+
44
+ export default PBCContainer;
@@ -0,0 +1,40 @@
1
+ import { useEffect, useRef } from 'react';
2
+ import { AppElementPredicate, AppTargetId } from '@genesislcap/foundation-shell/app';
3
+ import { customEventFactory, getTargetElements } from './utils';
4
+
5
+ interface PBCElementsRendererProps {
6
+ target: AppTargetId;
7
+ predicate?: AppElementPredicate;
8
+ }
9
+
10
+ interface PBCContainerElement extends HTMLDivElement {
11
+ $emit: (type: string, detail: any) => void;
12
+ }
13
+
14
+ const PBCElementsRenderer = ({ target = [], predicate = () => true }: PBCElementsRendererProps) => {
15
+ const containerRef = useRef<PBCContainerElement>(null);
16
+
17
+ useEffect(() => {
18
+ if (containerRef.current) {
19
+ containerRef.current.$emit = (type, detail) => {
20
+ containerRef.current.dispatchEvent(customEventFactory(type, detail));
21
+ }
22
+ }
23
+ }, []);
24
+
25
+ useEffect(() => {
26
+ if (containerRef.current) {
27
+ containerRef.current.replaceChildren();
28
+ }
29
+ const templates = getTargetElements(target, predicate);
30
+ templates.forEach((currentTemplate: any) => {
31
+ if (containerRef.current) {
32
+ currentTemplate.render(containerRef.current, containerRef.current);
33
+ }
34
+ });
35
+ }, [target, predicate]);
36
+
37
+ return (<div ref={containerRef} className="container"></div>);
38
+ };
39
+
40
+ export default PBCElementsRenderer;
@@ -0,0 +1,121 @@
1
+ import { createLogger } from '@genesislcap/foundation-logger';
2
+ import {
3
+ AppContext,
4
+ AppElement,
5
+ AppElementPredicate,
6
+ AppStyle,
7
+ AppStylePredicate,
8
+ AppTargetId,
9
+ assetPredicate,
10
+ getApp,
11
+ registrationPredicate,
12
+ targetIdPredicate
13
+ } from '@genesislcap/foundation-shell/app';
14
+ import { importPBCAssets } from '@genesislcap/foundation-shell/pbc';
15
+ import { toElementStyles } from '@genesislcap/foundation-utils';
16
+ import { ComposableStyles } from '@genesislcap/web-core';
17
+
18
+ const logger = createLogger('pbc-utils');
19
+
20
+ /**
21
+ * Some of this logic already exists in shell, but exists as part of a logic chain that assumes web components.
22
+ * After testing, we can backport the changes required.
23
+ */
24
+
25
+ /**
26
+ * @public
27
+ */
28
+ export async function registerPBCs(): Promise<boolean> {
29
+ const app = getApp();
30
+ const pbcAssets = await importPBCAssets();
31
+ app.registerAssets(pbcAssets);
32
+ return app.hasAssets();
33
+ }
34
+
35
+ /**
36
+ * @privateRemarks
37
+ * Shared across elements and styles.
38
+ */
39
+ const assetFilter = (
40
+ asset: AppElement | AppStyle,
41
+ targetId: AppTargetId,
42
+ predicate: AppElementPredicate | AppStylePredicate = () => true,
43
+ context: AppContext,
44
+ ) => targetIdPredicate(asset, targetId) &&
45
+ assetPredicate(asset, context) &&
46
+ registrationPredicate(
47
+ asset,
48
+ predicate,
49
+ context,
50
+ );
51
+
52
+ /**
53
+ * @public
54
+ */
55
+ export function getTargetStyles(
56
+ targetId: AppTargetId,
57
+ predicate: AppStylePredicate = () => true
58
+ ) {
59
+ const app = getApp();
60
+ return app.styles
61
+ .filter(asset => assetFilter(asset, targetId, predicate, app.config.context!))
62
+ .map((token) => token.styles)
63
+ .flat();
64
+ }
65
+
66
+
67
+ /**
68
+ * @public
69
+ */
70
+ export function getTargetElements(
71
+ targetId: AppTargetId,
72
+ predicate: AppElementPredicate = () => true
73
+ ) {
74
+ const app = getApp();
75
+ return app.elements
76
+ .filter(asset => assetFilter(asset, targetId, predicate, app.config.context!))
77
+ .map((token) => token.elements);
78
+ }
79
+
80
+ /**
81
+ * @public
82
+ */
83
+ export function registerStylesTarget(nativeElement: HTMLElement, targetId: AppTargetId) {
84
+ const styles = getTargetStyles(targetId);
85
+ if (!styles || styles.length === 0) {
86
+ return;
87
+ }
88
+ applyDynamicStyles(nativeElement, styles);
89
+ }
90
+
91
+ /**
92
+ * @public
93
+ */
94
+ export function applyDynamicStyles(nativeElement: HTMLElement, style: ComposableStyles | ComposableStyles[]) {
95
+ const elementStyles = toElementStyles(style);
96
+ const styleTarget = nativeElement.shadowRoot ? nativeElement.shadowRoot : document;
97
+ elementStyles.addStylesTo(styleTarget);
98
+ }
99
+
100
+ /**
101
+ * @public
102
+ */
103
+ export function customEventFactory(type: string, detail?: any) {
104
+ return new CustomEvent(type, {
105
+ bubbles: true,
106
+ cancelable: true,
107
+ composed: true,
108
+ detail,
109
+ });
110
+ }
111
+
112
+ /**
113
+ * @privateRemarks
114
+ * May need to add an elementTag to routes, ie. elementTag: 'notifications-dashboard'. May remove when complete.
115
+ * @public
116
+ */
117
+ export function deriveElementTag(name: string): string {
118
+ const tagName = name.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '');
119
+ logger.debug(`Guessing pbc element tag is '${tagName}' based on '${name}'. This may be incorrect, please set pbcElementTag in route data.`);
120
+ return tagName;
121
+ }
@@ -0,0 +1,48 @@
1
+
2
+ import { CustomEventMap } from '@genesislcap/foundation-events';
3
+ import { getApp } from '@genesislcap/foundation-shell/app';
4
+ import {
5
+ AbstractStoreRoot,
6
+ registerStore,
7
+ StoreRoot,
8
+ StoreRootEventDetailMap,
9
+ } from '@genesislcap/foundation-store';
10
+ import { DI } from '@genesislcap/web-core';
11
+
12
+ interface Store extends StoreRoot {}
13
+ type StoreEventDetailMap = StoreRootEventDetailMap & Record<string, never>;
14
+
15
+ declare global {
16
+ interface HTMLElementEventMap extends CustomEventMap<StoreEventDetailMap> {}
17
+ }
18
+
19
+ class DefaultStore extends AbstractStoreRoot<Store, StoreEventDetailMap> implements Store {
20
+ constructor() {
21
+ super();
22
+
23
+ /**
24
+ * Register the store root
25
+ */
26
+ getApp().registerStoreRoot(this);
27
+ }
28
+ }
29
+
30
+ const Store = registerStore(DefaultStore, 'Store');
31
+
32
+ class StoreService {
33
+ private store: any;
34
+
35
+ constructor() {
36
+ this.store = DI.getOrCreateDOMContainer().get(Store) as Store;
37
+ }
38
+
39
+ getStore() {
40
+ return this.store;
41
+ }
42
+
43
+ onConnected(event?: CustomEvent) {
44
+ this.store.onConnected(event);
45
+ }
46
+ }
47
+
48
+ export const storeService = new StoreService();
@@ -1,21 +1,28 @@
1
1
  import {configure, define} from '@genesislcap/foundation-login';
2
- import { AUTH_PATH } from '../config';
3
- import { DI } from '@microsoft/fast-foundation';
4
- import { history } from '../utils/history';
2
+ import { getUser } from '@genesislcap/foundation-user';
3
+ import { DI } from '@genesislcap/web-core';
4
+ import { AUTH_PATH } from '@/config';
5
+ import type { Router } from '@/utils/history';
5
6
 
6
7
  /**
7
8
  * Configure the micro frontend
8
9
  */
9
- export const configureFoundationLogin = () => {
10
+ export const configureFoundationLogin = ({ router }:{ router: Router }) => {
10
11
  configure(DI.getOrCreateDOMContainer(), {
12
+ autoConnect: true,
13
+ autoAuth: true, // < Allow users to skip login
11
14
  showConnectionIndicator: true,
12
15
  hostPath: AUTH_PATH,
13
16
  redirectHandler: () => {
14
- history.push('/{{kebabCase routes.[0].name}}');
17
+ // workaround for redirect from foundation-login
18
+ setTimeout(() => {
19
+ const lastPath = getUser().lastPath() ?? '/{{kebabCase routes.[0].name}}';
20
+ router.push(lastPath);
21
+ }, 0);
15
22
  },
16
23
  });
17
24
 
18
25
  return define({
19
26
  name: `client-app-login`,
20
27
  });
21
- };
28
+ }
@@ -1,32 +1,58 @@
1
- import { configure as configureHeader }from '@genesislcap/foundation-header/config';
2
- import { foundationLayoutComponents } from '@genesislcap/foundation-layout';
3
1
  import { EntityManagement } from '@genesislcap/foundation-entity-management';
2
+ import { Form } from '@genesislcap/foundation-forms';
3
+ import { foundationLayoutComponents } from '@genesislcap/foundation-layout';
4
+ import { getApp } from '@genesislcap/foundation-shell/app';
5
+ import * as zeroDesignSystem from '@genesislcap/foundation-zero';
4
6
  import { g2plotChartsComponents } from '@genesislcap/g2plot-chart';
5
7
  import * as rapidDesignSystem from '@genesislcap/rapid-design-system';
6
8
  import { rapidGridComponents } from '@genesislcap/rapid-grid-pro';
7
- import { configureFoundationLogin } from './foundation-login';
9
+ import { FoundationRouter } from '@genesislcap/foundation-ui';
8
10
 
11
+ /**
12
+ * Ensure tree shaking doesn't remove these.
13
+ */
14
+ FoundationRouter;
9
15
  EntityManagement;
16
+ Form;
17
+
18
+ /**
19
+ * registerComponents.
20
+ * @public
21
+ */
22
+ export async function registerComponents() {
23
+ const { configure: configureHeader } = await import('@genesislcap/foundation-header/config');
24
+ /**
25
+ * Register any PBC components with the design system
26
+ */
27
+ getApp().registerComponents({
28
+ designSystem: rapidDesignSystem,
29
+ });
10
30
 
11
- configureHeader({
12
- templateOptions: {
13
- provider: 'template',
14
- icon: 'rapid-icon',
15
- button: 'rapid-button',
16
- connectionIndicator: 'rapid-connection-indicator',
17
- select: 'rapid-select',
18
- option: 'rapid-option',
19
- flyout: 'rapid-flyout',
20
- },
21
- });
31
+ rapidDesignSystem
32
+ .provideDesignSystem()
33
+ .register(
34
+ rapidDesignSystem.baseComponents,
35
+ rapidGridComponents,
36
+ g2plotChartsComponents,
37
+ foundationLayoutComponents,
38
+ );
22
39
 
23
- configureFoundationLogin();
40
+ configureHeader({
41
+ templateOptions: {
42
+ provider: 'template',
43
+ icon: 'rapid-icon',
44
+ button: 'rapid-button',
45
+ connectionIndicator: 'rapid-connection-indicator',
46
+ select: 'rapid-select',
47
+ option: 'rapid-option',
48
+ flyout: 'rapid-flyout',
49
+ },
50
+ });
24
51
 
25
- rapidDesignSystem
26
- .provideDesignSystem()
27
- .register(
28
- rapidDesignSystem.baseComponents,
29
- rapidGridComponents,
30
- g2plotChartsComponents,
31
- foundationLayoutComponents,
32
- );
52
+ /**
53
+ * May be still required while we transition all PBCs to rapid. Remove when complete.
54
+ */
55
+ zeroDesignSystem
56
+ .provideDesignSystem()
57
+ .register(zeroDesignSystem.baseComponents, g2plotChartsComponents, foundationLayoutComponents);
58
+ }
@@ -48,8 +48,6 @@ export const AuthProvider: FunctionComponent<AuthProviderProps> = ({
48
48
  }
49
49
  };
50
50
 
51
-
52
-
53
51
  const value = { user, setUser, checkAuthStatus };
54
52
 
55
53
  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
@@ -0,0 +1,74 @@
1
+ import React, { createContext, useContext, ReactNode } from 'react';
2
+ import { RouteObject, Navigate } from 'react-router-dom';
3
+ import { getApp } from '@genesislcap/foundation-shell/app';
4
+ import AuthPage from '@/pages/AuthPage/AuthPage';
5
+ import NotFoundPage from '@/pages/NotFoundPage/NotFoundPage';
6
+ import NotPermittedPage from '@/pages/NotPermittedPage/NotPermittedPage';
7
+ {{#each routes}}
8
+ import {{pascalCase this.name}} from '@/pages/{{pascalCase this.name}}/{{pascalCase this.name}}';
9
+ {{/each}}
10
+ import PBCContainer from '@/pbc/container';
11
+ import { AUTH_PATH, NOT_PERMITTED_PATH } from '@/config';
12
+
13
+ const routes = [
14
+ {
15
+ path: '',
16
+ element: <Navigate to={AUTH_PATH} replace />,
17
+ },
18
+ {
19
+ path: '/not-found',
20
+ element: <NotFoundPage />,
21
+ },
22
+ {
23
+ path: `/${AUTH_PATH}`,
24
+ element: <AuthPage />,
25
+ },
26
+ {
27
+ path: `/${NOT_PERMITTED_PATH}`,
28
+ element: <NotPermittedPage />,
29
+ },
30
+ {{#each routes}}
31
+ {
32
+ path: '/{{kebabCase this.name}}',
33
+ element: <{{pascalCase this.name}} />,
34
+ data: {
35
+ permissionCode: '{{this.permissions.viewRight}}',
36
+ navItems: [
37
+ {
38
+ navId: 'header',
39
+ title: '{{#if this.title}}{{this.title}}{{else}}{{this.name}}{{/if}}',
40
+ icon: {
41
+ name: '{{this.icon}}',
42
+ variant: 'solid',
43
+ },
44
+ },
45
+ ],
46
+ },
47
+ },
48
+ {{/each}}
49
+ ];
50
+
51
+ const RoutesContext = createContext<RouteObject[]>([]);
52
+
53
+ export const RoutesProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
54
+ const pbcRoutes = getApp().routes.map((route) => ({
55
+ title: route.title,
56
+ path: `/${route.path}`,
57
+ element: <PBCContainer />,
58
+ data: {
59
+ ...route.settings,
60
+ pbcElement: route.element,
61
+ // @ts-expect-error - getApp() is not typed to return the elementTag
62
+ pbcElementTag: route.elementTag,
63
+ navItems: route.navItems,
64
+ },
65
+ }));
66
+
67
+ const allRoutes = [...routes, ...pbcRoutes];
68
+
69
+ return <RoutesContext.Provider value={allRoutes}>{children}</RoutesContext.Provider>;
70
+ };
71
+
72
+ export const useRoutesContext = () => {
73
+ return useContext(RoutesContext);
74
+ };
@@ -0,0 +1,3 @@
1
+ type LayoutName = 'blank' | 'default';
2
+
3
+ export default LayoutName;
@@ -1,3 +1,5 @@
1
+ import LayoutName from './LayoutName';
2
+
1
3
  export interface RouteLayouts {
2
- [key: string]: 'blank' | 'default';
4
+ [key: string]: LayoutName;
3
5
  }
@@ -0,0 +1,5 @@
1
+ import { routeLayouts } from '@/config';
2
+
3
+ export const getLayoutNameByRoute = (route: string) => {
4
+ return routeLayouts[route] || 'default';
5
+ }
@@ -1,3 +1,5 @@
1
- import { createBrowserHistory } from 'history';
1
+ import { createBrowserHistory, History } from 'history';
2
2
 
3
- export const history = createBrowserHistory();
3
+ export type Router = History;
4
+
5
+ export const history = createBrowserHistory() as History;
@@ -2,4 +2,5 @@ export * from './history';
2
2
  export * from './fdc3';
3
3
  export * from './layout';
4
4
  export * from './permissions';
5
- export * from './setApiHost';
5
+ export * from './setApiHost';
6
+ export * from './getLayoutNameByRoute';
@@ -1,6 +1,6 @@
1
1
  import { base, Page } from '@genesislcap/foundation-testing/e2e';
2
2
  import { ProtectedPage } from './pages';
3
- import { PORT } from '../../playwright.config';
3
+ import { PORT } from '@/playwright.config';
4
4
 
5
5
  export type FixtureConfig = {
6
6
  API_HOST: string;