@genesislcap/blank-app-seed 3.30.0-prerelease.14 → 3.30.0-prerelease.16

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 (47) hide show
  1. package/.genx/package.json +1 -1
  2. package/CHANGELOG.md +14 -0
  3. package/client-tmp/react/package.json +22 -7
  4. package/client-tmp/react/public/favicon.ico +0 -0
  5. package/client-tmp/react/public/index.html +13 -0
  6. package/client-tmp/react/src/App.tsx +95 -68
  7. package/client-tmp/react/src/config.ts +2 -16
  8. package/client-tmp/react/src/custom-elements.d.ts +3 -1
  9. package/client-tmp/react/src/environments/environment.prod.ts +8 -0
  10. package/client-tmp/react/src/environments/environment.ts +9 -0
  11. package/client-tmp/react/src/guards/ProtectedGuard.tsx +64 -0
  12. package/client-tmp/react/src/helpers/hasPermissionHelper.tsx +10 -0
  13. package/client-tmp/react/src/helpers/isAuthenticatedHelper.tsx +14 -0
  14. package/client-tmp/react/src/helpers/isConnectedHelper.tsx +16 -0
  15. package/client-tmp/react/src/layouts/blank/BlankLayout.tsx +1 -1
  16. package/client-tmp/react/src/layouts/default/DefaultLayout.tsx +26 -15
  17. package/client-tmp/react/src/main.tsx +21 -5
  18. package/client-tmp/react/src/pages/NotFoundPage/NotFoundPage.css +0 -0
  19. package/client-tmp/react/src/pages/NotFoundPage/NotFoundPage.tsx +14 -0
  20. package/client-tmp/react/src/pages/NotPermittedPage/NotPermittedPage.test.tsx +1 -1
  21. package/client-tmp/react/src/pages/NotPermittedPage/NotPermittedPage.tsx +1 -1
  22. package/client-tmp/react/src/pbc/README.md +7 -0
  23. package/client-tmp/react/src/pbc/container.tsx +44 -0
  24. package/client-tmp/react/src/pbc/elementsRenderer.tsx +40 -0
  25. package/client-tmp/react/src/pbc/utils.ts +121 -0
  26. package/client-tmp/react/src/services/store.service.ts +48 -0
  27. package/client-tmp/react/src/share/foundation-login.ts +13 -6
  28. package/client-tmp/react/src/share/genesis-components.ts +49 -23
  29. package/client-tmp/react/src/store/AuthContext.tsx +0 -2
  30. package/client-tmp/react/src/store/RoutesContext.tsx +74 -0
  31. package/client-tmp/react/src/types/LayoutName.ts +3 -0
  32. package/client-tmp/react/src/types/RouteLayouts.ts +3 -1
  33. package/client-tmp/react/src/utils/getLayoutNameByRoute.ts +5 -0
  34. package/client-tmp/react/src/utils/history.ts +4 -2
  35. package/client-tmp/react/src/utils/index.ts +2 -1
  36. package/client-tmp/react/test/e2e/fixture.ts +1 -1
  37. package/client-tmp/react/tsconfig.app.json +1 -22
  38. package/client-tmp/react/tsconfig.json +30 -10
  39. package/client-tmp/react/vite.config.ts +26 -15
  40. package/client-tmp/react/webpack.config.js +103 -0
  41. package/package.json +1 -1
  42. package/client-tmp/react/env.development.json +0 -3
  43. package/client-tmp/react/src/guards/AuthGuard.tsx +0 -32
  44. package/client-tmp/react/src/guards/PermissionsGuard.tsx +0 -37
  45. package/client-tmp/react/src/index.ts +0 -21
  46. package/client-tmp/react/src/reportWebVitals.ts +0 -13
  47. /package/server/{{appName}}-app/src/main/genesis/scripts/{{{appName}}-data-pipelines.kts → {{appName}}-pipelines.kts} +0 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@genesislcap/blank-app-seed-config",
3
3
  "description": "Genesis Blank App Seed Configuration",
4
- "version": "3.30.0-prerelease.14",
4
+ "version": "3.30.0-prerelease.16",
5
5
  "license": "Apache-2.0",
6
6
  "scripts": {
7
7
  "lint": "eslint .",
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.30.0-prerelease.16](https://github.com/genesiscommunitysuccess/blank-app-seed/compare/v3.30.0-prerelease.15...v3.30.0-prerelease.16) (2024-09-30)
4
+
5
+
6
+ ### Features
7
+
8
+ * add webpack builder in react (#350) 69c4c6b, closes FUI-2173 FUI-2173 FUI-2173 FUI-2157 FUI-2157 origin/ak/FUI-2173 ak/FUI-2157 FUI-2157 FUI-2157 FUI-2140 FUI-2140 FUI-2140 FUI-2140 FUI-2140 FUI-2140 FUI-2140 FUI-2140 FUI-2140 FUI-2140 FUI-2140 FUI-2140 FUI-2140 FUI-2140 FUI-2140 FUI-2140 FUI-2140
9
+
10
+ ## [3.30.0-prerelease.15](https://github.com/genesiscommunitysuccess/blank-app-seed/compare/v3.30.0-prerelease.14...v3.30.0-prerelease.15) (2024-09-26)
11
+
12
+
13
+ ### Features
14
+
15
+ * pbc support in react [FUI-2140](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/2140) (#347) 4c41243, closes FUI-2173 FUI-2173 FUI-2173 FUI-2157 FUI-2157 origin/ak/FUI-2173 ak/FUI-2157 FUI-2157 FUI-2157
16
+
3
17
  ## [3.30.0-prerelease.14](https://github.com/genesiscommunitysuccess/blank-app-seed/compare/v3.30.0-prerelease.13...v3.30.0-prerelease.14) (2024-09-26)
4
18
 
5
19
 
@@ -6,10 +6,13 @@
6
6
  "baseline": "npm run clean && npm run bootstrap",
7
7
  "bootstrap": "npm i --legacy-peer-deps",
8
8
  "bootstrap:ci": "npm ci --no-fund --no-audit",
9
- "build": "vite build",
10
9
  "build:stats": "npm run build --stats-json",
11
10
  "clean": "genx clean dist node_modules",
12
- "dev": "vite",
11
+ "dev": "webpack serve --mode development",
12
+ "build": "webpack --mode production",
13
+ "stats": "webpack --mode production --json > stats.json",
14
+ "build:vite": "vite build",
15
+ "dev:vite": "vite build && vite preview",
13
16
  "dev:docker": "npm run dev -- --host 0.0.0.0",
14
17
  "dev:no-open": "NO_OPEN=true npm run dev",
15
18
  "dev:intellij": "npm run dev",
@@ -33,17 +36,21 @@
33
36
  "@ag-grid-enterprise/core": "29.2.0",
34
37
  "@ag-grid-enterprise/row-grouping": "29.2.0",
35
38
  "@ag-grid-enterprise/server-side-row-model": "29.2.0",
39
+ "@genesislcap/foundation-comms": "{{versions.UI}}",
40
+ "@genesislcap/foundation-entity-management": "{{versions.UI}}",
36
41
  {{#if FDC3.includeDependencies}}
37
42
  "@genesislcap/foundation-fdc3": "{{versions.UI}}",
38
43
  {{/if}}
39
- "@genesislcap/foundation-comms": "{{versions.UI}}",
40
- "@genesislcap/foundation-login": "{{versions.UI}}",
41
- "@genesislcap/foundation-entity-management": "{{versions.UI}}",
42
44
  "@genesislcap/foundation-header": "{{versions.UI}}",
45
+ "@genesislcap/foundation-layout": "{{versions.UI}}",
46
+ "@genesislcap/foundation-logger": "{{versions.UI}}",
47
+ "@genesislcap/foundation-login": "{{versions.UI}}",
48
+ "@genesislcap/foundation-shell": "{{versions.UI}}",
43
49
  "@genesislcap/foundation-ui": "{{versions.UI}}",
50
+ "@genesislcap/foundation-utils": "{{versions.UI}}",
44
51
  "@genesislcap/rapid-design-system": "{{versions.UI}}",
45
52
  "@genesislcap/rapid-grid-pro": "{{versions.UI}}",
46
- "@genesislcap/foundation-layout": "{{versions.UI}}",
53
+ "@genesislcap/web-core": "{{versions.UI}}",
47
54
  "@genesislcap/g2plot-chart": "{{versions.UI}}",
48
55
  "history": "^5.3.0",
49
56
  "react": "^19.0.0-beta-94eed63c49-20240425",
@@ -64,6 +71,7 @@
64
71
  "@testing-library/dom": "^10.4.0",
65
72
  "@testing-library/jest-dom": "^6.5.0",
66
73
  "@testing-library/react": "^16.0.0",
74
+ "@types/css-modules": "^1.0.5",
67
75
  "@types/jest": "^29.5.12",
68
76
  "@types/node": "^20.14.10",
69
77
  "@types/react": "npm:types-react@alpha",
@@ -71,16 +79,23 @@
71
79
  "@typescript-eslint/eslint-plugin": "^7.13.1",
72
80
  "@typescript-eslint/parser": "^7.13.1",
73
81
  "@vitejs/plugin-react": "^4.3.1",
82
+ "babel-loader": "^9.2.1",
74
83
  "babel-plugin-react-require": "^4.0.3",
84
+ "dotenv-webpack": "^8.1.0",
75
85
  "eslint": "^8.57.0",
76
86
  "eslint-plugin-react-hooks": "^4.6.2",
77
87
  "eslint-plugin-react-refresh": "^0.4.7",
88
+ "file-loader": "^6.2.0",
78
89
  "jest": "^29.7.0",
79
90
  "jest-environment-jsdom": "^29.7.0",
80
91
  "ts-jest": "^29.2.5",
81
92
  "ts-node": "^10.9.2",
82
93
  "typescript": "^5.2.2",
83
- "vite": "^5.3.1"
94
+ "vite": "^5.3.1",
95
+ "vite-plugin-tsconfig-paths": "^1.4.1",
96
+ "webpack": "^5.94.0",
97
+ "webpack-cli": "^5.1.4",
98
+ "webpack-dev-server": "^5.1.0"
84
99
  },
85
100
  "overrides": {
86
101
  "@types/react": "npm:types-react@alpha",
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/x-icon" href="favicon.ico">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>{{capitalCase appName}}</title>
8
+ </head>
9
+ <body>
10
+ <div id="root"></div>
11
+ <script src="/bundle.js"></script>
12
+ </body>
13
+ </html>
@@ -1,31 +1,75 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { unstable_HistoryRouter as HistoryRouter, Routes, Route, useLocation } from 'react-router-dom';
1
3
  import {
2
- unstable_HistoryRouter as HistoryRouter,
3
- Routes,
4
- Route,
5
- useLocation,
6
- } from 'react-router-dom';
7
- import { useEffect } from 'react';
8
- import { history, setApiHost{{#if FDC3.channels.length}}, listenToChannel{{/if}} } from './utils';
4
+ history,
5
+ setApiHost,
6
+ getLayoutNameByRoute,
7
+ {{#if FDC3.channels.length~}}
8
+ listenToChannel,
9
+ onFDC3Ready,
10
+ {{/if}}
11
+ } from './utils';
12
+ import { customEventFactory, registerStylesTarget } from '@/pbc/utils';
9
13
  import LayoutWrapper from './layouts/LayoutWrapper';
10
- import { AUTH_PATH, NOT_PERMITTED_PATH, routeLayouts } from './config';
11
- import AuthGuard from './guards/AuthGuard';
12
- import PermissionsGuard from './guards/PermissionsGuard';
14
+ import LayoutName from '@/types/LayoutName';
15
+ import { AUTH_PATH, routeLayouts } from './config';
13
16
  import { AuthProvider } from './store/AuthContext';
14
- // Pages Components
17
+ import { RoutesProvider, useRoutesContext } from './store/RoutesContext';
15
18
  import AuthPage from './pages/AuthPage/AuthPage';
16
- import NotPermittedPage from './pages/NotPermittedPage/NotPermittedPage';
17
- {{#each routes}}
18
- import {{pascalCase this.name}} from './pages/{{pascalCase this.name}}/{{pascalCase this.name}}';
19
- {{/each}}
20
-
21
- // Genesis Components
22
- import './share/genesis-components';
19
+ import { registerComponents as genesisRegisterComponents } from './share/genesis-components';
20
+ import { configureFoundationLogin } from './share/foundation-login';
21
+ import ProtectedGuard from './guards/ProtectedGuard';
22
+ import { storeService } from '@/services/store.service';
23
23
 
24
- const LayoutWithLocation = () => {
24
+ const DynamicLayout = () => {
25
25
  const location = useLocation();
26
- const layout = routeLayouts[location.pathname] || 'default';
27
- {{#if FDC3.channels.length}}
26
+ const [layoutName, setLayoutName] = useState<LayoutName>(routeLayouts[location.pathname] || 'default');
27
+ const handleRouteChange = (location: any) => {
28
+ setLayoutName(getLayoutNameByRoute(location.pathname));
29
+ };
30
+ const route = useRoutesContext().find((r) => r.path === location.pathname);
31
+ let pageComponent;
32
+ let content;
33
+
28
34
  useEffect(() => {
35
+ handleRouteChange(location);
36
+ const unlisten = history.listen(handleRouteChange);
37
+
38
+ return () => {
39
+ unlisten();
40
+ }
41
+ }, [location]);
42
+
43
+ if (route) {
44
+ pageComponent = route.element;
45
+ } else {
46
+ pageComponent = <AuthPage />;
47
+ }
48
+
49
+ if (location.pathname === `/${AUTH_PATH}` || location.pathname === '/') {
50
+ content = pageComponent;
51
+ } else {
52
+ content = <ProtectedGuard>{pageComponent}</ProtectedGuard>
53
+ }
54
+
55
+ return <LayoutWrapper layout={layoutName}>{content}</LayoutWrapper>
56
+
57
+ };
58
+
59
+ interface AppProps {
60
+ rootElement: HTMLElement;
61
+ }
62
+
63
+ const App: React.FC<AppProps> = ({ rootElement }) => {
64
+ const [isStoreConnected, setIsStoreConnected] = useState(false);
65
+ const dispatchCustomEvent = (type: string, detail?: any) => {
66
+ rootElement.dispatchEvent(customEventFactory(type, detail));
67
+ };
68
+ const handleStoreConnected = (event: CustomEvent) => {
69
+ storeService.onConnected(event);
70
+ };
71
+ {{#if FDC3.channels.length~}}
72
+ const FDC3ReadyHandler = () => {
29
73
  {{#each FDC3.channels}}
30
74
  listenToChannel('{{this.name}}', '{{this.type}}', (result) => {
31
75
  console.log('Received FDC3 channel message on: {{this.name}} channel, type: {{this.type}}', result);
@@ -33,61 +77,44 @@ const LayoutWithLocation = () => {
33
77
  // E.g. open a modal or route to specific page: Route.path.push(`[Route name]`);
34
78
  });
35
79
  {{/each}}
36
-
37
- return () => {
38
- console.log('Component is being unmounted');
39
- };
40
- }, []);
80
+ };
41
81
  {{/if}}
42
82
 
43
- let pageComponent;
44
- let permissionCode = '{{this.permissions.viewRight}}';
45
-
46
- switch (location.pathname) {
47
- case `/${AUTH_PATH}`:
48
- pageComponent = <AuthPage />;
49
- break;
50
- case `/${NOT_PERMITTED_PATH}`:
51
- pageComponent = <NotPermittedPage />;
52
- break;
53
- {{#each routes}}
54
- case '/{{kebabCase this.name}}':
55
- pageComponent = <{{pascalCase this.name}} />;
56
- permissionCode = '{{this.permissions.viewRight}}';
57
- break;
58
- {{/each}}
59
- default:
60
- pageComponent = <AuthPage />;
61
- }
83
+ setApiHost();
84
+ genesisRegisterComponents();
85
+ configureFoundationLogin({ router: history });
62
86
 
63
- if (
64
- location.pathname === '/auth' ||
65
- location.pathname === '/'
66
- ) {
67
- return <LayoutWrapper layout={layout}>{pageComponent}</LayoutWrapper>;
68
- } else {
69
- return (
70
- <AuthGuard>
71
- <PermissionsGuard permissionCode={permissionCode}>
72
- <LayoutWrapper layout={layout}>{pageComponent}</LayoutWrapper>
73
- </PermissionsGuard>
74
- </AuthGuard>
75
- );
76
- }
77
- };
87
+ useEffect(() => {
88
+ registerStylesTarget(document.body, 'main');
89
+ {{#if FDC3.channels.length~}}
90
+ onFDC3Ready(FDC3ReadyHandler);
91
+ {{/if}}
92
+ if (!isStoreConnected) {
93
+ rootElement.addEventListener('store-connected', handleStoreConnected);
94
+ dispatchCustomEvent('store-connected', rootElement);
95
+ dispatchCustomEvent('store-ready', true);
96
+ setIsStoreConnected(true);
97
+ }
78
98
 
79
- const App: React.FC = () => {
80
- setApiHost();
99
+ return () => {
100
+ if (isStoreConnected) {
101
+ rootElement.removeEventListener('store-connected', handleStoreConnected);
102
+ dispatchCustomEvent('store-disconnected');
103
+ }
104
+ };
105
+ }, [isStoreConnected]);
81
106
 
82
107
  return (
83
108
  <AuthProvider>
84
- <HistoryRouter history={history}>
85
- <Routes>
86
- <Route path="*" element={<LayoutWithLocation />} />
87
- </Routes>
88
- </HistoryRouter>
109
+ <RoutesProvider>
110
+ <HistoryRouter history={history as any}>
111
+ <Routes>
112
+ <Route path="*" element={<DynamicLayout />} />
113
+ </Routes>
114
+ </HistoryRouter>
115
+ </RoutesProvider>
89
116
  </AuthProvider>
90
117
  );
91
118
  };
92
119
 
93
- export default App;
120
+ export default App;
@@ -1,32 +1,18 @@
1
1
  import { RouteLayouts } from './types/RouteLayouts';
2
+ import { environment } from '@environment';
2
3
 
3
4
  export const routeLayouts: RouteLayouts = {
4
- '/auth-mock': 'blank',
5
5
  '/auth': 'blank',
6
6
  '/': 'blank',
7
7
  };
8
8
 
9
- import type { MainMenu } from './types/menu';
10
-
11
9
  export const AUTH_PATH = 'auth';
12
10
  export const NOT_PERMITTED_PATH = 'not-permitted';
13
11
 
14
12
  export const API_DATA = {
15
- URL: import.meta.env.VITE_API_HOST,
13
+ URL: environment.API_HOST,
16
14
  AUTH: {
17
15
  username: '', // provide login to a user in given environment
18
16
  password: '', // provide password to a user in given environment
19
17
  },
20
18
  };
21
-
22
- export const mainMenu: MainMenu = [
23
- {{#each routes}}
24
- {
25
- index: {{@index}},
26
- path: '{{kebabCase this.name}}',
27
- title: '{{#if this.title}}{{this.title}}{{else}}{{this.name}}{{/if}}',
28
- icon: '{{this.icon}}',
29
- variant: 'solid'
30
- }{{#unless @last}},{{/unless}}
31
- {{/each}}
32
- ];
@@ -1,10 +1,11 @@
1
1
  import React, { useState, DOMAttributes } from 'react';
2
2
 
3
- type CustomElement<T = HTMLElement> = Partial<T & DOMAttributes<T> & { children: any }>;
3
+ type CustomElement<T = React.HTMLAttributes<HTMLElement>> = Partial<T & DOMAttributes<T> & { [key: string]: any }>;
4
4
 
5
5
  declare module "react/jsx-runtime" {
6
6
  namespace JSX {
7
7
  interface IntrinsicElements {
8
+ 'rapid-design-system-provider': CustomElement;
8
9
  'entity-management': CustomElement;
9
10
  'foundation-form': CustomElement;
10
11
  'rapid-grid-pro': CustomElement;
@@ -16,6 +17,7 @@ declare module "react/jsx-runtime" {
16
17
  'rapid-layout': CustomElement;
17
18
  'rapid-layout-region': CustomElement;
18
19
  'rapid-layout-item': CustomElement;
20
+ 'foundation-header': CustomElement;
19
21
  }
20
22
  }
21
23
  }
@@ -0,0 +1,8 @@
1
+ export const environment = {
2
+ production: true,
3
+ PORT: 4200,
4
+ ENABLE_SSO: {{enableSSO}},
5
+ HOST: 'localhost',
6
+ PROTOCOL: 'http',
7
+ BUILDER: 'webpack',
8
+ };
@@ -0,0 +1,9 @@
1
+ export const environment = {
2
+ production: false,
3
+ API_HOST: '{{apiHost}}',
4
+ PORT: 4200,
5
+ ENABLE_SSO: {{enableSSO}},
6
+ HOST: 'localhost',
7
+ PROTOCOL: 'http',
8
+ BUILDER: 'webpack'
9
+ };
@@ -0,0 +1,64 @@
1
+ import { useState, useEffect, ReactNode } from 'react';
2
+ import { RouteObject } from 'react-router';
3
+ import isConnectedHelper from '@/helpers/isConnectedHelper';
4
+ import isAuthenticatedHelper from '@/helpers/isAuthenticatedHelper';
5
+ import hasPermissionHelper from '@/helpers/hasPermissionHelper';
6
+ import { useRoutesContext } from '@/store/RoutesContext';
7
+ import { NOT_PERMITTED_PATH, AUTH_PATH } from '@/config';
8
+
9
+ enum PermissionState {
10
+ ALLOWED = 'allowed',
11
+ DENIED = 'denied',
12
+ UNKNOWN = 'unknown',
13
+ }
14
+
15
+ const redirectUrlByPermissionState: { [key in Partial<PermissionState>]?: string } = {
16
+ [PermissionState.DENIED]: NOT_PERMITTED_PATH,
17
+ [PermissionState.UNKNOWN]: AUTH_PATH,
18
+ };
19
+
20
+ type ExtendedRouteObject = RouteObject & {
21
+ data?: {
22
+ permissionCode?: string;
23
+ };
24
+ path: string;
25
+ }
26
+
27
+ const ProtectedGuard: React.FC<{ children: ReactNode }> = ({ children }: { children: ReactNode }) => {
28
+ const routes = useRoutesContext() as ExtendedRouteObject[];
29
+ const [isConnected, setIsConnected] = useState<boolean | null>(null);
30
+ const isAuthenticated: boolean | null = null;
31
+ const route = routes.find(({ path }) => path === location.pathname);
32
+ const hasPermission = route?.data?.permissionCode ? hasPermissionHelper(route.data?.permissionCode) : true;
33
+
34
+ useEffect(() => {
35
+ isConnectedHelper().then((connectedState: boolean): void => {
36
+ setIsConnected(connectedState);
37
+ });
38
+ }, []);
39
+
40
+ useEffect((): void => {
41
+ if (isConnected === null) {
42
+ return;
43
+ }
44
+
45
+ const isAuthenticated = isAuthenticatedHelper();
46
+
47
+
48
+ let permissionState;
49
+
50
+ if (!isConnected || !isAuthenticated) {
51
+ permissionState = PermissionState.UNKNOWN;
52
+ } else if (hasPermission === false) {
53
+ permissionState = PermissionState.DENIED;
54
+ }
55
+
56
+ if (permissionState) {
57
+ window.location.href = `/${redirectUrlByPermissionState[permissionState]}`;
58
+ }
59
+ }, [routes, isConnected, isAuthenticated, hasPermission]);
60
+
61
+ return children;
62
+ };
63
+
64
+ export default ProtectedGuard;
@@ -0,0 +1,10 @@
1
+ import { getUser } from '@genesislcap/foundation-user';
2
+
3
+ const hasPermissionHelper = (permissionCode: string | undefined): boolean => {
4
+ const user = getUser();
5
+
6
+ return !!(permissionCode && !user.hasPermission(permissionCode))
7
+
8
+ };
9
+
10
+ export default hasPermissionHelper;
@@ -0,0 +1,14 @@
1
+ import { getUser } from '@genesislcap/foundation-user';
2
+
3
+ const isAuthenticatedHelper = (): boolean => {
4
+ const user = getUser();
5
+
6
+ if (!user.isAuthenticated) {
7
+ user.trackPath();
8
+ return false;
9
+ }
10
+
11
+ return true;
12
+ };
13
+
14
+ export default isAuthenticatedHelper;
@@ -0,0 +1,16 @@
1
+ import { getConnect } from '@genesislcap/foundation-comms';
2
+
3
+ const isConnectedHelper = (): Promise<boolean> => {
4
+ const connect = getConnect();
5
+ const hostUrl = sessionStorage.getItem('hostUrl');
6
+
7
+ if (connect.isConnected) {
8
+ return new Promise((resolve) => resolve(true));
9
+ }
10
+ if (!hostUrl) {
11
+ return new Promise((resolve) => resolve(false));
12
+ }
13
+ return connect.connect(hostUrl);
14
+ };
15
+
16
+ export default isConnectedHelper;
@@ -1,7 +1,7 @@
1
1
  import React, { ReactNode, useEffect, useRef } from 'react';
2
2
  import { configureDesignSystem } from '@genesislcap/foundation-ui';
3
3
  import styles from './BlankLayout.module.css';
4
- import * as designTokens from '../../styles/design-tokens.json';
4
+ import * as designTokens from '@/styles/design-tokens.json';
5
5
 
6
6
  interface BlankLayoutProps {
7
7
  children: ReactNode;
@@ -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`.