@genesislcap/blank-app-seed 5.22.1 → 5.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +21 -14
- 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/.github/workflows/build.yml +22 -1
- package/.github/workflows/release.yaml +96 -0
- package/.husky/pre-commit +8 -0
- package/.releaserc +1 -1
- package/CHANGELOG.md +23 -0
- 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 +13 -7
- 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/package.json +1 -1
- 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/.github/workflows/release.yml +0 -50
- 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
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import ReactDOM from 'react-dom/client'
|
|
3
|
-
import App from './App.tsx'
|
|
4
|
-
import { AppErrorBoundary } from './components/error-boundary/ErrorBoundary'
|
|
5
|
-
|
|
6
|
-
import { registerPBCs } from './pbc/utils';
|
|
7
1
|
import { createLogger } from '@genesislcap/foundation-logger';
|
|
8
2
|
import { installRapidFlexLayoutReactStyles } from '@genesislcap/rapid-design-system';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import ReactDOM from 'react-dom/client';
|
|
5
|
+
import App from './App.tsx';
|
|
6
|
+
import { AppErrorBoundary } from './components/error-boundary/ErrorBoundary';
|
|
7
|
+
|
|
8
|
+
import { registerPBCs } from './pbc/utils';
|
|
9
9
|
|
|
10
|
-
import './styles/styles.css'
|
|
10
|
+
import './styles/styles.css';
|
|
11
11
|
|
|
12
12
|
// Single source of truth for the flexlayout-react theme lives in the platform (@genesislcap/rapid-design-system).
|
|
13
13
|
installRapidFlexLayoutReactStyles();
|
|
@@ -23,11 +23,11 @@ function bootstrapApp() {
|
|
|
23
23
|
<App rootElement={rootEelement} />
|
|
24
24
|
</AppErrorBoundary>
|
|
25
25
|
</React.StrictMode>,
|
|
26
|
-
)
|
|
26
|
+
);
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
registerPBCs()
|
|
31
|
-
.then(hasAssets => logger.debug(hasAssets ? 'PBCs registered' : 'No PBCs detected'))
|
|
32
|
-
.catch((err) => logger.error(err))
|
|
33
|
-
.finally(bootstrapApp)
|
|
31
|
+
.then((hasAssets) => logger.debug(hasAssets ? 'PBCs registered' : 'No PBCs detected'))
|
|
32
|
+
.catch((err) => logger.error(err))
|
|
33
|
+
.finally(bootstrapApp);
|
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
import { render } from '@testing-library/react';
|
|
2
|
+
import { MemoryRouter } from 'react-router-dom';
|
|
2
3
|
import AuthPage from './AuthPage';
|
|
3
4
|
|
|
5
|
+
// The login module pulls in the whole foundation-auth runtime (design-system registration,
|
|
6
|
+
// fast-router); this test only asserts the page shell renders.
|
|
7
|
+
jest.mock('../../share/foundation-login.ts', () => ({
|
|
8
|
+
configureFoundationLogin: jest.fn(),
|
|
9
|
+
}));
|
|
10
|
+
|
|
4
11
|
test('renders AuthPage component', () => {
|
|
5
|
-
const { container } = render(
|
|
12
|
+
const { container } = render(
|
|
13
|
+
<MemoryRouter>
|
|
14
|
+
<AuthPage />
|
|
15
|
+
</MemoryRouter>,
|
|
16
|
+
);
|
|
6
17
|
const authPageElement: Element | null = container.querySelector('.auth-page');
|
|
7
18
|
expect(authPageElement).toBeInTheDocument();
|
|
8
19
|
const clientAppLoginElement: Element | null = container.querySelector('client-app-login');
|
|
9
20
|
expect(clientAppLoginElement).toBeInTheDocument();
|
|
10
|
-
});
|
|
21
|
+
});
|
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
import React, {useEffect} from 'react';
|
|
2
|
-
import './AuthPage.css';
|
|
3
|
-
import { configureFoundationLogin } from '../../share/foundation-login.ts';
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
4
2
|
import { useNavigate, useLocation } from 'react-router-dom';
|
|
3
|
+
import { configureFoundationLogin } from '../../share/foundation-login.ts';
|
|
4
|
+
import './AuthPage.css';
|
|
5
5
|
|
|
6
6
|
const AuthPage: React.FC = () => {
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
const navigate = useNavigate();
|
|
8
|
+
const location = useLocation();
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
configureFoundationLogin({ navigate, location });
|
|
12
|
+
// oxlint-disable-next-line react-hooks/exhaustive-deps -- run once on mount; re-subscribing on every navigation would re-initialise login
|
|
13
|
+
}, []);
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
return (
|
|
16
|
+
<section className="auth-page">
|
|
17
|
+
<client-app-login></client-app-login>
|
|
18
|
+
</section>
|
|
19
|
+
);
|
|
19
20
|
};
|
|
20
21
|
|
|
21
22
|
export default AuthPage;
|
|
@@ -3,12 +3,7 @@ import ErrorMessage from '../../components/ErrorMessage/ErrorMessage';
|
|
|
3
3
|
import './NotFoundPage.css';
|
|
4
4
|
|
|
5
5
|
const NotFoundPage: React.FC = () => {
|
|
6
|
-
return
|
|
7
|
-
<ErrorMessage
|
|
8
|
-
elementType="h1"
|
|
9
|
-
message="Page Not Found 404"
|
|
10
|
-
/>
|
|
11
|
-
);
|
|
6
|
+
return <ErrorMessage elementType="h1" message="Page Not Found 404" />;
|
|
12
7
|
};
|
|
13
8
|
|
|
14
|
-
export default NotFoundPage;
|
|
9
|
+
export default NotFoundPage;
|
|
@@ -2,16 +2,20 @@ import { render, screen } from '@testing-library/react';
|
|
|
2
2
|
import NotPermittedPage from './NotPermittedPage';
|
|
3
3
|
|
|
4
4
|
jest.mock('../../components/ErrorMessage/ErrorMessage', () => {
|
|
5
|
-
return jest.fn((props: { message: string }) =>
|
|
5
|
+
return jest.fn((props: { message: string }) => (
|
|
6
|
+
<h1 data-testid="error-message">{props.message}</h1>
|
|
7
|
+
));
|
|
6
8
|
});
|
|
7
9
|
|
|
8
10
|
describe('NotPermittedPage Component', () => {
|
|
9
11
|
test('renders the ErrorMessage component with correct props', () => {
|
|
10
12
|
render(<NotPermittedPage />);
|
|
11
|
-
|
|
13
|
+
|
|
12
14
|
const errorMessage: HTMLElement = screen.getByTestId('error-message');
|
|
13
15
|
expect(errorMessage).toBeInTheDocument();
|
|
14
16
|
expect(errorMessage.tagName).toBe('H1');
|
|
15
|
-
expect(errorMessage).toHaveTextContent(
|
|
17
|
+
expect(errorMessage).toHaveTextContent(
|
|
18
|
+
'You do not have permission to access this part of the application, please contact your administrator.',
|
|
19
|
+
);
|
|
16
20
|
});
|
|
17
|
-
});
|
|
21
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useEffect, useRef } from 'react';
|
|
2
|
-
import { deriveElementTag } from './utils';
|
|
3
|
-
import { useRoutesContext } from '../store/RoutesContext';
|
|
4
2
|
import { useLocation, RouteObject } from 'react-router-dom';
|
|
3
|
+
import { useRoutesContext } from '../store/RoutesContext';
|
|
4
|
+
import { deriveElementTag } from './utils';
|
|
5
5
|
|
|
6
6
|
type ExtendedRouteObject = RouteObject & {
|
|
7
7
|
data?: {
|
|
@@ -9,7 +9,7 @@ type ExtendedRouteObject = RouteObject & {
|
|
|
9
9
|
pbcElement?: any;
|
|
10
10
|
};
|
|
11
11
|
path: string;
|
|
12
|
-
}
|
|
12
|
+
};
|
|
13
13
|
|
|
14
14
|
const PBCContainer: React.FC = () => {
|
|
15
15
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
@@ -36,9 +36,14 @@ const PBCContainer: React.FC = () => {
|
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
loadElement();
|
|
39
|
+
// `routes` comes from a memoized context value (see RoutesContext) so its identity is
|
|
40
|
+
// stable; an unstable one would re-run this effect and remount the PBC custom element
|
|
41
|
+
// on every re-render of the provider.
|
|
39
42
|
}, [location.pathname, routes]);
|
|
40
43
|
|
|
41
|
-
return
|
|
44
|
+
return (
|
|
45
|
+
<div ref={containerRef} className="container" style=\{{ width: '100%', height: '100%' }}></div>
|
|
46
|
+
);
|
|
42
47
|
};
|
|
43
48
|
|
|
44
49
|
export default PBCContainer;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Connect } from '@genesislcap/foundation-comms';
|
|
2
2
|
import { AppElementPredicate, AppTargetId } from '@genesislcap/foundation-shell/app';
|
|
3
|
-
import { customEventFactory, getTargetElements } from './utils';
|
|
4
3
|
import { DI } from '@genesislcap/web-core';
|
|
5
|
-
import {
|
|
4
|
+
import { useEffect, useRef, useState } from 'react';
|
|
5
|
+
import { customEventFactory, getTargetElements } from './utils';
|
|
6
6
|
|
|
7
7
|
const ALWAYS_TRUE_PREDICATE: AppElementPredicate = () => true;
|
|
8
8
|
|
|
@@ -15,15 +15,21 @@ interface PBCContainerElement extends HTMLDivElement {
|
|
|
15
15
|
$emit: (type: string, detail: any) => void;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
const PBCElementsRenderer = ({
|
|
18
|
+
const PBCElementsRenderer = ({
|
|
19
|
+
target = [],
|
|
20
|
+
predicate = ALWAYS_TRUE_PREDICATE,
|
|
21
|
+
}: PBCElementsRendererProps) => {
|
|
19
22
|
const containerRef = useRef<PBCContainerElement>(null);
|
|
20
23
|
const [isConnected, setIsConnected] = useState(false);
|
|
21
24
|
|
|
22
25
|
useEffect(() => {
|
|
23
26
|
const connect = DI.getOrCreateDOMContainer().get(Connect);
|
|
24
27
|
setIsConnected(connect.isConnected);
|
|
25
|
-
const isConnected$ = (
|
|
26
|
-
|
|
28
|
+
const isConnected$ = (
|
|
29
|
+
connect as {
|
|
30
|
+
isConnected$?: { subscribe: (cb: (v: boolean) => void) => { unsubscribe: () => void } };
|
|
31
|
+
}
|
|
32
|
+
)?.isConnected$;
|
|
27
33
|
const sub = isConnected$?.subscribe((connected: boolean) => setIsConnected(connected));
|
|
28
34
|
return () => sub?.unsubscribe?.();
|
|
29
35
|
}, []);
|
|
@@ -49,7 +55,7 @@ const PBCElementsRenderer = ({ target = [], predicate = ALWAYS_TRUE_PREDICATE }:
|
|
|
49
55
|
});
|
|
50
56
|
}, [target, predicate, isConnected]);
|
|
51
57
|
|
|
52
|
-
return
|
|
58
|
+
return <div ref={containerRef} className="container"></div>;
|
|
53
59
|
};
|
|
54
60
|
|
|
55
61
|
export default PBCElementsRenderer;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { createLogger } from '@genesislcap/foundation-logger';
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
3
|
+
AppContext,
|
|
4
|
+
AppElement,
|
|
5
|
+
AppElementPredicate,
|
|
6
|
+
AppStyle,
|
|
7
|
+
AppStylePredicate,
|
|
8
|
+
AppTargetId,
|
|
9
|
+
assetPredicate,
|
|
10
|
+
getApp,
|
|
11
|
+
registrationPredicate,
|
|
12
|
+
targetIdPredicate,
|
|
13
13
|
} from '@genesislcap/foundation-shell/app';
|
|
14
14
|
import { importPBCAssets } from '@genesislcap/foundation-shell/pbc';
|
|
15
15
|
import { toElementStyles } from '@genesislcap/foundation-utils';
|
|
@@ -26,10 +26,10 @@ const logger = createLogger('pbc-utils');
|
|
|
26
26
|
* @public
|
|
27
27
|
*/
|
|
28
28
|
export async function registerPBCs(): Promise<boolean> {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
const app = getApp();
|
|
30
|
+
const pbcAssets = await importPBCAssets();
|
|
31
|
+
app.registerAssets(pbcAssets);
|
|
32
|
+
return app.hasAssets();
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
/**
|
|
@@ -37,76 +37,72 @@ export async function registerPBCs(): Promise<boolean> {
|
|
|
37
37
|
* Shared across elements and styles.
|
|
38
38
|
*/
|
|
39
39
|
const assetFilter = (
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
) =>
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
predicate,
|
|
49
|
-
context,
|
|
50
|
-
);
|
|
40
|
+
asset: AppElement | AppStyle,
|
|
41
|
+
targetId: AppTargetId,
|
|
42
|
+
predicate: AppElementPredicate | AppStylePredicate = () => true,
|
|
43
|
+
context: AppContext,
|
|
44
|
+
) =>
|
|
45
|
+
targetIdPredicate(asset, targetId) &&
|
|
46
|
+
assetPredicate(asset, context) &&
|
|
47
|
+
registrationPredicate(asset, predicate, context);
|
|
51
48
|
|
|
52
49
|
/**
|
|
53
50
|
* @public
|
|
54
51
|
*/
|
|
55
|
-
export function getTargetStyles(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
.filter(asset => assetFilter(asset, targetId, predicate, app.config.context!))
|
|
62
|
-
.map((token) => token.styles)
|
|
63
|
-
.flat();
|
|
52
|
+
export function getTargetStyles(targetId: AppTargetId, predicate: AppStylePredicate = () => true) {
|
|
53
|
+
const app = getApp();
|
|
54
|
+
return app.styles
|
|
55
|
+
.filter((asset) => assetFilter(asset, targetId, predicate, app.config.context!))
|
|
56
|
+
.map((token) => token.styles)
|
|
57
|
+
.flat();
|
|
64
58
|
}
|
|
65
59
|
|
|
66
|
-
|
|
67
60
|
/**
|
|
68
61
|
* @public
|
|
69
62
|
*/
|
|
70
63
|
export function getTargetElements(
|
|
71
|
-
|
|
72
|
-
|
|
64
|
+
targetId: AppTargetId,
|
|
65
|
+
predicate: AppElementPredicate = () => true,
|
|
73
66
|
) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
67
|
+
const app = getApp();
|
|
68
|
+
return app.elements
|
|
69
|
+
.filter((asset) => assetFilter(asset, targetId, predicate, app.config.context!))
|
|
70
|
+
.map((token) => token.elements);
|
|
78
71
|
}
|
|
79
72
|
|
|
80
73
|
/**
|
|
81
74
|
* @public
|
|
82
75
|
*/
|
|
83
76
|
export function registerStylesTarget(nativeElement: HTMLElement, targetId: AppTargetId) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
77
|
+
const styles = getTargetStyles(targetId);
|
|
78
|
+
if (!styles || styles.length === 0) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
applyDynamicStyles(nativeElement, styles);
|
|
89
82
|
}
|
|
90
83
|
|
|
91
84
|
/**
|
|
92
85
|
* @public
|
|
93
86
|
*/
|
|
94
|
-
export function applyDynamicStyles(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
87
|
+
export function applyDynamicStyles(
|
|
88
|
+
nativeElement: HTMLElement,
|
|
89
|
+
style: ComposableStyles | ComposableStyles[],
|
|
90
|
+
) {
|
|
91
|
+
const elementStyles = toElementStyles(style);
|
|
92
|
+
const styleTarget = nativeElement.shadowRoot ? nativeElement.shadowRoot : document;
|
|
93
|
+
elementStyles.addStylesTo(styleTarget);
|
|
98
94
|
}
|
|
99
95
|
|
|
100
96
|
/**
|
|
101
97
|
* @public
|
|
102
98
|
*/
|
|
103
99
|
export function customEventFactory(type: string, detail?: any) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
100
|
+
return new CustomEvent(type, {
|
|
101
|
+
bubbles: true,
|
|
102
|
+
cancelable: true,
|
|
103
|
+
composed: true,
|
|
104
|
+
detail,
|
|
105
|
+
});
|
|
110
106
|
}
|
|
111
107
|
|
|
112
108
|
/**
|
|
@@ -115,7 +111,12 @@ export function customEventFactory(type: string, detail?: any) {
|
|
|
115
111
|
* @public
|
|
116
112
|
*/
|
|
117
113
|
export function deriveElementTag(name: string): string {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
114
|
+
const tagName = name
|
|
115
|
+
.replace(/([A-Z])/g, '-$1')
|
|
116
|
+
.toLowerCase()
|
|
117
|
+
.replace(/^-/, '');
|
|
118
|
+
logger.debug(
|
|
119
|
+
`Guessing pbc element tag is '${tagName}' based on '${name}'. This may be incorrect, please set pbcElementTag in route data.`,
|
|
120
|
+
);
|
|
121
|
+
return tagName;
|
|
121
122
|
}
|
|
@@ -30,9 +30,11 @@ class DefaultStore extends AbstractStoreRoot<Store, StoreEventDetailMap> impleme
|
|
|
30
30
|
|
|
31
31
|
setConnected(connected: boolean) {
|
|
32
32
|
this.connected = connected;
|
|
33
|
-
document.dispatchEvent(
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
document.dispatchEvent(
|
|
34
|
+
new CustomEvent('connected-changed', {
|
|
35
|
+
detail: { connected },
|
|
36
|
+
}),
|
|
37
|
+
);
|
|
36
38
|
}
|
|
37
39
|
}
|
|
38
40
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { configure, defaultAuthConfig } from '@genesislcap/foundation-auth/config';
|
|
2
|
+
import { Connect } from '@genesislcap/foundation-comms';
|
|
2
3
|
import {
|
|
3
4
|
buildPostLoginRedirect,
|
|
4
5
|
type RedirectableLocationState,
|
|
5
6
|
} from '@genesislcap/foundation-react-utils/router';
|
|
6
|
-
import { AUTH_PATH } from '../config';
|
|
7
|
-
import { Connect } from '@genesislcap/foundation-comms';
|
|
8
7
|
import { DI } from '@genesislcap/web-core';
|
|
9
8
|
import type { NavigateFunction, Location as RouterLocation } from 'react-router-dom';
|
|
9
|
+
import { AUTH_PATH } from '../config';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Configure the micro frontend
|
|
@@ -1,47 +1,46 @@
|
|
|
1
|
-
import { getApp } from '@genesislcap/foundation-shell/app';
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Ensure tree shaking doesn't remove these.
|
|
10
|
-
*/
|
|
11
|
-
avoidTreeShaking(FoundationRouter);
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* registerComponents.
|
|
15
|
-
* @public
|
|
16
|
-
*/
|
|
17
|
-
export async function registerComponents() {
|
|
18
|
-
const { configure: configureHeader } = await import('@genesislcap/foundation-header/config');
|
|
19
|
-
/**
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
getApp().registerComponents({
|
|
23
|
-
designSystem: rapidDesignSystem,
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
rapidDesignSystem
|
|
27
|
-
.provideDesignSystem()
|
|
28
|
-
.register(
|
|
29
|
-
rapidDesignSystem.baseComponents,
|
|
30
|
-
rapidGridProBeta(),
|
|
31
|
-
rapidGridComponents,
|
|
32
|
-
g2plotChartsComponents,
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
configureHeader({
|
|
36
|
-
templateOptions: {
|
|
37
|
-
provider: 'template',
|
|
38
|
-
icon: 'rapid-icon',
|
|
39
|
-
button: 'rapid-button',
|
|
40
|
-
connectionIndicator: 'rapid-connection-indicator',
|
|
41
|
-
select: 'rapid-select',
|
|
42
|
-
option: 'rapid-option',
|
|
43
|
-
flyout: 'rapid-flyout',
|
|
44
|
-
},
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
}
|
|
1
|
+
import { getApp } from '@genesislcap/foundation-shell/app';
|
|
2
|
+
import { FoundationRouter } from '@genesislcap/foundation-ui';
|
|
3
|
+
import { avoidTreeShaking } from '@genesislcap/foundation-utils';
|
|
4
|
+
import { g2plotChartsComponents } from '@genesislcap/g2plot-chart';
|
|
5
|
+
import * as rapidDesignSystem from '@genesislcap/rapid-design-system';
|
|
6
|
+
import { rapidGridComponents, rapidGridProBeta } from '@genesislcap/rapid-grid-pro';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Ensure tree shaking doesn't remove these.
|
|
10
|
+
*/
|
|
11
|
+
avoidTreeShaking(FoundationRouter);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* registerComponents.
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
export async function registerComponents() {
|
|
18
|
+
const { configure: configureHeader } = await import('@genesislcap/foundation-header/config');
|
|
19
|
+
/**
|
|
20
|
+
* Register any PBC components with the design system
|
|
21
|
+
*/
|
|
22
|
+
getApp().registerComponents({
|
|
23
|
+
designSystem: rapidDesignSystem,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
rapidDesignSystem
|
|
27
|
+
.provideDesignSystem()
|
|
28
|
+
.register(
|
|
29
|
+
rapidDesignSystem.baseComponents,
|
|
30
|
+
rapidGridProBeta(),
|
|
31
|
+
rapidGridComponents,
|
|
32
|
+
g2plotChartsComponents,
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
configureHeader({
|
|
36
|
+
templateOptions: {
|
|
37
|
+
provider: 'template',
|
|
38
|
+
icon: 'rapid-icon',
|
|
39
|
+
button: 'rapid-button',
|
|
40
|
+
connectionIndicator: 'rapid-connection-indicator',
|
|
41
|
+
select: 'rapid-select',
|
|
42
|
+
option: 'rapid-option',
|
|
43
|
+
flyout: 'rapid-flyout',
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
}
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createContext,
|
|
3
|
-
useState,
|
|
4
|
-
useContext,
|
|
5
|
-
ReactNode,
|
|
6
|
-
FunctionComponent,
|
|
7
|
-
} from 'react';
|
|
1
|
+
import { createContext, useState, useContext, ReactNode, FunctionComponent } from 'react';
|
|
8
2
|
import { authService } from '../services/auth.service';
|
|
9
3
|
|
|
10
4
|
interface AuthContextType {
|
|
@@ -31,9 +25,7 @@ export const useAuth = () => {
|
|
|
31
25
|
return context;
|
|
32
26
|
};
|
|
33
27
|
|
|
34
|
-
export const AuthProvider: FunctionComponent<AuthProviderProps> = ({
|
|
35
|
-
children,
|
|
36
|
-
}) => {
|
|
28
|
+
export const AuthProvider: FunctionComponent<AuthProviderProps> = ({ children }) => {
|
|
37
29
|
const [user, setUser] = useState<User | null>(null);
|
|
38
30
|
|
|
39
31
|
const checkAuthStatus = async () => {
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { AppRouteConfig, PbcRouteInput } from '@genesislcap/foundation-react-utils/router';
|
|
2
|
+
import { fireEvent, render, screen } from '@testing-library/react';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { RoutesProvider, useRoutesContext } from './RoutesContext';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `getApp()` resolves the shell's `App` singleton out of the DI DOM container, which this
|
|
8
|
+
* unit test has no reason to boot. The stand-in mirrors the only thing the provider reads:
|
|
9
|
+
* a plain `routes` array field, stored once by the real `App` and only ever reassigned
|
|
10
|
+
* (registerAssets/deregisterAssets) — so identity behaves here exactly as it does in the app.
|
|
11
|
+
*/
|
|
12
|
+
const mockShellApp: { routes: PbcRouteInput[] } = { routes: [] };
|
|
13
|
+
|
|
14
|
+
jest.mock('@genesislcap/foundation-shell/app', () => ({
|
|
15
|
+
getApp: () => mockShellApp,
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
// Route pages are inert payload for this test — the provider only parks them in the route
|
|
19
|
+
// table as `element` values, never renders them — while dragging in the foundation-auth
|
|
20
|
+
// runtime and, for generated dashboards/charts, chart libraries jest cannot transform.
|
|
21
|
+
// Stubbed here; the route table itself and `mergePbcRoutes` stay real.
|
|
22
|
+
jest.mock('../pages/AuthPage/AuthPage', () => () => null);
|
|
23
|
+
jest.mock('../pages/NotPermittedPage/NotPermittedPage', () => () => null);
|
|
24
|
+
{{#each routes}}
|
|
25
|
+
jest.mock('../pages/{{pascalCase this.name}}/{{pascalCase this.name}}', () => () => null);
|
|
26
|
+
{{/each}}
|
|
27
|
+
|
|
28
|
+
/** Every context value the consumer below saw, in render order. */
|
|
29
|
+
const captured: AppRouteConfig[][] = [];
|
|
30
|
+
|
|
31
|
+
const RoutesConsumer = () => {
|
|
32
|
+
const routes = useRoutesContext();
|
|
33
|
+
captured.push(routes);
|
|
34
|
+
return null;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/** A fresh element tree per call, so React cannot bail out of re-rendering the provider. */
|
|
38
|
+
const providerTree = () => (
|
|
39
|
+
<RoutesProvider>
|
|
40
|
+
<RoutesConsumer />
|
|
41
|
+
</RoutesProvider>
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const expectSingleIdentity = () => {
|
|
45
|
+
// initial render plus at least two re-renders
|
|
46
|
+
expect(captured.length).toBeGreaterThan(2);
|
|
47
|
+
captured.forEach((value) => {
|
|
48
|
+
expect(value).toBe(captured[0]);
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
describe('RoutesProvider', () => {
|
|
53
|
+
beforeEach(() => {
|
|
54
|
+
captured.length = 0;
|
|
55
|
+
mockShellApp.routes = [];
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('hands consumers one context value identity across re-renders', () => {
|
|
59
|
+
const { rerender } = render(providerTree());
|
|
60
|
+
|
|
61
|
+
rerender(providerTree());
|
|
62
|
+
rerender(providerTree());
|
|
63
|
+
|
|
64
|
+
expectSingleIdentity();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test('hands consumers one context value identity when a parent state change cascades in', () => {
|
|
68
|
+
const Parent = () => {
|
|
69
|
+
const [tick, setTick] = useState(0);
|
|
70
|
+
return (
|
|
71
|
+
<RoutesProvider>
|
|
72
|
+
<button type="button" onClick={() => setTick(tick + 1)}>
|
|
73
|
+
tick {tick}
|
|
74
|
+
</button>
|
|
75
|
+
<RoutesConsumer />
|
|
76
|
+
</RoutesProvider>
|
|
77
|
+
);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
render(<Parent />);
|
|
81
|
+
const tickButton = screen.getByRole('button');
|
|
82
|
+
fireEvent.click(tickButton);
|
|
83
|
+
fireEvent.click(tickButton);
|
|
84
|
+
|
|
85
|
+
expectSingleIdentity();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('recomputes the context value when the app reassigns its routes', () => {
|
|
89
|
+
const { rerender } = render(providerTree());
|
|
90
|
+
const beforeReassign = captured[captured.length - 1];
|
|
91
|
+
|
|
92
|
+
mockShellApp.routes = [{ path: 'pbc-page', settings: { permissionCode: 'PBC_VIEW' } }];
|
|
93
|
+
rerender(providerTree());
|
|
94
|
+
|
|
95
|
+
const afterReassign = captured[captured.length - 1];
|
|
96
|
+
expect(afterReassign).not.toBe(beforeReassign);
|
|
97
|
+
expect(afterReassign.map((route) => route.path)).toContain('/pbc-page');
|
|
98
|
+
});
|
|
99
|
+
});
|