@equinor/fusion-framework-react-app 14.1.0 → 14.1.2
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/dist/esm/version.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/version.d.ts +1 -1
- package/package.json +33 -30
- package/CHANGELOG.md +0 -2785
- package/docs/ag-grid.md +0 -70
- package/docs/analytics.md +0 -122
- package/docs/app.md +0 -148
- package/docs/apploader.md +0 -110
- package/docs/bookmark.md +0 -108
- package/docs/context.md +0 -88
- package/docs/feature-flag.md +0 -119
- package/docs/framework.md +0 -93
- package/docs/help-center.md +0 -88
- package/docs/http.md +0 -118
- package/docs/msal.md +0 -291
- package/docs/navigation.md +0 -80
- package/docs/routing.md +0 -86
- package/docs/settings.md +0 -139
- package/src/__tests__/Apploader.test.tsx +0 -51
- package/src/__tests__/fixtures/apploader-child-script.ts +0 -9
- package/src/__tests__/render-app.test.tsx +0 -113
- package/src/__tests__/testApp.test.tsx +0 -76
- package/src/__tests__/useAccessToken.test.tsx +0 -51
- package/src/__tests__/useAppSetting.test.tsx +0 -133
- package/src/__tests__/useAppSettings.test.tsx +0 -147
- package/src/__tests__/useCurrentAccount.test.tsx +0 -32
- package/src/__tests__/useCurrentBookmark.test.tsx +0 -108
- package/src/__tests__/useCurrentContext.test.tsx +0 -72
- package/src/__tests__/useFeature.test.tsx +0 -104
- package/src/__tests__/useHelpCenter.test.tsx +0 -64
- package/src/__tests__/useStateSyncEvents.test.ts +0 -58
- package/src/__tests__/useToken.test.tsx +0 -71
- package/src/__tests__/useTrackFeature.test.tsx +0 -83
- package/src/ag-grid/community.ts +0 -11
- package/src/ag-grid/enterprise.ts +0 -11
- package/src/ag-grid/react.ts +0 -11
- package/src/ag-grid/testing.ts +0 -19
- package/src/ag-grid/theme.ts +0 -17
- package/src/ag-grid/useTheme.ts +0 -21
- package/src/analytics/README.md +0 -148
- package/src/analytics/index.ts +0 -9
- package/src/analytics/useTrackFeature.ts +0 -73
- package/src/apploader/Apploader.tsx +0 -50
- package/src/apploader/README.md +0 -81
- package/src/apploader/index.ts +0 -10
- package/src/apploader/useApploader.ts +0 -107
- package/src/bookmark/index.ts +0 -20
- package/src/bookmark/useBookmark.ts +0 -25
- package/src/bookmark/useCurrentBookmark.ts +0 -54
- package/src/context/index.ts +0 -14
- package/src/context/useContextProvider.ts +0 -12
- package/src/context/useCurrentContext.ts +0 -20
- package/src/create-component.tsx +0 -120
- package/src/create-legacy-app.tsx +0 -51
- package/src/feature-flag/README.md +0 -20
- package/src/feature-flag/enable-feature-flag.ts +0 -79
- package/src/feature-flag/index.ts +0 -17
- package/src/feature-flag/useFeature.ts +0 -90
- package/src/framework/index.ts +0 -14
- package/src/framework/useFrameworkCurrentContext.ts +0 -15
- package/src/help-center/README.md +0 -21
- package/src/help-center/event-name.ts +0 -1
- package/src/help-center/index.ts +0 -11
- package/src/help-center/useHelpCenter.ts +0 -162
- package/src/http/index.ts +0 -10
- package/src/http/selectors.ts +0 -9
- package/src/index.ts +0 -46
- package/src/make-component.tsx +0 -102
- package/src/msal/index.ts +0 -16
- package/src/msal/useAccessToken.ts +0 -26
- package/src/msal/useCurrentAccount.ts +0 -21
- package/src/msal/useToken.ts +0 -63
- package/src/navigation/index.ts +0 -10
- package/src/navigation/useNavigationModule.ts +0 -10
- package/src/navigation/useRouter.ts +0 -35
- package/src/render-app.ts +0 -35
- package/src/render-component.tsx +0 -55
- package/src/routing/index.ts +0 -33
- package/src/settings/README.md +0 -123
- package/src/settings/index.ts +0 -12
- package/src/settings/useAppSetting.ts +0 -113
- package/src/settings/useAppSettings.ts +0 -103
- package/src/settings/useAppSettingsStatus.ts +0 -52
- package/src/state/index.ts +0 -12
- package/src/state/useAppState.ts +0 -299
- package/src/state/useStateSyncEvents.ts +0 -59
- package/src/useAppEnvironmentVariables.ts +0 -59
- package/src/useAppModule.ts +0 -45
- package/src/useAppModules.ts +0 -21
- package/src/version.ts +0 -2
- package/tsconfig.json +0 -54
- package/vitest.config.ts +0 -9
package/src/make-component.tsx
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import type React from 'react';
|
|
2
|
-
import { lazy } from 'react';
|
|
3
|
-
|
|
4
|
-
import { FrameworkProvider } from '@equinor/fusion-framework-react';
|
|
5
|
-
import type { Fusion } from '@equinor/fusion-framework-react';
|
|
6
|
-
|
|
7
|
-
import { type AppEnv, configureModules } from '@equinor/fusion-framework-app';
|
|
8
|
-
import type { AppModuleInitiator, AppModulesInstance } from '@equinor/fusion-framework-app';
|
|
9
|
-
|
|
10
|
-
import type { AnyModule } from '@equinor/fusion-framework-module';
|
|
11
|
-
|
|
12
|
-
import type { FrameworkEvent, FrameworkEventInit } from '@equinor/fusion-framework-module-event';
|
|
13
|
-
|
|
14
|
-
import { ModuleProvider as AppModuleProvider } from '@equinor/fusion-framework-react-module';
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Arguments supplied when rendering a Fusion app component.
|
|
18
|
-
*
|
|
19
|
-
* @template TFusion - The Fusion framework instance type.
|
|
20
|
-
* @template TEnv - The application environment type.
|
|
21
|
-
*/
|
|
22
|
-
export type ComponentRenderArgs<TFusion extends Fusion = Fusion, TEnv = AppEnv> = {
|
|
23
|
-
/** The Fusion framework instance. */
|
|
24
|
-
fusion: TFusion;
|
|
25
|
-
/** The application environment (manifest, config, basename, etc.). */
|
|
26
|
-
env: TEnv;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Factory function that receives a Fusion instance and environment and returns a
|
|
31
|
-
* lazy React component ready to be rendered.
|
|
32
|
-
*
|
|
33
|
-
* @template TFusion - The Fusion framework instance type.
|
|
34
|
-
* @template TEnv - The application environment type.
|
|
35
|
-
*/
|
|
36
|
-
export type ComponentRenderer<TFusion extends Fusion = Fusion, TEnv = AppEnv> = (
|
|
37
|
-
fusion: TFusion,
|
|
38
|
-
env: TEnv,
|
|
39
|
-
) => React.LazyExoticComponent<React.ComponentType>;
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Creates a lazy loading React Component that initializes and configures modules,
|
|
43
|
-
* then provides the necessary context to both the Fusion framework and the configured modules.
|
|
44
|
-
* This function is particularly useful for setting up a React application with modular architecture,
|
|
45
|
-
* allowing for lazy loading of components along with their dependencies.
|
|
46
|
-
*
|
|
47
|
-
* __Exposed providers__:
|
|
48
|
-
* - {@link @equinor/fusion-framework-react.FrameworkProvider | FrameworkProvider} to provide Fusion context.
|
|
49
|
-
* - {@link @equinor/fusion-framework-react-module.ModuleProvider | ModuleProvider} to provide module instances.
|
|
50
|
-
*
|
|
51
|
-
* @template TModules The types of modules included in the configuration.
|
|
52
|
-
* @template TRef The type of the Fusion instance.
|
|
53
|
-
* @template TEnv The environment type for the application.
|
|
54
|
-
* @param {React.ReactNode} Component - The React component to render lazily.
|
|
55
|
-
* @param {Object} args - The arguments required for module configuration and component rendering.
|
|
56
|
-
* @param {TRef} args.fusion - The Fusion instance to be used by the component and modules.
|
|
57
|
-
* @param {TEnv} args.env - The environment context for the application.
|
|
58
|
-
* @param {AppModuleInitiator<TModules, TRef, TEnv>} [configure] - Optional callback function for configuring application modules.
|
|
59
|
-
* @returns {React.LazyExoticComponent<React.ComponentType>} A lazy component that, when rendered,
|
|
60
|
-
* initializes the specified modules and provides the necessary Fusion and module context.
|
|
61
|
-
*/
|
|
62
|
-
export const makeComponent = <
|
|
63
|
-
TModules extends Array<AnyModule>,
|
|
64
|
-
TRef extends Fusion = Fusion,
|
|
65
|
-
TEnv extends AppEnv = AppEnv,
|
|
66
|
-
>(
|
|
67
|
-
Component: React.ReactNode,
|
|
68
|
-
args: { fusion: TRef; env: TEnv },
|
|
69
|
-
configure?: AppModuleInitiator<TModules, TRef, TEnv>,
|
|
70
|
-
): React.LazyExoticComponent<React.ComponentType> =>
|
|
71
|
-
lazy(async () => {
|
|
72
|
-
const init = configureModules<TModules, TRef, TEnv>(configure);
|
|
73
|
-
const modules = await init(args);
|
|
74
|
-
|
|
75
|
-
const { fusion } = args;
|
|
76
|
-
|
|
77
|
-
modules.event.dispatchEvent('onReactAppLoaded', {
|
|
78
|
-
detail: { modules, fusion, env: args.env },
|
|
79
|
-
source: Component,
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
return {
|
|
83
|
-
default: () => (
|
|
84
|
-
<FrameworkProvider value={fusion}>
|
|
85
|
-
<AppModuleProvider value={modules}>{Component}</AppModuleProvider>
|
|
86
|
-
</FrameworkProvider>
|
|
87
|
-
),
|
|
88
|
-
};
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
declare module '@equinor/fusion-framework-module-event' {
|
|
92
|
-
interface FrameworkEventMap {
|
|
93
|
-
onReactAppLoaded: FrameworkEvent<
|
|
94
|
-
FrameworkEventInit<
|
|
95
|
-
{ modules: AppModulesInstance; fusion: Fusion; env: AppEnv },
|
|
96
|
-
React.ComponentType
|
|
97
|
-
>
|
|
98
|
-
>;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export default makeComponent;
|
package/src/msal/index.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MSAL authentication sub-path entry-point.
|
|
3
|
-
*
|
|
4
|
-
* Provides React hooks for accessing MSAL-based authentication state
|
|
5
|
-
* (current account, access tokens) from within a Fusion application.
|
|
6
|
-
*
|
|
7
|
-
* @remarks
|
|
8
|
-
* Requires `@equinor/fusion-framework-module-msal` to be installed and
|
|
9
|
-
* configured by the host/portal. Applications should **not** configure the
|
|
10
|
-
* MSAL module themselves.
|
|
11
|
-
*
|
|
12
|
-
* @packageDocumentation
|
|
13
|
-
*/
|
|
14
|
-
export { useCurrentAccount } from './useCurrentAccount';
|
|
15
|
-
export { useAccessToken } from './useAccessToken';
|
|
16
|
-
export { useToken } from './useToken';
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { useToken } from './useToken';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* React hook that acquires an OAuth 2.0 access token string via MSAL.
|
|
5
|
-
*
|
|
6
|
-
* This is a convenience wrapper around {@link useToken} that extracts the
|
|
7
|
-
* `accessToken` property from the full `AuthenticationResult`.
|
|
8
|
-
*
|
|
9
|
-
* @param req - The token request containing the `scopes` to acquire.
|
|
10
|
-
* @param req.scopes - Array of scope strings (e.g. `['User.Read']`).
|
|
11
|
-
* @returns An object with:
|
|
12
|
-
* - `token` – the access token string, or `undefined` while pending.
|
|
13
|
-
* - `pending` – `true` while the token is being acquired.
|
|
14
|
-
* - `error` – any error encountered during acquisition.
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* ```tsx
|
|
18
|
-
* const { token, pending, error } = useAccessToken({ scopes: ['api://my-api/.default'] });
|
|
19
|
-
* ```
|
|
20
|
-
*/
|
|
21
|
-
export const useAccessToken = (req: {
|
|
22
|
-
scopes: string[];
|
|
23
|
-
}): { token?: string; pending: boolean; error: unknown } => {
|
|
24
|
-
const { token, error, pending } = useToken(req);
|
|
25
|
-
return { token: token?.accessToken, pending, error };
|
|
26
|
-
};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { AccountInfo } from '@equinor/fusion-framework-module-msal';
|
|
2
|
-
import useAppModule from '../useAppModule';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* React hook that returns the currently signed-in user's MSAL account info.
|
|
6
|
-
*
|
|
7
|
-
* @returns The {@link AccountInfo} for the active account, or `undefined` if
|
|
8
|
-
* no user is signed in.
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* ```tsx
|
|
12
|
-
* const account = useCurrentAccount();
|
|
13
|
-
* if (account) {
|
|
14
|
-
* console.log('Signed in as', account.name);
|
|
15
|
-
* }
|
|
16
|
-
* ```
|
|
17
|
-
*/
|
|
18
|
-
export const useCurrentAccount = (): AccountInfo | undefined => {
|
|
19
|
-
const msalProvider = useAppModule('auth');
|
|
20
|
-
return msalProvider.account || undefined;
|
|
21
|
-
};
|
package/src/msal/useToken.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { useEffect, useRef, useState } from 'react';
|
|
2
|
-
|
|
3
|
-
import type { AuthenticationResult } from '@equinor/fusion-framework-module-msal';
|
|
4
|
-
|
|
5
|
-
import useAppModule from '../useAppModule';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* React hook that acquires a full MSAL {@link AuthenticationResult} for the
|
|
9
|
-
* requested scopes.
|
|
10
|
-
*
|
|
11
|
-
* The hook attempts silent acquisition first and falls back to an interactive
|
|
12
|
-
* prompt when required by the MSAL provider.
|
|
13
|
-
*
|
|
14
|
-
* @param req - The token request containing the `scopes` to acquire.
|
|
15
|
-
* @param req.scopes - Array of scope strings (e.g. `['User.Read']`).
|
|
16
|
-
* @returns An object with:
|
|
17
|
-
* - `token` – the full {@link AuthenticationResult}, or `undefined` while pending.
|
|
18
|
-
* - `pending` – `true` while the token is being acquired.
|
|
19
|
-
* - `error` – any error encountered during acquisition.
|
|
20
|
-
*
|
|
21
|
-
* @example
|
|
22
|
-
* ```tsx
|
|
23
|
-
* const { token, pending } = useToken({ scopes: ['User.Read'] });
|
|
24
|
-
* if (pending) return <Spinner />;
|
|
25
|
-
* console.log('ID token:', token?.idToken);
|
|
26
|
-
* ```
|
|
27
|
-
*/
|
|
28
|
-
export const useToken = (req: {
|
|
29
|
-
scopes: string[];
|
|
30
|
-
}): { token?: AuthenticationResult; pending: boolean; error: unknown } => {
|
|
31
|
-
const msalProvider = useAppModule('auth');
|
|
32
|
-
const [token, setToken] = useState<AuthenticationResult | undefined>(undefined);
|
|
33
|
-
const [pending, setPending] = useState<boolean>(false);
|
|
34
|
-
const [error, setError] = useState<unknown>(null);
|
|
35
|
-
|
|
36
|
-
// `req` is typically a fresh object literal each render; key the effect on its
|
|
37
|
-
// scopes' content instead of identity, so it doesn't re-run (and reset `pending`
|
|
38
|
-
// to `true` forever) every time the caller re-renders. `JSON.stringify` (rather than
|
|
39
|
-
// `.join(',')`) keeps scopes with different array boundaries (e.g. `['a,b']` vs.
|
|
40
|
-
// `['a', 'b']`) from colliding on the same key.
|
|
41
|
-
const scopesKey = JSON.stringify(req.scopes);
|
|
42
|
-
const reqRef = useRef(req);
|
|
43
|
-
reqRef.current = req;
|
|
44
|
-
|
|
45
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies: scopesKey is a re-run trigger, not read in the body
|
|
46
|
-
useEffect(() => {
|
|
47
|
-
setPending(true);
|
|
48
|
-
setToken(undefined);
|
|
49
|
-
msalProvider
|
|
50
|
-
.acquireToken({ request: reqRef.current })
|
|
51
|
-
.then((result) => {
|
|
52
|
-
// Only update state when a token was actually acquired
|
|
53
|
-
if (result) {
|
|
54
|
-
setToken(result);
|
|
55
|
-
}
|
|
56
|
-
})
|
|
57
|
-
.catch(setError)
|
|
58
|
-
.finally(() => setPending(false));
|
|
59
|
-
}, [msalProvider, scopesKey]);
|
|
60
|
-
return { token, pending, error };
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
export default useToken;
|
package/src/navigation/index.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Navigation sub-path entry-point.
|
|
3
|
-
*
|
|
4
|
-
* Provides hooks for accessing the Fusion navigation module and creating
|
|
5
|
-
* client-side routers compatible with `react-router`.
|
|
6
|
-
*
|
|
7
|
-
* @packageDocumentation
|
|
8
|
-
*/
|
|
9
|
-
export { useNavigationModule } from './useNavigationModule';
|
|
10
|
-
export { useRouter } from './useRouter';
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import useAppModule from '../useAppModule';
|
|
2
|
-
import type { INavigationProvider } from '@equinor/fusion-framework-module-navigation';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* React hook that resolves the application-scoped navigation module provider.
|
|
6
|
-
*
|
|
7
|
-
* @returns The navigation provider instance.
|
|
8
|
-
* @throws If the navigation module has not been enabled for the application.
|
|
9
|
-
*/
|
|
10
|
-
export const useNavigationModule = (): INavigationProvider => useAppModule('navigation');
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { useMemo } from 'react';
|
|
2
|
-
import { useNavigationModule } from './useNavigationModule';
|
|
3
|
-
import type { INavigationProvider } from '@equinor/fusion-framework-module-navigation';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* React hook that creates a router instance for client-side navigation.
|
|
7
|
-
*
|
|
8
|
-
* The `routes` argument **must** be static or memoised to avoid re-creating
|
|
9
|
-
* the router on every render.
|
|
10
|
-
*
|
|
11
|
-
* @param routes - An array of route objects compatible with
|
|
12
|
-
* `INavigationProvider.createRouter`.
|
|
13
|
-
* @returns A router instance to pass to `<RouterProvider>`.
|
|
14
|
-
*
|
|
15
|
-
* @see {@link https://equinor.github.io/fusion-framework/modules/navigation/ | Fusion navigation docs}
|
|
16
|
-
* @see {@link https://reactrouter.com/en/main/routers/create-browser-router | react-router docs}
|
|
17
|
-
*
|
|
18
|
-
* @example
|
|
19
|
-
* ```tsx
|
|
20
|
-
* import { useRouter } from '@equinor/fusion-framework-react-app/navigation';
|
|
21
|
-
* import { RouterProvider } from '@equinor/fusion-framework-react-router';
|
|
22
|
-
*
|
|
23
|
-
* const routes = [{ path: '/', element: <Home /> }];
|
|
24
|
-
* const App = () => {
|
|
25
|
-
* const router = useRouter(routes);
|
|
26
|
-
* return <RouterProvider router={router} />;
|
|
27
|
-
* };
|
|
28
|
-
* ```
|
|
29
|
-
*/
|
|
30
|
-
export const useRouter = (
|
|
31
|
-
routes: Parameters<INavigationProvider['createRouter']>[0],
|
|
32
|
-
): ReturnType<INavigationProvider['createRouter']> => {
|
|
33
|
-
const provider = useNavigationModule();
|
|
34
|
-
return useMemo(() => provider.createRouter(routes), [provider, routes]);
|
|
35
|
-
};
|
package/src/render-app.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { createComponent } from './create-component';
|
|
2
|
-
import { renderComponent, type RenderTeardown } from './render-component';
|
|
3
|
-
|
|
4
|
-
import type { ComponentRenderArgs } from './create-component';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Creates a render function for a Fusion React application.
|
|
8
|
-
*
|
|
9
|
-
* Wraps {@link createComponent} and {@link renderComponent} into a single factory:
|
|
10
|
-
* call the returned function with an `HTMLElement` and `ComponentRenderArgs` to
|
|
11
|
-
* mount the app using React 18's `createRoot` API.
|
|
12
|
-
*
|
|
13
|
-
* @param componentArgs - Arguments forwarded to {@link createComponent} (the React
|
|
14
|
-
* component to render and an optional module-configuration callback).
|
|
15
|
-
* @returns A mount function that accepts a DOM element and render args, and returns
|
|
16
|
-
* a {@link RenderTeardown} callback to unmount the application.
|
|
17
|
-
*
|
|
18
|
-
* @example
|
|
19
|
-
* ```ts
|
|
20
|
-
* import { renderApp } from '@equinor/fusion-framework-react-app';
|
|
21
|
-
* import { App } from './App';
|
|
22
|
-
* import { configure } from './config';
|
|
23
|
-
*
|
|
24
|
-
* export const render = renderApp(App, configure);
|
|
25
|
-
* export default render;
|
|
26
|
-
* ```
|
|
27
|
-
*/
|
|
28
|
-
export const renderApp = (...componentArgs: Parameters<typeof createComponent>) => {
|
|
29
|
-
const renderer = renderComponent(createComponent(...componentArgs));
|
|
30
|
-
return (el: HTMLElement, args: ComponentRenderArgs): RenderTeardown => {
|
|
31
|
-
return renderer(el, args);
|
|
32
|
-
};
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export default renderApp;
|
package/src/render-component.tsx
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { Suspense, StrictMode } from 'react';
|
|
2
|
-
import type { FunctionComponent } from 'react';
|
|
3
|
-
import { createRoot, type Root } from 'react-dom/client';
|
|
4
|
-
import type { ComponentRenderArgs, ComponentRenderer } from './create-component';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Callback returned after mounting an application; invoke it to unmount and clean
|
|
8
|
-
* up the React root.
|
|
9
|
-
*/
|
|
10
|
-
export type RenderTeardown = VoidFunction;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Renders a React component into a DOM element using React 18's `createRoot` API.
|
|
14
|
-
*
|
|
15
|
-
* The component is wrapped in `<StrictMode>` and `<Suspense>` with a basic
|
|
16
|
-
* loading fallback.
|
|
17
|
-
*
|
|
18
|
-
* @param el - The DOM element to render into.
|
|
19
|
-
* @param Component - The React function component to render.
|
|
20
|
-
* @returns A {@link RenderTeardown} callback that unmounts the component.
|
|
21
|
-
*/
|
|
22
|
-
const render = (el: Element, Component: FunctionComponent): RenderTeardown => {
|
|
23
|
-
const root: Root = createRoot(el);
|
|
24
|
-
root.render(
|
|
25
|
-
<StrictMode>
|
|
26
|
-
<Suspense fallback={<p>loading app</p>}>
|
|
27
|
-
<Component />
|
|
28
|
-
</Suspense>
|
|
29
|
-
</StrictMode>,
|
|
30
|
-
);
|
|
31
|
-
return () => {
|
|
32
|
-
root.unmount();
|
|
33
|
-
};
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Creates a mount function from a {@link ComponentRenderer}.
|
|
38
|
-
*
|
|
39
|
-
* The returned function accepts a target `HTMLElement` and
|
|
40
|
-
* {@link ComponentRenderArgs}, resolves the lazy component via the renderer,
|
|
41
|
-
* and mounts it with React 18's `createRoot`.
|
|
42
|
-
*
|
|
43
|
-
* @param renderer - A {@link ComponentRenderer} that produces a lazy component
|
|
44
|
-
* from Fusion and environment arguments.
|
|
45
|
-
* @returns A function `(el, args) => RenderTeardown` that mounts the app and
|
|
46
|
-
* returns a teardown callback.
|
|
47
|
-
*/
|
|
48
|
-
export const renderComponent = (renderer: ComponentRenderer) => {
|
|
49
|
-
return (el: HTMLElement, args: ComponentRenderArgs): RenderTeardown => {
|
|
50
|
-
const Component = renderer(args.fusion, args.env);
|
|
51
|
-
return render(el, Component);
|
|
52
|
-
};
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
export default renderComponent;
|
package/src/routing/index.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Routing sub-path entry-point for `@equinor/fusion-framework-react-app`.
|
|
3
|
-
*
|
|
4
|
-
* Re-exports the full public API of `@equinor/fusion-framework-react-router`
|
|
5
|
-
* and its route builder DSL so consumers can import all routing primitives
|
|
6
|
-
* from a single entry point without adding a separate direct dependency.
|
|
7
|
-
*
|
|
8
|
-
* Requires `@equinor/fusion-framework-react-router` to be installed.
|
|
9
|
-
* It is declared as an optional peer dependency — install it only when
|
|
10
|
-
* you need routing in your app, portal, or widget.
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* ```ts
|
|
14
|
-
* import { Router } from '@equinor/fusion-framework-react-app/routing';
|
|
15
|
-
* import { layout, index, route } from '@equinor/fusion-framework-react-app/routing';
|
|
16
|
-
* ```
|
|
17
|
-
*
|
|
18
|
-
* @packageDocumentation
|
|
19
|
-
*/
|
|
20
|
-
export * from '@equinor/fusion-framework-react-router';
|
|
21
|
-
// Explicit re-exports from /routes so the DSL `Route` class takes precedence
|
|
22
|
-
// over the deprecated react-router `Route` component from the main entry.
|
|
23
|
-
export {
|
|
24
|
-
index,
|
|
25
|
-
IndexRoute,
|
|
26
|
-
route,
|
|
27
|
-
Route,
|
|
28
|
-
layout,
|
|
29
|
-
LayoutRoute,
|
|
30
|
-
prefix,
|
|
31
|
-
PrefixRoute,
|
|
32
|
-
} from '@equinor/fusion-framework-react-router/routes';
|
|
33
|
-
export type { RouteSchemaEntry } from '@equinor/fusion-framework-react-router/routes';
|
package/src/settings/README.md
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
## Portal Settings
|
|
2
|
-
|
|
3
|
-
> TBD
|
|
4
|
-
|
|
5
|
-
## App Settings
|
|
6
|
-
|
|
7
|
-
App settings are a way to store and retrieve settings that are shared across the app. The settings are stored in the configured service of the app module.
|
|
8
|
-
|
|
9
|
-
```ts
|
|
10
|
-
declare module '@equinor/fusion-framework-react-app/settings' {
|
|
11
|
-
interface AppSettings {
|
|
12
|
-
theme: 'default' | 'light' | 'dark';
|
|
13
|
-
mode: 'simple' | 'advanced';
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
useAppSetting('theme', 'default');
|
|
17
|
-
|
|
18
|
-
// Explicit type the setting
|
|
19
|
-
useAppSetting<{notDefined: string}>('notDefined', 'not registered');
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
### Example
|
|
23
|
-
|
|
24
|
-
```tsx
|
|
25
|
-
const MyApp = () => {
|
|
26
|
-
const [ theme, setTheme ] = useAppSetting('theme', 'default');
|
|
27
|
-
const [ mode, setMode ] = useAppSetting('mode', 'simple');
|
|
28
|
-
|
|
29
|
-
// using the setter as a callback
|
|
30
|
-
const toggleMode = useCallback(() => {
|
|
31
|
-
setMode(mode => mode === 'simple' ? 'advanced' : 'simple')
|
|
32
|
-
}, [setMode]);
|
|
33
|
-
|
|
34
|
-
return (
|
|
35
|
-
<MyThemeProvider theme={theme} onChange={setTheme}>
|
|
36
|
-
<Button onClick={toggleMode}>Toggle mode</Button>
|
|
37
|
-
{mode === 'simple' ? <SimpleView /> : <AdvancedView />}
|
|
38
|
-
</MyThemeProvider>
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
### Using all settings
|
|
44
|
-
|
|
45
|
-
> [!WARNING]
|
|
46
|
-
> **Using the `setSettings` must include all settings, not just the ones you want to change.**
|
|
47
|
-
> prefer using `setSettings` with a callback function.
|
|
48
|
-
|
|
49
|
-
> [!IMPORTANT]
|
|
50
|
-
> This is not recommended for large apps, as it will cause re-renders on every setting change.
|
|
51
|
-
|
|
52
|
-
```tsx
|
|
53
|
-
const MyApp = () => {
|
|
54
|
-
const [ settings, setSettings ] = useAppSettings();
|
|
55
|
-
|
|
56
|
-
const updateTheme = useCallback(
|
|
57
|
-
(theme: AppSettings['theme']) => setSettings(settings => ({...settings, theme})),
|
|
58
|
-
[updateSettings]
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
return (
|
|
62
|
-
<MyThemeProvider theme={settings.theme} onChange={updateTheme}>
|
|
63
|
-
{settings.mode === 'simple' ? <SimpleView /> : <AdvancedView />}
|
|
64
|
-
</MyThemeProvider>
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### Using hook callbacks
|
|
70
|
-
|
|
71
|
-
The `useAppSettings` and `useAppSetting` hooks can take callbacks for loading, updating, updated and error handling.
|
|
72
|
-
|
|
73
|
-
> [!NOTE]
|
|
74
|
-
> These callbacks are optional and can be used to show loading spinners, error dialogs or other UI elements.
|
|
75
|
-
>
|
|
76
|
-
> We have chosen to use callbacks as parameters to the hooks, instead of returning them, to avoid unnecessary re-renders.
|
|
77
|
-
|
|
78
|
-
> [!NOTE]
|
|
79
|
-
> `onUpdating` and `onLoading` refers to the global state of the settings, not the individual settings. This means that if you have multiple settings that are being updated, the `onUpdating` and `onLoading` will be true until all settings are updated.
|
|
80
|
-
>
|
|
81
|
-
> Good practice is to disable UI elements that can trigger settings updates when `onUpdating` or `onLoading` is true.
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
> [!IMPORTANT]
|
|
85
|
-
> Hooks must be memoized to avoid re-renders on every render. Provided callbacks are not internally memoized, to allow consumers to control implementation of these callbacks.
|
|
86
|
-
|
|
87
|
-
```tsx
|
|
88
|
-
|
|
89
|
-
// state and callback for loading settings
|
|
90
|
-
const [ loading, setLoading ] = useState(false);
|
|
91
|
-
|
|
92
|
-
// state and callback for updating settings
|
|
93
|
-
const [ updating, setUpdating ] = useState(false);
|
|
94
|
-
|
|
95
|
-
// state and callback for error handling
|
|
96
|
-
const [ error, setError ] = useState<Error | null>(null);
|
|
97
|
-
|
|
98
|
-
// callback for when settings are updated
|
|
99
|
-
const onUpdated = useCallback(() => {
|
|
100
|
-
showSnackbar('Settings updated');
|
|
101
|
-
}, [showSnackbar]);
|
|
102
|
-
|
|
103
|
-
const [ settings, setSettings ] = useAppSettings(defaultSettings, {
|
|
104
|
-
onLoading: setLoading,
|
|
105
|
-
onUpdating: setUpdating,
|
|
106
|
-
onError: setError,
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
const updateSettings = useCallback(() => {
|
|
110
|
-
setSettings(/* new settings */);
|
|
111
|
-
}, [setSettings, onUpdated]);
|
|
112
|
-
|
|
113
|
-
return (
|
|
114
|
-
<MyThemeProvider theme={settings.theme}>
|
|
115
|
-
{loading && <Loading />}
|
|
116
|
-
{updating && <Updating />}
|
|
117
|
-
{error && <ErrorDialog error={error} />}
|
|
118
|
-
<Button onClick={updateSettings} disabled={loading||updating}>
|
|
119
|
-
Update settings
|
|
120
|
-
</Button>
|
|
121
|
-
</MyThemeProvider>
|
|
122
|
-
);
|
|
123
|
-
```
|
package/src/settings/index.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Settings sub-path entry-point.
|
|
3
|
-
*
|
|
4
|
-
* Provides hooks for reading and updating per-application user settings
|
|
5
|
-
* that are persisted by the Fusion platform.
|
|
6
|
-
*
|
|
7
|
-
* @packageDocumentation
|
|
8
|
-
*/
|
|
9
|
-
export { useAppSetting } from './useAppSetting';
|
|
10
|
-
export { useAppSettings } from './useAppSettings';
|
|
11
|
-
|
|
12
|
-
export type { AppSettings } from '@equinor/fusion-framework-module-app';
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
|
2
|
-
import { BehaviorSubject, map } from 'rxjs';
|
|
3
|
-
|
|
4
|
-
import { useCurrentApp } from '@equinor/fusion-framework-react/app';
|
|
5
|
-
|
|
6
|
-
import { useAppSettingsStatus, type AppSettingsStatusHooks } from './useAppSettingsStatus';
|
|
7
|
-
|
|
8
|
-
import type { AppSettings } from '@equinor/fusion-framework-module-app';
|
|
9
|
-
import { useObservableState } from '@equinor/fusion-observable/react';
|
|
10
|
-
|
|
11
|
-
type UpdateSettingFunction<T, O = T> = (currentSetting: T | undefined) => O;
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Custom hook to manage application settings.
|
|
15
|
-
*
|
|
16
|
-
* @template TSettings - The type of the settings object. Defaults to `AppSettings`.
|
|
17
|
-
* @template TProp - The type of the property key in the settings object. Defaults to `keyof TSettings`.
|
|
18
|
-
*
|
|
19
|
-
* @param {TProp} prop - The property key in the settings object to manage.
|
|
20
|
-
* @param {TSettings[TProp]} [defaultValue] - The default value for the setting.
|
|
21
|
-
* @param hooks - Optional hooks to handle the status changes and errors.
|
|
22
|
-
*
|
|
23
|
-
* @returns {Array} An array containing:
|
|
24
|
-
* - `setting`: The current setting value or undefined.
|
|
25
|
-
* - `setSetting`: A function to update the setting.
|
|
26
|
-
*
|
|
27
|
-
* @example
|
|
28
|
-
* const { setting, setSetting } = useAppSetting('theme');
|
|
29
|
-
*
|
|
30
|
-
* @example
|
|
31
|
-
* // with default value
|
|
32
|
-
* const { setting, setSetting } = useAppSetting('theme', 'dark');
|
|
33
|
-
*
|
|
34
|
-
* @example
|
|
35
|
-
* // with hooks
|
|
36
|
-
* const [isLoading, setIsLoading] = useState(false);
|
|
37
|
-
* const [isUpdating, setIsUpdating] = useState(false);
|
|
38
|
-
* const [error, setError] = useState<Error | null>(null);
|
|
39
|
-
*
|
|
40
|
-
* const { setting, setSetting } = useAppSetting('theme', 'dark', {
|
|
41
|
-
* onLoading: setIsLoading,
|
|
42
|
-
* onUpdating: setIsUpdating,
|
|
43
|
-
* onError: setError,
|
|
44
|
-
* onUpdated: useCallback(() => console.log('Settings updated'), [])
|
|
45
|
-
* });
|
|
46
|
-
*/
|
|
47
|
-
export const useAppSetting = <
|
|
48
|
-
TSettings extends Record<string, unknown> = AppSettings,
|
|
49
|
-
TProp extends keyof TSettings = keyof TSettings,
|
|
50
|
-
>(
|
|
51
|
-
prop: TProp,
|
|
52
|
-
defaultValue?: TSettings[TProp],
|
|
53
|
-
hooks?: AppSettingsStatusHooks & {
|
|
54
|
-
onError?: (error: Error | null) => void;
|
|
55
|
-
onUpdated?: () => void;
|
|
56
|
-
},
|
|
57
|
-
): [
|
|
58
|
-
TSettings[TProp] | undefined,
|
|
59
|
-
(update: TSettings[TProp] | UpdateSettingFunction<TSettings[TProp]>) => void,
|
|
60
|
-
] => {
|
|
61
|
-
const [{ onError, onUpdated, onLoading, onUpdating }] = useState(() => hooks ?? {});
|
|
62
|
-
|
|
63
|
-
const { currentApp = null } = useCurrentApp();
|
|
64
|
-
|
|
65
|
-
// create a subject to manage the setting value
|
|
66
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies: new subject when app changes
|
|
67
|
-
const subject = useMemo(() => {
|
|
68
|
-
return new BehaviorSubject<TSettings[TProp] | undefined>(defaultValue);
|
|
69
|
-
}, [currentApp]);
|
|
70
|
-
|
|
71
|
-
useLayoutEffect(() => {
|
|
72
|
-
// Narrow the settings stream down to just this specific setting's value
|
|
73
|
-
const sub = currentApp?.settings$
|
|
74
|
-
.pipe(map((settings) => (settings as TSettings)[prop]))
|
|
75
|
-
.subscribe(subject);
|
|
76
|
-
return () => sub?.unsubscribe();
|
|
77
|
-
}, [currentApp, subject, prop]);
|
|
78
|
-
|
|
79
|
-
// subscribe to the setting value
|
|
80
|
-
const { value: setting } = useObservableState(subject);
|
|
81
|
-
|
|
82
|
-
// update function
|
|
83
|
-
const setSetting = useCallback(
|
|
84
|
-
(update: TSettings[TProp] | UpdateSettingFunction<TSettings[TProp]>) => {
|
|
85
|
-
// Cannot persist a setting update without a current app to write it to
|
|
86
|
-
if (!currentApp) {
|
|
87
|
-
return onError?.(new Error('App is not available'));
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// resolve setting value with the provided value or function
|
|
91
|
-
const value =
|
|
92
|
-
typeof update === 'function'
|
|
93
|
-
? (update as UpdateSettingFunction<TSettings[TProp]>)(subject.value)
|
|
94
|
-
: update;
|
|
95
|
-
|
|
96
|
-
currentApp.updateSetting<TSettings, TProp>(prop, value).subscribe({
|
|
97
|
-
error: onError,
|
|
98
|
-
complete: onUpdated,
|
|
99
|
-
});
|
|
100
|
-
},
|
|
101
|
-
[currentApp, subject, prop, onError, onUpdated],
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
// status hooks
|
|
105
|
-
useAppSettingsStatus(currentApp, {
|
|
106
|
-
onLoading,
|
|
107
|
-
onUpdating,
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
return [setting, setSetting];
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
export default useAppSetting;
|