@genesislcap/blank-app-seed 3.30.0-prerelease.3 → 3.30.0-prerelease.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.genx/configure.js +5 -0
- package/.genx/package.json +1 -1
- package/.genx/prompts/api.js +2 -9
- package/.genx/prompts/server.js +9 -0
- package/.genx/prompts.js +9 -2
- package/.genx/static.js +1 -1
- package/.genx/templates/angular/component/component.hbs +12 -0
- package/.genx/templates/react/chart.hbs +7 -3
- package/.genx/templates/react/component/component.column.defs.hbs +4 -2
- package/.genx/templates/react/component/component.create.form.hbs +2 -2
- package/.genx/templates/react/component/component.gridOptions.hbs +4 -2
- package/.genx/templates/react/component/component.hbs +76 -27
- package/.genx/templates/react/component/component.index.hbs +1 -1
- package/.genx/templates/react/component/component.update.form.hbs +1 -1
- package/.genx/templates/react/entityManager.hbs +62 -49
- package/.genx/templates/react/form.hbs +7 -3
- package/.genx/templates/react/grid.hbs +16 -10
- package/.genx/templates/react/route.hbs +3 -3
- package/.genx/templates/react/tabsLayout.hbs +5 -5
- package/.genx/templates/web-components/component/component.hbs +12 -0
- package/.genx/templates/web-components/route.template.hbs +2 -2
- package/.genx/utils/deleteGradleWrappers.js +12 -0
- package/.genx/utils/generateRoute.js +9 -7
- package/.genx/utils/generateTile.js +31 -16
- package/.genx/utils/index.js +2 -0
- package/.genx/versions.json +3 -3
- package/.gitignore +3 -0
- package/.idea/modules.xml +6 -6
- package/CHANGELOG.md +189 -0
- package/README.md +5 -5
- package/client-tmp/angular/__mocks__/fileMock.js +1 -0
- package/client-tmp/angular/angular.json +0 -29
- package/client-tmp/angular/jest.config.js +20 -0
- package/client-tmp/angular/package.json +6 -6
- package/client-tmp/angular/src/app/layouts/default/default.layout.spec.ts +2 -2
- package/client-tmp/angular/src/jest.setup.ts +46 -0
- package/client-tmp/angular/tsconfig.app.json +1 -2
- package/client-tmp/angular/tsconfig.json +1 -2
- package/client-tmp/angular/tsconfig.spec.json +13 -7
- package/client-tmp/react/.babelrc +10 -0
- package/client-tmp/react/.eslintrc.cjs +1 -0
- package/client-tmp/react/jest.config.ts +15 -0
- package/client-tmp/react/jest.setup.ts +1 -0
- package/client-tmp/react/lint-css.ts +19 -0
- package/client-tmp/react/package.json +45 -17
- package/client-tmp/react/public/favicon.ico +0 -0
- package/client-tmp/react/public/index.html +13 -0
- package/client-tmp/react/src/App.tsx +95 -68
- package/client-tmp/react/src/components/{ErrorMessage.test.js → ErrorMessage/ErrorMessage.test.tsx} +31 -16
- package/client-tmp/react/src/components/ErrorMessage/{ErrorMessage.jsx → ErrorMessage.tsx} +9 -4
- package/client-tmp/react/src/config.ts +2 -16
- package/client-tmp/react/src/custom-elements.d.ts +21 -9
- package/client-tmp/react/src/environments/environment.prod.ts +8 -0
- package/client-tmp/react/src/environments/environment.ts +9 -0
- package/client-tmp/react/src/guards/ProtectedGuard.tsx +64 -0
- package/client-tmp/react/src/helpers/hasPermissionHelper.tsx +10 -0
- package/client-tmp/react/src/helpers/isAuthenticatedHelper.tsx +14 -0
- package/client-tmp/react/src/helpers/isConnectedHelper.tsx +16 -0
- package/client-tmp/react/src/layouts/blank/BlankLayout.tsx +1 -1
- package/client-tmp/react/src/layouts/default/DefaultLayout.tsx +26 -15
- package/client-tmp/react/src/main.tsx +21 -5
- package/client-tmp/react/src/pages/AuthPage/AuthPage.test.tsx +10 -0
- package/client-tmp/react/src/pages/AuthPage/{AuthPage.jsx → AuthPage.tsx} +3 -2
- package/client-tmp/react/src/pages/NotFoundPage/NotFoundPage.css +0 -0
- package/client-tmp/react/src/pages/NotFoundPage/NotFoundPage.tsx +14 -0
- package/client-tmp/react/src/pages/NotPermittedPage/NotPermittedPage.test.tsx +17 -0
- package/client-tmp/react/src/pages/NotPermittedPage/NotPermittedPage.tsx +14 -0
- package/client-tmp/react/src/pbc/README.md +7 -0
- package/client-tmp/react/src/pbc/container.tsx +44 -0
- package/client-tmp/react/src/pbc/elementsRenderer.tsx +40 -0
- package/client-tmp/react/src/pbc/utils.ts +121 -0
- package/client-tmp/react/src/services/store.service.ts +48 -0
- package/client-tmp/react/src/share/foundation-login.ts +13 -6
- package/client-tmp/react/src/share/genesis-components.ts +49 -23
- package/client-tmp/react/src/store/AuthContext.tsx +0 -2
- package/client-tmp/react/src/store/RoutesContext.tsx +74 -0
- package/client-tmp/react/src/types/LayoutName.ts +3 -0
- package/client-tmp/react/src/types/RouteLayouts.ts +3 -1
- package/client-tmp/react/src/utils/getLayoutNameByRoute.ts +5 -0
- package/client-tmp/react/src/utils/history.ts +4 -2
- package/client-tmp/react/src/utils/index.ts +3 -1
- package/client-tmp/react/src/utils/layout.ts +11 -0
- package/client-tmp/react/test/e2e/fixture.ts +1 -1
- package/client-tmp/react/tsconfig.app.json +2 -26
- package/client-tmp/react/tsconfig.json +31 -8
- package/client-tmp/react/tsconfig.node.json +1 -1
- package/client-tmp/react/vite.config.ts +70 -0
- package/client-tmp/react/webpack.config.js +103 -0
- package/client-tmp/web-components/package.json +2 -1
- package/client-tmp/web-components/src/main/main.styles.ts +1 -1
- package/client-tmp/web-components/src/utils/index.ts +1 -0
- package/client-tmp/web-components/src/utils/layout.ts +11 -0
- package/client-tmp/web-components/tsconfig.json +1 -1
- package/package.json +1 -1
- package/server/build.gradle.kts +1 -0
- package/server/gradle.properties +1 -0
- package/server/settings.gradle.kts +8 -7
- package/settings.gradle.kts +7 -4
- package/testData/excel/.gitkeep +0 -0
- package/client-tmp/angular/karma.conf.js +0 -9
- package/client-tmp/angular/src/app/app.component.spec.ts +0 -23
- package/client-tmp/react/env.development.json +0 -3
- package/client-tmp/react/lint-css.js +0 -18
- package/client-tmp/react/src/guards/AuthGuard.tsx +0 -32
- package/client-tmp/react/src/guards/PermissionsGuard.tsx +0 -37
- package/client-tmp/react/src/index.js +0 -17
- package/client-tmp/react/src/pages/NotPermittedPage/NotPermittedPage.jsx +0 -13
- package/client-tmp/react/src/reportWebVitals.js +0 -13
- package/client-tmp/react/vite.config.js +0 -59
- /package/client-tmp/react/src/{setupTests.js → setupTests.ts} +0 -0
- /package/server/{{appName}}-app/src/main/genesis/scripts/{{{appName}}-data-pipelines.kts → {{appName}}-pipelines.kts} +0 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import glob from 'glob';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
const cssFiles: string[] = glob.sync(path.join(__dirname, '**/*.css'));
|
|
6
|
+
|
|
7
|
+
if (cssFiles.length === 0) {
|
|
8
|
+
console.log('No CSS files found.');
|
|
9
|
+
process.exit(0);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const command: string = `genx lint -l stylelint ${cssFiles.join(' ')}`;
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
execSync(command, { stdio: 'inherit' });
|
|
16
|
+
} catch (error) {
|
|
17
|
+
console.error('Error running stylelint:', error);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
@@ -2,29 +2,35 @@
|
|
|
2
2
|
"name": "{{pkgName}}",
|
|
3
3
|
"version": "{{applicationVersionWeb}}",
|
|
4
4
|
"private": true,
|
|
5
|
+
"config": {
|
|
6
|
+
"PERSIST_LAYOUT_IN_DEV": false
|
|
7
|
+
},
|
|
5
8
|
"scripts": {
|
|
6
9
|
"baseline": "npm run clean && npm run bootstrap",
|
|
7
10
|
"bootstrap": "npm i --legacy-peer-deps",
|
|
8
11
|
"bootstrap:ci": "npm ci --no-fund --no-audit",
|
|
9
|
-
"build": "vite build",
|
|
10
12
|
"build:stats": "npm run build --stats-json",
|
|
11
13
|
"clean": "genx clean dist node_modules",
|
|
12
|
-
"dev": "
|
|
14
|
+
"dev": "webpack serve --mode development",
|
|
15
|
+
"build": "webpack --mode production",
|
|
16
|
+
"stats": "webpack --mode production --json > stats.json",
|
|
17
|
+
"build:vite": "vite build",
|
|
18
|
+
"dev:vite": "vite build && vite preview",
|
|
13
19
|
"dev:docker": "npm run dev -- --host 0.0.0.0",
|
|
14
20
|
"dev:no-open": "NO_OPEN=true npm run dev",
|
|
15
21
|
"dev:intellij": "npm run dev",
|
|
16
22
|
"dev:https": "HTTPS=true npm run dev",
|
|
17
23
|
"dsconfig": "dsconfig --path src/styles/design-tokens.json",
|
|
18
|
-
"lint": "eslint src/**/*.
|
|
19
|
-
"lint:fix": "eslint src/**/*.
|
|
24
|
+
"lint": "eslint src/**/*.ts src/**/*.tsx",
|
|
25
|
+
"lint:fix": "eslint src/**/*.ts src/**/*.tsx --fix",
|
|
20
26
|
"lint:eslint": "npm lint",
|
|
21
|
-
"lint:stylelint": "node lint-css.
|
|
22
|
-
"test": "
|
|
27
|
+
"lint:stylelint": "npx ts-node lint-css.ts",
|
|
28
|
+
"test": "jest",
|
|
29
|
+
"test:coverage": "jest --coverage",
|
|
30
|
+
"test:unit:watch": "jest --watchAll",
|
|
23
31
|
"test:e2e": "genx test --e2e",
|
|
24
32
|
"test:e2e:debug": "genx test --e2e --debug",
|
|
25
|
-
"test:e2e:ui": "genx test --e2e --interactive"
|
|
26
|
-
"test:coverage": "genx test --no-watch --coverage",
|
|
27
|
-
"test:unit:watch": "genx test --watch"
|
|
33
|
+
"test:e2e:ui": "genx test --e2e --interactive"
|
|
28
34
|
},
|
|
29
35
|
"dependencies": {
|
|
30
36
|
"@ag-grid-community/client-side-row-model": "29.2.0",
|
|
@@ -33,24 +39,32 @@
|
|
|
33
39
|
"@ag-grid-enterprise/core": "29.2.0",
|
|
34
40
|
"@ag-grid-enterprise/row-grouping": "29.2.0",
|
|
35
41
|
"@ag-grid-enterprise/server-side-row-model": "29.2.0",
|
|
42
|
+
"@genesislcap/foundation-comms": "{{versions.UI}}",
|
|
43
|
+
"@genesislcap/foundation-entity-management": "{{versions.UI}}",
|
|
36
44
|
{{#if FDC3.includeDependencies}}
|
|
37
45
|
"@genesislcap/foundation-fdc3": "{{versions.UI}}",
|
|
38
46
|
{{/if}}
|
|
39
|
-
"@genesislcap/foundation-comms": "{{versions.UI}}",
|
|
40
|
-
"@genesislcap/foundation-login": "{{versions.UI}}",
|
|
41
|
-
"@genesislcap/foundation-entity-management": "{{versions.UI}}",
|
|
42
47
|
"@genesislcap/foundation-header": "{{versions.UI}}",
|
|
48
|
+
"@genesislcap/foundation-layout": "{{versions.UI}}",
|
|
49
|
+
"@genesislcap/foundation-logger": "{{versions.UI}}",
|
|
50
|
+
"@genesislcap/foundation-login": "{{versions.UI}}",
|
|
51
|
+
"@genesislcap/foundation-shell": "{{versions.UI}}",
|
|
43
52
|
"@genesislcap/foundation-ui": "{{versions.UI}}",
|
|
53
|
+
"@genesislcap/foundation-utils": "{{versions.UI}}",
|
|
44
54
|
"@genesislcap/rapid-design-system": "{{versions.UI}}",
|
|
45
55
|
"@genesislcap/rapid-grid-pro": "{{versions.UI}}",
|
|
46
|
-
"@genesislcap/
|
|
56
|
+
"@genesislcap/web-core": "{{versions.UI}}",
|
|
47
57
|
"@genesislcap/g2plot-chart": "{{versions.UI}}",
|
|
48
58
|
"history": "^5.3.0",
|
|
49
|
-
"react": "^19.0.0-
|
|
50
|
-
"react-dom": "^19.0.0-
|
|
51
|
-
"react-router-dom": "6.24.1"
|
|
59
|
+
"react": "^19.0.0-rc-ed966dac-20241007",
|
|
60
|
+
"react-dom": "^19.0.0-rc-ed966dac-20241007",
|
|
61
|
+
"react-router-dom": "6.24.1",
|
|
62
|
+
"web-vitals": "^2.1.4"
|
|
52
63
|
},
|
|
53
64
|
"devDependencies": {
|
|
65
|
+
"@babel/core": "^7.25.2",
|
|
66
|
+
"@babel/preset-env": "^7.25.4",
|
|
67
|
+
"@babel/preset-react": "^7.24.7",
|
|
54
68
|
"@genesislcap/design-system-configurator": "{{versions.UI}}",
|
|
55
69
|
"@genesislcap/eslint-config": "{{versions.UI}}",
|
|
56
70
|
"@genesislcap/prettier-config": "{{versions.UI}}",
|
|
@@ -60,17 +74,31 @@
|
|
|
60
74
|
"@testing-library/dom": "^10.4.0",
|
|
61
75
|
"@testing-library/jest-dom": "^6.5.0",
|
|
62
76
|
"@testing-library/react": "^16.0.0",
|
|
77
|
+
"@types/css-modules": "^1.0.5",
|
|
78
|
+
"@types/jest": "^29.5.12",
|
|
63
79
|
"@types/node": "^20.14.10",
|
|
64
80
|
"@types/react": "npm:types-react@alpha",
|
|
65
81
|
"@types/react-dom": "npm:types-react-dom@alpha",
|
|
66
82
|
"@typescript-eslint/eslint-plugin": "^7.13.1",
|
|
67
83
|
"@typescript-eslint/parser": "^7.13.1",
|
|
68
84
|
"@vitejs/plugin-react": "^4.3.1",
|
|
85
|
+
"babel-loader": "^9.2.1",
|
|
86
|
+
"babel-plugin-react-require": "^4.0.3",
|
|
87
|
+
"dotenv-webpack": "^8.1.0",
|
|
69
88
|
"eslint": "^8.57.0",
|
|
70
89
|
"eslint-plugin-react-hooks": "^4.6.2",
|
|
71
90
|
"eslint-plugin-react-refresh": "^0.4.7",
|
|
91
|
+
"file-loader": "^6.2.0",
|
|
92
|
+
"jest": "^29.7.0",
|
|
93
|
+
"jest-environment-jsdom": "^29.7.0",
|
|
94
|
+
"ts-jest": "^29.2.5",
|
|
95
|
+
"ts-node": "^10.9.2",
|
|
72
96
|
"typescript": "^5.2.2",
|
|
73
|
-
"vite": "^5.3.1"
|
|
97
|
+
"vite": "^5.3.1",
|
|
98
|
+
"vite-plugin-tsconfig-paths": "^1.4.1",
|
|
99
|
+
"webpack": "^5.94.0",
|
|
100
|
+
"webpack-cli": "^5.1.4",
|
|
101
|
+
"webpack-dev-server": "^5.1.0"
|
|
74
102
|
},
|
|
75
103
|
"overrides": {
|
|
76
104
|
"@types/react": "npm:types-react@alpha",
|
|
Binary file
|
|
@@ -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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
|
11
|
-
import
|
|
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
|
-
|
|
17
|
+
import { RoutesProvider, useRoutesContext } from './store/RoutesContext';
|
|
15
18
|
import AuthPage from './pages/AuthPage/AuthPage';
|
|
16
|
-
import
|
|
17
|
-
{
|
|
18
|
-
import
|
|
19
|
-
{
|
|
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
|
|
24
|
+
const DynamicLayout = () => {
|
|
25
25
|
const location = useLocation();
|
|
26
|
-
const
|
|
27
|
-
{
|
|
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
|
-
|
|
44
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
80
|
-
|
|
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
|
-
<
|
|
85
|
-
<
|
|
86
|
-
<
|
|
87
|
-
|
|
88
|
-
|
|
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;
|
package/client-tmp/react/src/components/{ErrorMessage.test.js → ErrorMessage/ErrorMessage.test.tsx}
RENAMED
|
@@ -1,35 +1,33 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
1
|
import { render, screen } from '@testing-library/react';
|
|
3
|
-
import '
|
|
4
|
-
import ErrorMessage from './ErrorMessage';
|
|
2
|
+
import { default as ErrorMessage, ErrorMessageProps } from './ErrorMessage';
|
|
5
3
|
|
|
6
4
|
describe('ErrorMessage Component', () => {
|
|
7
|
-
const message = 'Test Error Message';
|
|
5
|
+
const message: string = 'Test Error Message';
|
|
8
6
|
|
|
9
7
|
test('renders the message as a div by default', () => {
|
|
10
8
|
render(<ErrorMessage message={message} />);
|
|
11
|
-
const displayedMessage = screen.getByText(message);
|
|
9
|
+
const displayedMessage: HTMLElement = screen.getByText(message);
|
|
12
10
|
expect(displayedMessage.tagName).toBe('DIV');
|
|
13
11
|
expect(displayedMessage).toBeInTheDocument();
|
|
14
12
|
});
|
|
15
13
|
|
|
16
14
|
test('renders the message as an h1 element when elementType is "h1"', () => {
|
|
17
15
|
render(<ErrorMessage message={message} elementType="h1" />);
|
|
18
|
-
const displayedMessage = screen.getByRole('heading', { level: 1 });
|
|
16
|
+
const displayedMessage: HTMLElement = screen.getByRole('heading', { level: 1 });
|
|
19
17
|
expect(displayedMessage.tagName).toBe('H1');
|
|
20
18
|
expect(displayedMessage).toBeInTheDocument();
|
|
21
19
|
});
|
|
22
20
|
|
|
23
21
|
test('renders the message as a p element when elementType is "p"', () => {
|
|
24
22
|
render(<ErrorMessage message={message} elementType="p" />);
|
|
25
|
-
const displayedMessage = screen.getByText(message);
|
|
23
|
+
const displayedMessage: HTMLElement = screen.getByText(message);
|
|
26
24
|
expect(displayedMessage.tagName).toBe('P');
|
|
27
25
|
expect(displayedMessage).toBeInTheDocument();
|
|
28
26
|
});
|
|
29
27
|
|
|
30
28
|
test('applies the correct styles to the error message wrapper', () => {
|
|
31
29
|
render(<ErrorMessage message={message} />);
|
|
32
|
-
const wrapper = screen.getByText(message).closest('section');
|
|
30
|
+
const wrapper: HTMLElement | null = screen.getByText(message).closest('section');
|
|
33
31
|
expect(wrapper).toHaveStyle(`
|
|
34
32
|
display: flex;
|
|
35
33
|
flex-direction: column;
|
|
@@ -42,8 +40,8 @@ describe('ErrorMessage Component', () => {
|
|
|
42
40
|
|
|
43
41
|
test('applies the correct styles to the error message itself', () => {
|
|
44
42
|
render(<ErrorMessage message={message} />);
|
|
45
|
-
const displayedMessage = screen.getByText(message);
|
|
46
|
-
const messageWrapper = displayedMessage.parentElement;
|
|
43
|
+
const displayedMessage: HTMLElement = screen.getByText(message);
|
|
44
|
+
const messageWrapper: HTMLElement | null = displayedMessage.parentElement;
|
|
47
45
|
|
|
48
46
|
expect(messageWrapper).toBeInTheDocument();
|
|
49
47
|
expect(messageWrapper).toHaveStyle(`
|
|
@@ -64,17 +62,34 @@ describe('ErrorMessage Component', () => {
|
|
|
64
62
|
});
|
|
65
63
|
|
|
66
64
|
test('renders nothing if the message is an empty string', () => {
|
|
67
|
-
const { container } = render(<ErrorMessage message="" />);
|
|
65
|
+
const { container }: { container: HTMLElement } = render(<ErrorMessage message="" />);
|
|
68
66
|
expect(container.firstChild).toBeNull();
|
|
69
67
|
});
|
|
70
68
|
|
|
71
69
|
test('renders the correct element type for various elementType props', () => {
|
|
72
|
-
const elementTypes = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'span', 'div'];
|
|
73
|
-
elementTypes.forEach((elementType) => {
|
|
74
|
-
const { container } = render(<ErrorMessage message={message} elementType={elementType} />);
|
|
75
|
-
const displayedMessage = container.querySelector(elementType);
|
|
70
|
+
const elementTypes: ErrorMessageProps['elementType'][] = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'span', 'div'];
|
|
71
|
+
elementTypes.forEach((elementType: ErrorMessageProps['elementType']) => {
|
|
72
|
+
const { container }: { container: HTMLElement } = render(<ErrorMessage message={message} elementType={elementType} />);
|
|
73
|
+
const displayedMessage: HTMLElement | null = container.querySelector(elementType as string);
|
|
76
74
|
expect(displayedMessage).toBeInTheDocument();
|
|
77
|
-
expect(displayedMessage
|
|
75
|
+
expect(displayedMessage?.tagName).toBe((elementType as string).toUpperCase());
|
|
78
76
|
});
|
|
79
77
|
});
|
|
78
|
+
|
|
79
|
+
test('renders the message as a div element when elementType is unknown', () => {
|
|
80
|
+
render(<ErrorMessage message={message} />);
|
|
81
|
+
const displayedMessage: HTMLElement = screen.getByText(message);
|
|
82
|
+
expect(displayedMessage.tagName).toBe('DIV');
|
|
83
|
+
expect(displayedMessage).toBeInTheDocument();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test('renders nothing if the message is null', () => {
|
|
87
|
+
const { container }: { container: HTMLElement } = render(<ErrorMessage />);
|
|
88
|
+
expect(container.firstChild).toBeNull();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('renders nothing if the message is undefined', () => {
|
|
92
|
+
const { container }: { container: HTMLElement } = render(<ErrorMessage message={undefined} />);
|
|
93
|
+
expect(container.firstChild).toBeNull();
|
|
94
|
+
});
|
|
80
95
|
});
|
|
@@ -3,7 +3,7 @@ import React from 'react';
|
|
|
3
3
|
const styles = {
|
|
4
4
|
errorMessageWrapper: {
|
|
5
5
|
display: 'flex',
|
|
6
|
-
flexDirection: 'column',
|
|
6
|
+
flexDirection: 'column' as const,
|
|
7
7
|
justifyContent: 'center',
|
|
8
8
|
alignItems: 'center',
|
|
9
9
|
height: '100%',
|
|
@@ -14,11 +14,11 @@ const styles = {
|
|
|
14
14
|
backgroundColor: 'var(--neutral-layer-4)',
|
|
15
15
|
borderColor: 'var(--error-color)',
|
|
16
16
|
borderRadius: '7px',
|
|
17
|
-
borderStyle: 'solid',
|
|
17
|
+
borderStyle: 'solid' as const,
|
|
18
18
|
borderWidth: '4px',
|
|
19
19
|
padding: '5px',
|
|
20
20
|
margin: '15px',
|
|
21
|
-
textAlign: 'center',
|
|
21
|
+
textAlign: 'center' as const,
|
|
22
22
|
width: 'fit-content',
|
|
23
23
|
alignSelf: 'center',
|
|
24
24
|
height: 'auto',
|
|
@@ -26,7 +26,12 @@ const styles = {
|
|
|
26
26
|
},
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
export interface ErrorMessageProps {
|
|
30
|
+
elementType?: 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'span';
|
|
31
|
+
message?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const ErrorMessage: React.FC<ErrorMessageProps> = ({ elementType = 'div', message = '' }) => {
|
|
30
35
|
const ElementType = elementType;
|
|
31
36
|
|
|
32
37
|
return message && message !== '' && (
|
|
@@ -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:
|
|
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,11 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
interface IntrinsicElements {
|
|
3
|
-
// Wildcard for all webcomponents:
|
|
4
|
-
[elemName: string]: unknown;
|
|
5
|
-
}
|
|
6
|
-
}
|
|
1
|
+
import React, { useState, DOMAttributes } from 'react';
|
|
7
2
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
type CustomElement<T = React.HTMLAttributes<HTMLElement>> = Partial<T & DOMAttributes<T> & { [key: string]: any }>;
|
|
4
|
+
|
|
5
|
+
declare module "react/jsx-runtime" {
|
|
6
|
+
namespace JSX {
|
|
7
|
+
interface IntrinsicElements {
|
|
8
|
+
'rapid-design-system-provider': CustomElement;
|
|
9
|
+
'entity-management': CustomElement;
|
|
10
|
+
'foundation-form': CustomElement;
|
|
11
|
+
'rapid-grid-pro': CustomElement;
|
|
12
|
+
'grid-pro-genesis-datasource': CustomElement;
|
|
13
|
+
'grid-pro-column': CustomElement;
|
|
14
|
+
'rapid-g2plot-chart': CustomElement;
|
|
15
|
+
'chart-datasource': CustomElement;
|
|
16
|
+
'client-app-login': CustomElement;
|
|
17
|
+
'rapid-layout': CustomElement;
|
|
18
|
+
'rapid-layout-region': CustomElement;
|
|
19
|
+
'rapid-layout-item': CustomElement;
|
|
20
|
+
'foundation-header': CustomElement;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
11
23
|
}
|
|
@@ -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;
|