@genesislcap/blank-app-seed 5.22.2-prerelease.2 → 5.23.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.
- package/.genx/configure.js +11 -1
- package/.genx/package.json +1 -1
- package/.genx/scripts/generate-test-apps.sh +124 -0
- package/.genx/templates/angular/chart.hbs +19 -7
- package/.genx/templates/angular/component/component.column.defs.hbs +16 -4
- package/.genx/templates/angular/component/component.create.form.hbs +10 -2
- package/.genx/templates/angular/component/component.events.config.hbs +31 -6
- package/.genx/templates/angular/component/component.filter.form.hbs +1 -2
- package/.genx/templates/angular/component/component.gridOptions.hbs +15 -3
- package/.genx/templates/angular/component/component.hbs +77 -46
- package/.genx/templates/angular/component/component.index.hbs +1 -1
- package/.genx/templates/angular/component/component.update.form.hbs +1 -1
- package/.genx/templates/angular/entityManager.hbs +6 -6
- package/{client-tmp/angular/src/app/utils/fdc3.ts → .genx/templates/angular/fdc3.ts.hbs} +6 -8
- package/.genx/templates/angular/form.hbs +9 -12
- package/.genx/templates/angular/grid.hbs +43 -40
- package/.genx/templates/angular/route.hbs +8 -2
- package/.genx/templates/angular/route.template.hbs +7 -7
- package/.genx/templates/angular/slices/eventing.slice.hbs +21 -10
- package/.genx/templates/angular/store.hbs +1 -5
- package/.genx/templates/angular/tabsPanel.hbs +2 -2
- package/.genx/templates/react/chart.hbs +6 -15
- package/.genx/templates/react/component/component.column.defs.hbs +16 -10
- package/.genx/templates/react/component/component.create.form.hbs +2 -2
- package/.genx/templates/react/component/component.events.config.hbs +32 -5
- package/.genx/templates/react/component/component.filter.form.hbs +1 -2
- package/.genx/templates/react/component/component.gridOptions.hbs +17 -11
- package/.genx/templates/react/component/component.hbs +84 -42
- package/.genx/templates/react/component/component.update.form.hbs +1 -1
- package/.genx/templates/react/entityManager.hbs +8 -16
- package/{client-tmp/react/src/utils/fdc3.ts → .genx/templates/react/fdc3.ts.hbs} +7 -8
- package/.genx/templates/react/form.hbs +1 -15
- package/.genx/templates/react/grid.hbs +11 -11
- package/.genx/templates/react/gridLayout.hbs +44 -4
- package/.genx/templates/react/horizontalLayout.hbs +10 -1
- package/.genx/templates/react/route.hbs +23 -16
- package/.genx/templates/react/slices/eventing.slice.hbs +19 -8
- package/.genx/templates/react/store.hbs +1 -5
- package/.genx/templates/react/tabsLayout.hbs +5 -1
- package/.genx/templates/web-components/chart.hbs +25 -25
- package/.genx/templates/web-components/component/component.column.defs.hbs +11 -3
- package/.genx/templates/web-components/component/component.create.form.hbs +11 -4
- package/.genx/templates/web-components/component/component.events.config.hbs +33 -6
- package/.genx/templates/web-components/component/component.filter.form.hbs +1 -2
- package/.genx/templates/web-components/component/component.gridOptions.hbs +12 -3
- package/.genx/templates/web-components/component/component.hbs +19 -20
- package/.genx/templates/web-components/component/component.index.hbs +1 -1
- package/.genx/templates/web-components/component/component.template.hbs +9 -13
- package/.genx/templates/web-components/component/component.update.form.hbs +1 -1
- package/.genx/templates/web-components/entityManager.hbs +92 -73
- package/{client-tmp/web-components/src/utils/fdc3.ts → .genx/templates/web-components/fdc3.ts.hbs} +6 -7
- package/.genx/templates/web-components/form.hbs +16 -15
- package/.genx/templates/web-components/grid.hbs +49 -41
- package/.genx/templates/web-components/gridLayout.hbs +32 -28
- package/.genx/templates/web-components/horizontalLayout.hbs +5 -5
- package/.genx/templates/web-components/route.template.hbs +4 -6
- package/.genx/templates/web-components/slices/eventing.slice.hbs +23 -15
- package/.genx/templates/web-components/store.hbs +1 -9
- package/.genx/templates/web-components/tabsLayout.hbs +5 -5
- package/.genx/tests/fixtures/routes-full.json +299 -0
- package/.genx/tests/fixtures/testapp/client/src/pages/Home/Home.tsx +12 -0
- package/.genx/utils/formatJSONValue.js +38 -2
- package/.genx/utils/formatRouteData.js +67 -18
- package/.genx/utils/generateTile.js +10 -1
- package/.genx/utils/gridSerializers.js +63 -23
- package/.genx/utils/registerPartials.js +15 -12
- package/.genx/utils/toJsStringLiteral.js +37 -0
- package/.genx/versions.json +3 -3
- package/.github/workflows/build.yml +22 -1
- package/.husky/pre-commit +8 -0
- package/CHANGELOG.md +97 -23
- package/bdd-tests/gradle/wrapper/gradle-wrapper.properties +1 -1
- package/bdd-tests/gradle.properties +0 -1
- package/client-tmp/angular/.oxfmtrc.json +32 -0
- package/client-tmp/angular/.oxlintrc.json +4 -0
- package/client-tmp/angular/README.md +4 -4
- package/client-tmp/angular/jest.config.js +1 -1
- package/client-tmp/angular/lint-css.js +24 -3
- package/client-tmp/angular/oxlint-staged.js +45 -0
- package/client-tmp/angular/package.json +19 -9
- package/client-tmp/angular/playwright.config.ts +12 -11
- package/client-tmp/angular/src/app/app.component.html +0 -1
- package/client-tmp/angular/src/app/app.component.ts +8 -9
- package/client-tmp/angular/src/app/app.config.ts +2 -2
- package/client-tmp/angular/src/app/app.module.ts +6 -5
- package/client-tmp/angular/src/app/components/error-message/error-message.component.html +29 -15
- package/client-tmp/angular/src/app/components/error-message/error-message.component.spec.ts +2 -2
- package/client-tmp/angular/src/app/components/error-message/error-message.component.ts +3 -5
- package/client-tmp/angular/src/app/directive/app-lazy-load.directive.ts +1 -0
- package/client-tmp/angular/src/app/guards/chained.guard.ts +19 -19
- package/client-tmp/angular/src/app/guards/connection.guard.ts +12 -12
- package/client-tmp/angular/src/app/layouts/blank/blank.layout.spec.ts +1 -1
- package/client-tmp/angular/src/app/layouts/blank/blank.layout.ts +1 -5
- package/client-tmp/angular/src/app/layouts/default/default.layout.html +3 -4
- package/client-tmp/angular/src/app/layouts/default/default.layout.spec.ts +4 -4
- package/client-tmp/angular/src/app/layouts/default/default.layout.ts +1 -1
- package/client-tmp/angular/src/app/pages/auth-login/auth-login.component.ts +1 -2
- package/client-tmp/angular/src/app/pages/not-permitted/not-permitted.component.html +3 -3
- package/client-tmp/angular/src/app/pages/not-permitted/not-permitted.component.scss +1 -1
- package/client-tmp/angular/src/app/pages/not-permitted/not-permitted.component.spec.ts +5 -5
- package/client-tmp/angular/src/app/pages/not-permitted/not-permitted.component.ts +3 -4
- package/client-tmp/angular/src/app/services/route.service.ts +79 -74
- package/client-tmp/angular/src/app/share/foundation-auth.ts +7 -1
- package/client-tmp/angular/src/app/share/genesis-components.ts +66 -68
- package/client-tmp/angular/src/app/utils/index.ts +3 -1
- package/client-tmp/angular/src/app/utils/permissions.ts +7 -7
- package/client-tmp/angular/src/declaration.d.ts +1 -1
- package/client-tmp/angular/src/environments/environment.ts +1 -1
- package/client-tmp/angular/src/jest.setup.ts +8 -0
- package/client-tmp/angular/src/main.ts +2 -2
- package/client-tmp/angular/src/pbc/container.ts +28 -26
- package/client-tmp/angular/src/pbc/elementsRenderer.ts +49 -39
- package/client-tmp/angular/src/pbc/utils.ts +61 -60
- package/client-tmp/angular/src/styles/_mixins.scss +7 -8
- package/client-tmp/angular/src/styles/styles.css +6 -6
- package/client-tmp/angular/test/e2e/fixture.ts +2 -2
- package/client-tmp/angular/test/e2e/flows/001-protected.e2e.ts +1 -1
- package/client-tmp/angular/tsconfig.app.json +2 -8
- package/client-tmp/angular/tsconfig.json +1 -4
- package/client-tmp/angular/tsconfig.spec.json +4 -11
- package/client-tmp/angular/webpack.dev.config.js +3 -4
- package/client-tmp/angular/webpack.prod.config.js +3 -4
- package/client-tmp/angular/webpack.shared.config.js +20 -24
- package/client-tmp/react/.oxfmtrc.json +30 -0
- package/client-tmp/react/.oxlintrc.json +4 -0
- package/client-tmp/react/README.md +4 -4
- package/client-tmp/react/jest.config.ts +8 -4
- package/client-tmp/react/jest.setup.ts +85 -1
- package/client-tmp/react/oxlint-staged.js +45 -0
- package/client-tmp/react/package.json +24 -9
- package/client-tmp/react/playwright.config.ts +11 -10
- package/client-tmp/react/src/App.tsx +27 -29
- package/client-tmp/react/src/__mocks__/fileMock.js +1 -0
- package/client-tmp/react/src/components/ErrorMessage/ErrorMessage.test.tsx +16 -4
- package/client-tmp/react/src/components/ErrorMessage/ErrorMessage.tsx +32 -29
- package/client-tmp/react/src/components/error-boundary/ErrorBoundary.tsx +15 -6
- package/client-tmp/react/src/components/routes/AppRoutes.tsx +1 -1
- package/client-tmp/react/src/components/single-component/registry.ts +4 -0
- package/client-tmp/react/src/custom-elements.d.ts +4 -2
- package/client-tmp/react/src/helpers/hasPermissionHelper.tsx +1 -1
- package/client-tmp/react/src/helpers/isAuthenticatedHelper.tsx +1 -1
- package/client-tmp/react/src/helpers/isConnectedHelper.tsx +3 -3
- package/client-tmp/react/src/layouts/blank/BlankLayout.tsx +7 -11
- package/client-tmp/react/src/layouts/default/DefaultLayout.tsx +8 -8
- package/client-tmp/react/src/main.tsx +11 -11
- package/client-tmp/react/src/pages/AuthPage/AuthPage.test.tsx +13 -2
- package/client-tmp/react/src/pages/AuthPage/AuthPage.tsx +14 -13
- package/client-tmp/react/src/pages/NotFoundPage/NotFoundPage.tsx +2 -7
- package/client-tmp/react/src/pages/NotPermittedPage/NotPermittedPage.test.tsx +8 -4
- package/client-tmp/react/src/pages/NotPermittedPage/NotPermittedPage.tsx +1 -1
- package/client-tmp/react/src/pbc/container.tsx +9 -4
- package/client-tmp/react/src/pbc/elementsRenderer.tsx +18 -9
- package/client-tmp/react/src/pbc/utils.ts +60 -59
- package/client-tmp/react/src/services/auth.service.ts +1 -1
- package/client-tmp/react/src/services/store.service.ts +5 -3
- package/client-tmp/react/src/share/foundation-login.ts +2 -2
- package/client-tmp/react/src/share/genesis-components.ts +46 -47
- package/client-tmp/react/src/store/AuthContext.tsx +2 -10
- package/client-tmp/react/src/store/RoutesContext.test.tsx +99 -0
- package/client-tmp/react/src/store/RoutesContext.tsx +25 -5
- package/client-tmp/react/src/styles/styles.css +7 -7
- package/client-tmp/react/src/types/LayoutName.ts +1 -1
- package/client-tmp/react/src/utils/getLayoutNameByRoute.ts +1 -1
- package/client-tmp/react/src/utils/index.ts +2 -0
- package/client-tmp/react/src/utils/layout.ts +8 -1
- package/client-tmp/react/src/utils/permissions.ts +7 -7
- package/client-tmp/react/src/utils/useDocumentTitle.ts +5 -6
- package/client-tmp/react/test/e2e/fixture.ts +5 -2
- package/client-tmp/react/test/e2e/flows/001-protected.e2e.ts +3 -1
- package/client-tmp/react/tsconfig.app.json +1 -1
- package/client-tmp/react/tsconfig.json +1 -5
- package/client-tmp/web-components/.oxfmtrc.json +30 -0
- package/client-tmp/web-components/.oxlintrc.json +4 -0
- package/client-tmp/web-components/oxlint-staged.js +45 -0
- package/client-tmp/web-components/package.json +14 -22
- package/client-tmp/web-components/src/components/components.ts +9 -7
- package/client-tmp/web-components/src/main/main.css +1 -2
- package/client-tmp/web-components/src/main/main.ts +1 -1
- package/client-tmp/web-components/src/routes/config.ts +4 -0
- package/client-tmp/web-components/src/utils/index.ts +2 -0
- package/client-tmp/web-components/tsconfig.json +1 -4
- package/gradle/wrapper/gradle-wrapper.properties +1 -1
- package/package.json +1 -1
- package/server/gradle/wrapper/gradle-wrapper.properties +1 -1
- package/server/gradle.properties +0 -2
- package/.genx/templates/angular/gridLayout.hbs +0 -30
- package/.genx/templates/angular/horizontalLayout.hbs +0 -7
- package/.genx/templates/angular/tabsLayout.hbs +0 -7
- package/.genx/tests/fixtures/testapp/client/src/routes/home/home.template.ts +0 -6
- package/client-tmp/react/.babelrc +0 -10
- package/client-tmp/react/.eslintrc.cjs +0 -21
- package/client-tmp/react/git +0 -0
- package/client-tmp/react/webpack.config.js +0 -121
- package/client-tmp/web-components/.prettierignore +0 -14
|
@@ -27,7 +27,8 @@ Run `npm run test:e2e` to execute the end-to-end tests.
|
|
|
27
27
|
|
|
28
28
|
## Linting
|
|
29
29
|
|
|
30
|
-
Run `npm run lint` to lint the project.
|
|
30
|
+
Run `npm run lint` to lint the project (Oxlint → Oxfmt → Stylelint via `genx lint -l ox`).
|
|
31
|
+
Run `npm run lint:fix` to auto-fix lint findings and formatting.
|
|
31
32
|
|
|
32
33
|
## Styling
|
|
33
34
|
|
|
@@ -52,9 +53,8 @@ modes, and the selected mode is remembered across reloads.
|
|
|
52
53
|
- `npm run dev:no-open`: Serves the project in development mode without automatically opening the browser.
|
|
53
54
|
- `npm run dev:intellij`: Serves the project in development mode (specific for IntelliJ).
|
|
54
55
|
- `npm run dev:https`: Serves the project in development mode with HTTPS.
|
|
55
|
-
- `npm run lint`: Lints the project
|
|
56
|
-
- `npm run lint:fix`: Fixes
|
|
57
|
-
- `npm run lint:eslint`: Lints the project using ESLint and the specified profile.
|
|
56
|
+
- `npm run lint`: Lints the project (Oxlint → Oxfmt → Stylelint).
|
|
57
|
+
- `npm run lint:fix`: Fixes lint findings and formatting.
|
|
58
58
|
- `npm run lint:stylelint`: Lints CSS using a custom script.
|
|
59
59
|
- `npm run test`: Runs unit tests.
|
|
60
60
|
- `npm run test:e2e`: Runs end-to-end tests.
|
|
@@ -4,12 +4,16 @@ const config: Config.InitialOptions = {
|
|
|
4
4
|
testEnvironment: 'jsdom',
|
|
5
5
|
moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx'],
|
|
6
6
|
transform: {
|
|
7
|
-
'^.+\\.jsx?$': 'babel-jest',
|
|
7
|
+
'^.+\\.jsx?$': ['babel-jest', { presets: ['@babel/preset-env'] }],
|
|
8
8
|
'^.+\\.tsx?$': ['ts-jest', { tsconfig: 'tsconfig.app.json' }],
|
|
9
9
|
},
|
|
10
|
+
moduleNameMapper: {
|
|
11
|
+
'\\.(css|jpg|jpeg|png|gif|svg|woff2?)$': '<rootDir>/src/__mocks__/fileMock.js',
|
|
12
|
+
},
|
|
13
|
+
transformIgnorePatterns: ['node_modules/(?!(@genesislcap/*|consola|@microsoft|exenv-es6|uuid))'],
|
|
10
14
|
setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
|
|
11
|
-
testMatch: [
|
|
12
|
-
watchPathIgnorePatterns: [
|
|
15
|
+
testMatch: ['**/?(*.)+(test).[jt]s?(x)'],
|
|
16
|
+
watchPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/dist/'],
|
|
13
17
|
};
|
|
14
18
|
|
|
15
|
-
export default config;
|
|
19
|
+
export default config;
|
|
@@ -1 +1,85 @@
|
|
|
1
|
-
import '
|
|
1
|
+
import { TextDecoder, TextEncoder } from 'node:util';
|
|
2
|
+
import '@testing-library/jest-dom';
|
|
3
|
+
|
|
4
|
+
// jsdom does not provide TextEncoder/TextDecoder, which react-router needs at import time.
|
|
5
|
+
if (typeof globalThis.TextEncoder === 'undefined') {
|
|
6
|
+
Object.assign(globalThis, { TextEncoder, TextDecoder });
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// Mock window.matchMedia (fast-foundation reads it at import time)
|
|
10
|
+
Object.defineProperty(window, 'matchMedia', {
|
|
11
|
+
writable: true,
|
|
12
|
+
value: (query: string) => ({
|
|
13
|
+
matches: false,
|
|
14
|
+
media: query,
|
|
15
|
+
onchange: null,
|
|
16
|
+
addListener: jest.fn(), // Deprecated
|
|
17
|
+
removeListener: jest.fn(), // Deprecated
|
|
18
|
+
addEventListener: jest.fn(),
|
|
19
|
+
removeEventListener: jest.fn(),
|
|
20
|
+
dispatchEvent: jest.fn(),
|
|
21
|
+
}),
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Mock BroadcastChannel
|
|
25
|
+
class MockBroadcastChannel {
|
|
26
|
+
name: string;
|
|
27
|
+
onmessage: ((this: BroadcastChannel, ev: MessageEvent) => any) | null = null;
|
|
28
|
+
onmessageerror: ((this: BroadcastChannel, ev: MessageEvent) => any) | null = null;
|
|
29
|
+
|
|
30
|
+
constructor(name: string) {
|
|
31
|
+
this.name = name;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
postMessage(message: any) {
|
|
35
|
+
if (this.onmessage) {
|
|
36
|
+
this.onmessage({ data: message } as MessageEvent);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
close() {}
|
|
41
|
+
|
|
42
|
+
addEventListener() {}
|
|
43
|
+
removeEventListener() {}
|
|
44
|
+
dispatchEvent() {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
Object.defineProperty(window, 'BroadcastChannel', {
|
|
50
|
+
writable: true,
|
|
51
|
+
value: MockBroadcastChannel,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// jsdom lacks the constructable-stylesheet API used by the modal-theme runtime
|
|
55
|
+
// (CSSStyleSheet.replaceSync + Document.adoptedStyleSheets)
|
|
56
|
+
if (typeof CSSStyleSheet === 'undefined') {
|
|
57
|
+
Object.defineProperty(window, 'CSSStyleSheet', {
|
|
58
|
+
writable: true,
|
|
59
|
+
value: class {
|
|
60
|
+
replaceSync() {}
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
} else if (!CSSStyleSheet.prototype.replaceSync) {
|
|
64
|
+
CSSStyleSheet.prototype.replaceSync = () => {};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!('adoptedStyleSheets' in document)) {
|
|
68
|
+
Object.defineProperty(document, 'adoptedStyleSheets', {
|
|
69
|
+
writable: true,
|
|
70
|
+
value: [],
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// jsdom lacks structuredClone, which the design-system theme merge uses
|
|
75
|
+
if (typeof globalThis.structuredClone === 'undefined') {
|
|
76
|
+
Object.defineProperty(globalThis, 'structuredClone', {
|
|
77
|
+
writable: true,
|
|
78
|
+
value: (value: unknown) => JSON.parse(JSON.stringify(value)),
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// jsdom's sandbox does not expose Node's global fetch; foundation-auth references it at import time.
|
|
83
|
+
if (typeof globalThis.fetch === 'undefined') {
|
|
84
|
+
Object.defineProperty(globalThis, 'fetch', { writable: true, value: jest.fn() });
|
|
85
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lints the staged files, fixing what can be fixed and failing on what cannot.
|
|
3
|
+
*
|
|
4
|
+
* `oxlint --fix` is not single-pass convergent: it applies at most one fix per
|
|
5
|
+
* overlapping span, so a file with several unused specifiers in one import
|
|
6
|
+
* statement still reports the rest afterwards. A single
|
|
7
|
+
* `oxlint --fix --deny-warnings` would therefore reject a commit whose findings
|
|
8
|
+
* are entirely auto-fixable, and lint-staged would revert the partial fix. There
|
|
9
|
+
* is no `--fix-passes` flag (oxlint 1.78), so the loop lives here; it can go
|
|
10
|
+
* back to one plain call once oxlint converges on its own.
|
|
11
|
+
*
|
|
12
|
+
* The fixing passes stay quiet so a remaining finding is reported once, by the
|
|
13
|
+
* final pass, rather than once per attempt.
|
|
14
|
+
*/
|
|
15
|
+
const { spawnSync } = require('node:child_process');
|
|
16
|
+
|
|
17
|
+
/** Convergence needs about log2(findings) passes; this is well clear of that. */
|
|
18
|
+
const MAX_PASSES = 10;
|
|
19
|
+
|
|
20
|
+
const files = process.argv.slice(2);
|
|
21
|
+
|
|
22
|
+
const runOxlint = (args, quiet) =>
|
|
23
|
+
spawnSync('oxlint', [...args, ...files], {
|
|
24
|
+
stdio: quiet ? 'ignore' : 'inherit',
|
|
25
|
+
shell: process.platform === 'win32',
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
if (files.length === 0) {
|
|
29
|
+
process.exit(0);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
for (let pass = 0; pass < MAX_PASSES; pass += 1) {
|
|
33
|
+
const { status, error } = runOxlint(['--fix', '--deny-warnings'], true);
|
|
34
|
+
if (error) {
|
|
35
|
+
// Never fail silently: a missing binary must not look like a lint failure.
|
|
36
|
+
console.error(`oxlint-staged: could not run oxlint (${error.code})`);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
if (status === 0) {
|
|
40
|
+
process.exit(0);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Still not clean: report what is left (without touching the files again) and fail.
|
|
45
|
+
process.exit(runOxlint(['--deny-warnings'], false).status === 0 ? 0 : 1);
|
|
@@ -28,11 +28,10 @@
|
|
|
28
28
|
"dev:no-open": "NO_OPEN=true npm run dev",
|
|
29
29
|
"dev:intellij": "npm run dev",
|
|
30
30
|
"dev:https": "HTTPS=true npm run dev",
|
|
31
|
-
"
|
|
32
|
-
"lint
|
|
33
|
-
"lint:
|
|
31
|
+
"git:setup": "cd .. && npx --no --prefix client husky install",
|
|
32
|
+
"lint": "genx lint -l ox",
|
|
33
|
+
"lint:fix": "genx lint -l ox --fix",
|
|
34
34
|
"lint:stylelint": "genx lint -l stylelint",
|
|
35
|
-
"stats": "webpack --mode production --json > stats.json",
|
|
36
35
|
"test": "jest",
|
|
37
36
|
"test:coverage": "jest --coverage",
|
|
38
37
|
"test:unit:watch": "jest --watchAll",
|
|
@@ -40,7 +39,18 @@
|
|
|
40
39
|
"test:e2e:debug": "genx test --e2e --debug",
|
|
41
40
|
"test:e2e:ui": "genx test --e2e --interactive"
|
|
42
41
|
},
|
|
43
|
-
"
|
|
42
|
+
"lint-staged": {
|
|
43
|
+
"*.{ts,js,tsx,jsx}": [
|
|
44
|
+
"node oxlint-staged.js",
|
|
45
|
+
"oxfmt --write"
|
|
46
|
+
],
|
|
47
|
+
"*.{mjs,cjs}": [
|
|
48
|
+
"oxfmt --write"
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
"stylelint": {
|
|
52
|
+
"extends": "@genesislcap/stylelint-config"
|
|
53
|
+
},
|
|
44
54
|
"dependencies": {
|
|
45
55
|
"@microsoft/fast-react-wrapper": ">=0.3.25",
|
|
46
56
|
"ag-grid-community": "36.0.0",
|
|
@@ -60,6 +70,7 @@
|
|
|
60
70
|
"@genesislcap/foundation-notifications": "{{versions.UI}}",
|
|
61
71
|
"@genesislcap/foundation-react-utils": "{{versions.UI}}",
|
|
62
72
|
"@genesislcap/foundation-shell": "{{versions.UI}}",
|
|
73
|
+
"@genesislcap/foundation-store": "{{versions.UI}}",
|
|
63
74
|
"@genesislcap/foundation-ui": "{{versions.UI}}",
|
|
64
75
|
"@genesislcap/foundation-user": "{{versions.UI}}",
|
|
65
76
|
"@genesislcap/foundation-utils": "{{versions.UI}}",
|
|
@@ -91,13 +102,15 @@
|
|
|
91
102
|
"@analytics/core": "0.12.17"
|
|
92
103
|
},
|
|
93
104
|
"devDependencies": {
|
|
105
|
+
"@babel/core": "^7.24.0",
|
|
106
|
+
"@babel/preset-env": "^7.24.0",
|
|
94
107
|
"@genesislcap/design-system-configurator": "{{versions.UI}}",
|
|
95
|
-
"@genesislcap/eslint-config": "{{versions.UI}}",
|
|
96
|
-
"@genesislcap/prettier-config": "{{versions.UI}}",
|
|
97
108
|
"@genesislcap/foundation-testing": "{{versions.UI}}",
|
|
98
109
|
"@genesislcap/genx": "{{versions.UI}}",
|
|
99
110
|
"@genesislcap/event-type-codegen": "{{versions.UI}}",
|
|
100
111
|
"@genesislcap/build-kit": "{{versions.UI}}",
|
|
112
|
+
"@genesislcap/oxlint-config": "{{versions.UI}}",
|
|
113
|
+
"@genesislcap/stylelint-config": "{{versions.UI}}",
|
|
101
114
|
"@testing-library/dom": "^10.4.0",
|
|
102
115
|
"@testing-library/jest-dom": "^6.5.0",
|
|
103
116
|
"@testing-library/react": "^16.1.0",
|
|
@@ -106,10 +119,12 @@
|
|
|
106
119
|
"@types/node": "^20.14.10",
|
|
107
120
|
"@types/react": "^19.2.0",
|
|
108
121
|
"@types/react-dom": "^19.2.0",
|
|
109
|
-
"
|
|
110
|
-
"eslint-plugin-react-refresh": "^0.4.16",
|
|
122
|
+
"husky": "^7.0.4",
|
|
111
123
|
"jest": "^29.7.0",
|
|
112
124
|
"jest-environment-jsdom": "^29.7.0",
|
|
125
|
+
"lint-staged": "^12.4.1",
|
|
126
|
+
"oxfmt": "^0.44.0",
|
|
127
|
+
"oxlint": "^1.77.0",
|
|
113
128
|
"ts-jest": "^29.2.5",
|
|
114
129
|
"ts-node": "^10.9.2",
|
|
115
130
|
"typescript": "5.9.2"
|
|
@@ -2,16 +2,17 @@ import { configDefaults } from '@genesislcap/foundation-testing/e2e';
|
|
|
2
2
|
|
|
3
3
|
export const PROTOCOL = process.env['PROTOCOL'] || 'http';
|
|
4
4
|
export const HOST = process.env['HOST'] || 'localhost';
|
|
5
|
+
// oxlint-disable-next-line no-magic-numbers -- 5173 is the standard Vite dev server port
|
|
5
6
|
export const PORT: number = Number(process.env['PORT']) || 5173;
|
|
6
7
|
|
|
7
8
|
export default {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
};
|
|
9
|
+
...configDefaults,
|
|
10
|
+
webServer: {
|
|
11
|
+
...configDefaults.webServer,
|
|
12
|
+
url: `${PROTOCOL}://${HOST}:${PORT}`,
|
|
13
|
+
},
|
|
14
|
+
use: {
|
|
15
|
+
...configDefaults.use,
|
|
16
|
+
baseURL: `${PROTOCOL}://${HOST}:${PORT}`,
|
|
17
|
+
},
|
|
18
|
+
};
|
|
@@ -1,39 +1,41 @@
|
|
|
1
1
|
import { useCallback, useEffect, useState } from 'react';
|
|
2
|
+
import { Provider } from 'react-redux';
|
|
2
3
|
import { BrowserRouter as Router } from 'react-router-dom';
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
listenToChannel,
|
|
6
|
-
onFDC3Ready,
|
|
7
|
-
} from './utils';
|
|
8
|
-
{{/if}}
|
|
4
|
+
import AppRoutes from './components/routes/AppRoutes';
|
|
9
5
|
import { customEventFactory, registerStylesTarget } from './pbc/utils';
|
|
10
|
-
import { RoutesProvider } from './store/RoutesContext';
|
|
11
|
-
import { registerComponents as genesisRegisterComponents } from './share/genesis-components';
|
|
12
6
|
import { storeService } from './services/store.service';
|
|
13
|
-
import
|
|
7
|
+
import { registerComponents as genesisRegisterComponents } from './share/genesis-components';
|
|
8
|
+
import { RoutesProvider } from './store/RoutesContext';
|
|
14
9
|
import { reduxStore } from './store/store';
|
|
15
|
-
|
|
10
|
+
{{#if FDC3.channels.length~}}
|
|
11
|
+
import { listenToChannel, onFDC3Ready } from './utils';
|
|
12
|
+
{{/if}}
|
|
16
13
|
|
|
17
14
|
interface AppProps {
|
|
18
15
|
rootElement: HTMLElement;
|
|
19
16
|
}
|
|
20
17
|
|
|
21
18
|
const App: React.FC<AppProps> = ({ rootElement }) => {
|
|
22
|
-
{{#if FDC3.channels.length
|
|
23
|
-
|
|
19
|
+
{{#if FDC3.channels.length}}
|
|
20
|
+
// Memoized so the handler keeps a stable identity and the effect below registers the
|
|
21
|
+
// channel listeners once instead of on every render.
|
|
22
|
+
const FDC3ReadyHandler = useCallback(() => {
|
|
24
23
|
{{#each FDC3.channels}}
|
|
25
24
|
listenToChannel('{{this.name}}', '{{this.type}}', (result) => {
|
|
26
|
-
console.log('Received FDC3
|
|
25
|
+
console.log('Received FDC3 message on {{this.name}} ({{this.type}})', result);
|
|
27
26
|
// TODO: Add your listener logic here
|
|
28
27
|
// E.g. open a modal or route to specific page: Route.path.push(`[Route name]`);
|
|
29
28
|
});
|
|
30
29
|
{{/each}}
|
|
31
|
-
};
|
|
30
|
+
}, []);
|
|
32
31
|
{{/if}}
|
|
33
32
|
const [componentsReady, setComponentsReady] = useState(false);
|
|
34
|
-
const dispatchCustomEvent = useCallback(
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
const dispatchCustomEvent = useCallback(
|
|
34
|
+
(type: string, detail?: unknown) => {
|
|
35
|
+
rootElement.dispatchEvent(customEventFactory(type, detail));
|
|
36
|
+
},
|
|
37
|
+
[rootElement],
|
|
38
|
+
);
|
|
37
39
|
|
|
38
40
|
const handleStoreConnected = useCallback((event: CustomEvent) => {
|
|
39
41
|
storeService.onConnected(event);
|
|
@@ -56,18 +58,14 @@ const App: React.FC<AppProps> = ({ rootElement }) => {
|
|
|
56
58
|
rootElement.addEventListener('store-connected', handleStoreConnected as EventListener);
|
|
57
59
|
dispatchCustomEvent('store-connected', rootElement);
|
|
58
60
|
dispatchCustomEvent('store-ready', true);
|
|
59
|
-
|
|
60
|
-
return () => {
|
|
61
|
-
rootElement.removeEventListener(
|
|
62
|
-
'store-connected',
|
|
63
|
-
handleStoreConnected as EventListener,
|
|
64
|
-
);
|
|
65
|
-
};
|
|
66
|
-
{{#if FDC3.channels.length~}}
|
|
61
|
+
{{#if FDC3.channels.length}}
|
|
67
62
|
onFDC3Ready(FDC3ReadyHandler);
|
|
68
63
|
{{/if}}
|
|
69
64
|
|
|
70
|
-
|
|
65
|
+
return () => {
|
|
66
|
+
rootElement.removeEventListener('store-connected', handleStoreConnected as EventListener);
|
|
67
|
+
};
|
|
68
|
+
}, [rootElement, handleStoreConnected, dispatchCustomEvent{{#if FDC3.channels.length}}, FDC3ReadyHandler{{/if}}]);
|
|
71
69
|
|
|
72
70
|
const baseElement = document.querySelector('base');
|
|
73
71
|
const basePath = baseElement?.getAttribute('href') || '';
|
|
@@ -79,9 +77,9 @@ const App: React.FC<AppProps> = ({ rootElement }) => {
|
|
|
79
77
|
return (
|
|
80
78
|
<Provider store={reduxStore}>
|
|
81
79
|
<RoutesProvider>
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
80
|
+
<Router basename={basePath}>
|
|
81
|
+
<AppRoutes />
|
|
82
|
+
</Router>
|
|
85
83
|
</RoutesProvider>
|
|
86
84
|
</Provider>
|
|
87
85
|
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = {};
|
|
@@ -42,7 +42,7 @@ describe('ErrorMessage Component', () => {
|
|
|
42
42
|
render(<ErrorMessage message={message} />);
|
|
43
43
|
const displayedMessage: HTMLElement = screen.getByText(message);
|
|
44
44
|
const messageWrapper: HTMLElement | null = displayedMessage.parentElement;
|
|
45
|
-
|
|
45
|
+
|
|
46
46
|
expect(messageWrapper).toBeInTheDocument();
|
|
47
47
|
expect(messageWrapper).toHaveStyle(`
|
|
48
48
|
color: var(--neutral-foreground-rest);
|
|
@@ -67,9 +67,21 @@ describe('ErrorMessage Component', () => {
|
|
|
67
67
|
});
|
|
68
68
|
|
|
69
69
|
test('renders the correct element type for various elementType props', () => {
|
|
70
|
-
const elementTypes: ErrorMessageProps['elementType'][] = [
|
|
70
|
+
const elementTypes: ErrorMessageProps['elementType'][] = [
|
|
71
|
+
'h1',
|
|
72
|
+
'h2',
|
|
73
|
+
'h3',
|
|
74
|
+
'h4',
|
|
75
|
+
'h5',
|
|
76
|
+
'h6',
|
|
77
|
+
'p',
|
|
78
|
+
'span',
|
|
79
|
+
'div',
|
|
80
|
+
];
|
|
71
81
|
elementTypes.forEach((elementType: ErrorMessageProps['elementType']) => {
|
|
72
|
-
const { container }: { container: HTMLElement } = render(
|
|
82
|
+
const { container }: { container: HTMLElement } = render(
|
|
83
|
+
<ErrorMessage message={message} elementType={elementType} />,
|
|
84
|
+
);
|
|
73
85
|
const displayedMessage: HTMLElement | null = container.querySelector(elementType as string);
|
|
74
86
|
expect(displayedMessage).toBeInTheDocument();
|
|
75
87
|
expect(displayedMessage?.tagName).toBe((elementType as string).toUpperCase());
|
|
@@ -92,4 +104,4 @@ describe('ErrorMessage Component', () => {
|
|
|
92
104
|
const { container }: { container: HTMLElement } = render(<ErrorMessage message={undefined} />);
|
|
93
105
|
expect(container.firstChild).toBeNull();
|
|
94
106
|
});
|
|
95
|
-
});
|
|
107
|
+
});
|
|
@@ -22,7 +22,7 @@ const styles = {
|
|
|
22
22
|
width: 'fit-content',
|
|
23
23
|
alignSelf: 'center',
|
|
24
24
|
height: 'auto',
|
|
25
|
-
maxHeight: '100%'
|
|
25
|
+
maxHeight: '100%',
|
|
26
26
|
},
|
|
27
27
|
};
|
|
28
28
|
|
|
@@ -34,34 +34,37 @@ export interface ErrorMessageProps {
|
|
|
34
34
|
const ErrorMessage: React.FC<ErrorMessageProps> = ({ elementType = 'div', message = '' }) => {
|
|
35
35
|
const ElementType = elementType;
|
|
36
36
|
|
|
37
|
-
return
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
37
|
+
return (
|
|
38
|
+
message &&
|
|
39
|
+
message !== '' && (
|
|
40
|
+
<section style={styles.errorMessageWrapper}>
|
|
41
|
+
<div style={styles.errorMessage}>
|
|
42
|
+
{(() => {
|
|
43
|
+
switch (ElementType) {
|
|
44
|
+
case 'h1':
|
|
45
|
+
return <h1>{message}</h1>;
|
|
46
|
+
case 'h2':
|
|
47
|
+
return <h2>{message}</h2>;
|
|
48
|
+
case 'h3':
|
|
49
|
+
return <h3>{message}</h3>;
|
|
50
|
+
case 'h4':
|
|
51
|
+
return <h4>{message}</h4>;
|
|
52
|
+
case 'h5':
|
|
53
|
+
return <h5>{message}</h5>;
|
|
54
|
+
case 'h6':
|
|
55
|
+
return <h6>{message}</h6>;
|
|
56
|
+
case 'p':
|
|
57
|
+
return <p>{message}</p>;
|
|
58
|
+
case 'span':
|
|
59
|
+
return <span>{message}</span>;
|
|
60
|
+
default:
|
|
61
|
+
return <div>{message}</div>;
|
|
62
|
+
}
|
|
63
|
+
})()}
|
|
64
|
+
</div>
|
|
65
|
+
</section>
|
|
66
|
+
)
|
|
64
67
|
);
|
|
65
68
|
};
|
|
66
69
|
|
|
67
|
-
export default ErrorMessage;
|
|
70
|
+
export default ErrorMessage;
|
|
@@ -27,6 +27,9 @@ type BaseErrorBoundaryState = {
|
|
|
27
27
|
referenceId: string;
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
+
/** Cap on the ring buffer of error reports exposed to genesis-telemetry.js. */
|
|
31
|
+
const MAX_ERROR_BOUNDARY_REPORTS = 20;
|
|
32
|
+
|
|
30
33
|
const initialBoundaryState: BaseErrorBoundaryState = {
|
|
31
34
|
hasError: false,
|
|
32
35
|
error: null,
|
|
@@ -53,6 +56,7 @@ const toError = (value: unknown): Error => {
|
|
|
53
56
|
|
|
54
57
|
const createReferenceId = (): string => {
|
|
55
58
|
const timestamp = new Date().toISOString().split(':').join('-');
|
|
59
|
+
// oxlint-disable-next-line no-magic-numbers -- base-36 encoding with 6-char slice is a well-known ID generation pattern
|
|
56
60
|
const random = Math.random().toString(36).slice(2, 8).toUpperCase();
|
|
57
61
|
return `APP-${timestamp}-${random}`;
|
|
58
62
|
};
|
|
@@ -68,6 +72,8 @@ const ErrorBoundaryFallback: React.FC<ErrorBoundaryFallbackProps> = ({
|
|
|
68
72
|
const [copied, setCopied] = useState(false);
|
|
69
73
|
const [copyHelpVisible, setCopyHelpVisible] = useState(false);
|
|
70
74
|
|
|
75
|
+
const COPY_RESET_DELAY_MS = 2_000;
|
|
76
|
+
|
|
71
77
|
const handleCopy = async () => {
|
|
72
78
|
try {
|
|
73
79
|
await navigator.clipboard.writeText(details);
|
|
@@ -75,7 +81,7 @@ const ErrorBoundaryFallback: React.FC<ErrorBoundaryFallbackProps> = ({
|
|
|
75
81
|
setCopyHelpVisible(false);
|
|
76
82
|
window.setTimeout(() => {
|
|
77
83
|
setCopied(false);
|
|
78
|
-
},
|
|
84
|
+
}, COPY_RESET_DELAY_MS);
|
|
79
85
|
} catch {
|
|
80
86
|
setCopyHelpVisible(true);
|
|
81
87
|
}
|
|
@@ -155,8 +161,13 @@ class BaseErrorBoundary extends React.Component<BaseErrorBoundaryProps, BaseErro
|
|
|
155
161
|
|
|
156
162
|
// Expose to genesis-telemetry.js so the UI Builder agent can read it via get_preview_diagnostics
|
|
157
163
|
const reports: unknown[] = ((window as any).__GENESIS_ERROR_BOUNDARY_REPORTS__ ??= []);
|
|
158
|
-
reports.push({
|
|
159
|
-
|
|
164
|
+
reports.push({
|
|
165
|
+
message: normalized.message,
|
|
166
|
+
stack: normalized.stack ?? null,
|
|
167
|
+
componentStack: errorInfo.componentStack ?? null,
|
|
168
|
+
ts: Date.now(),
|
|
169
|
+
});
|
|
170
|
+
if (reports.length > MAX_ERROR_BOUNDARY_REPORTS) reports.shift();
|
|
160
171
|
}
|
|
161
172
|
|
|
162
173
|
private readonly handleRetry = (): void => {
|
|
@@ -186,9 +197,7 @@ class BaseErrorBoundary extends React.Component<BaseErrorBoundaryProps, BaseErro
|
|
|
186
197
|
].join('\n');
|
|
187
198
|
|
|
188
199
|
const fallbackTitle =
|
|
189
|
-
scope === 'application'
|
|
190
|
-
? 'Something went wrong'
|
|
191
|
-
: `Something went wrong in "${title}"`;
|
|
200
|
+
scope === 'application' ? 'Something went wrong' : `Something went wrong in "${title}"`;
|
|
192
201
|
const fallbackSubtitle =
|
|
193
202
|
scope === 'application'
|
|
194
203
|
? 'The app hit an unexpected error. You can retry or copy diagnostics for a fast fix.'
|
|
@@ -2,10 +2,10 @@ import { renderAppRoutes } from '@genesislcap/foundation-react-utils/router';
|
|
|
2
2
|
import DefaultLayout from '../../layouts/default/DefaultLayout';
|
|
3
3
|
import NotFoundPage from '../../pages/NotFoundPage/NotFoundPage.tsx';
|
|
4
4
|
import { useRoutesContext } from '../../store/RoutesContext';
|
|
5
|
-
import ProtectedRoute from './ProtectedRoute';
|
|
6
5
|
{{#if routes.[0]}}
|
|
7
6
|
import SingleComponent, { initialComponentName } from '../single-component/SingleComponent';
|
|
8
7
|
{{/if}}
|
|
8
|
+
import ProtectedRoute from './ProtectedRoute';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Builds the app's `<Routes>` from the declarative route table (see RoutesContext)
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { createComponentRegistry } from '@genesislcap/foundation-react-utils/router';
|
|
2
|
+
{{#if routes.[0]}}
|
|
3
|
+
/* eslint-disable import-es/order -- generated route pages follow route-table order, not alphabetical */
|
|
2
4
|
{{#each routes}}
|
|
3
5
|
import {{pascalCase this.name}} from '../../pages/{{pascalCase this.name}}/{{pascalCase this.name}}';
|
|
4
6
|
{{/each}}
|
|
7
|
+
/* eslint-enable import-es/order */
|
|
8
|
+
{{/if}}
|
|
5
9
|
|
|
6
10
|
/**
|
|
7
11
|
* Registry of components that can be rendered standalone via the
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import React, { DOMAttributes } from 'react';
|
|
2
2
|
|
|
3
|
-
type CustomElement<T = React.HTMLAttributes<HTMLElement>> = Partial<
|
|
3
|
+
type CustomElement<T = React.HTMLAttributes<HTMLElement>> = Partial<
|
|
4
|
+
T & DOMAttributes<T> & { [key: string]: any }
|
|
5
|
+
>;
|
|
4
6
|
|
|
5
|
-
declare module
|
|
7
|
+
declare module 'react/jsx-runtime' {
|
|
6
8
|
namespace JSX {
|
|
7
9
|
interface IntrinsicElements {
|
|
8
10
|
'rapid-design-system-provider': CustomElement;
|
|
@@ -5,12 +5,12 @@ const isConnectedHelper = (): Promise<boolean> => {
|
|
|
5
5
|
const hostUrl = sessionStorage.getItem('hostUrl');
|
|
6
6
|
|
|
7
7
|
if (connect.isConnected) {
|
|
8
|
-
return
|
|
8
|
+
return Promise.resolve(true);
|
|
9
9
|
}
|
|
10
10
|
if (!hostUrl) {
|
|
11
|
-
return
|
|
11
|
+
return Promise.resolve(false);
|
|
12
12
|
}
|
|
13
13
|
return connect.connect(hostUrl);
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
export default isConnectedHelper;
|
|
16
|
+
export default isConnectedHelper;
|