@equinor/fusion-framework-react-app 10.0.8 → 11.0.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/CHANGELOG.md +51 -0
- package/dist/esm/routing/index.js +24 -0
- package/dist/esm/routing/index.js.map +1 -0
- package/dist/esm/version.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/create-legacy-app.d.ts +1 -1
- package/dist/types/routing/index.d.ts +22 -0
- package/dist/types/version.d.ts +1 -1
- package/docs/analytics.md +122 -0
- package/docs/app.md +148 -0
- package/docs/apploader.md +110 -0
- package/docs/bookmark.md +101 -0
- package/docs/context.md +86 -0
- package/docs/framework.md +93 -0
- package/docs/help-center.md +88 -0
- package/docs/http.md +118 -0
- package/docs/routing.md +86 -0
- package/package.json +23 -11
- package/src/apploader/README.md +3 -0
- package/src/routing/index.ts +33 -0
- package/src/version.ts +1 -1
|
@@ -14,4 +14,4 @@ import type { AppModuleInitiator } from '@equinor/fusion-framework-app';
|
|
|
14
14
|
* @param configure - Optional callback to configure application modules.
|
|
15
15
|
* @returns A React function component that initialises modules and renders the app.
|
|
16
16
|
*/
|
|
17
|
-
export declare const createLegacyApp: <TModules extends Array<AnyModule>>(Component: ElementType, configure?: AppModuleInitiator<TModules>) => () => import("react
|
|
17
|
+
export declare const createLegacyApp: <TModules extends Array<AnyModule>>(Component: ElementType, configure?: AppModuleInitiator<TModules>) => () => import("react").JSX.Element;
|
|
@@ -0,0 +1,22 @@
|
|
|
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
|
+
export { index, IndexRoute, route, Route, layout, LayoutRoute, prefix, PrefixRoute, } from '@equinor/fusion-framework-react-router/routes';
|
|
22
|
+
export type { RouteSchemaEntry } from '@equinor/fusion-framework-react-router/routes';
|
package/dist/types/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "
|
|
1
|
+
export declare const version = "11.0.0";
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Analytics
|
|
2
|
+
|
|
3
|
+
React hooks for tracking application feature usage through the Fusion analytics module.
|
|
4
|
+
|
|
5
|
+
**Import:**
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { useTrackFeature } from '@equinor/fusion-framework-react-app/analytics';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
The analytics module is enabled and configured by the hosting portal, so **apps running inside a Fusion portal can use these hooks immediately without any runtime setup**.
|
|
12
|
+
|
|
13
|
+
> [!IMPORTANT]
|
|
14
|
+
> `useTrackFeature` accepts an `AnyValueMap` type parameter from `@equinor/fusion-framework-module-analytics`. This package is a `devDependency` of `@equinor/fusion-framework-react-app`, so **no runtime installation is needed** when running inside a Fusion portal. However, if your app imports `AnyValueMap` directly for typing, you may need to add `@equinor/fusion-framework-module-analytics` as a `devDependency` in your own project for TypeScript to resolve the type.
|
|
15
|
+
|
|
16
|
+
## When to Track
|
|
17
|
+
|
|
18
|
+
Use `useTrackFeature` when you want to record a discrete user action or application milestone. Focus on actions that answer a question about user behavior or feature value — you do not need to track every click.
|
|
19
|
+
|
|
20
|
+
> [!NOTE]
|
|
21
|
+
> The `name` argument you pass to the tracking callback becomes `value.feature` in the analytics event. The emitted analytics event always has `name: 'app-feature'` — the `name` you supply is the **feature name**, not the analytics event name.
|
|
22
|
+
|
|
23
|
+
| Use case | What to track | Example feature name |
|
|
24
|
+
| ----------------------- | ---------------------------------------- | ---------------------------- |
|
|
25
|
+
| Button or action clicks | User triggers a specific workflow | `'export-clicked'` |
|
|
26
|
+
| Page or component views | A section of the app is displayed | `'dashboard-loaded'` |
|
|
27
|
+
| Feature gate checks | A feature behind a flag is accessed | `'beta-feature-used'` |
|
|
28
|
+
| Form submissions | A user completes a form or wizard step | `'report-submitted'` |
|
|
29
|
+
| Error recovery actions | A user retries or dismisses an error | `'retry-clicked'` |
|
|
30
|
+
|
|
31
|
+
## useTrackFeature
|
|
32
|
+
|
|
33
|
+
Returns a stable callback for tracking feature usage events. Each event automatically includes the current app key and active context as attributes, so downstream dashboards can group events by application and context without extra work.
|
|
34
|
+
|
|
35
|
+
**Signature:**
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
function useTrackFeature(): (name: string, data?: AnyValueMap) => void;
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
| Parameter | Type | Description |
|
|
42
|
+
| --------- | -------------------------- | -------------------------------------------- |
|
|
43
|
+
| `name` | `string` | Name of the feature being tracked |
|
|
44
|
+
| `data` | `AnyValueMap` _(optional)_ | Additional key-value pairs included with the event |
|
|
45
|
+
|
|
46
|
+
### Track a Button Click
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
import { useCallback } from 'react';
|
|
50
|
+
import { useTrackFeature } from '@equinor/fusion-framework-react-app/analytics';
|
|
51
|
+
|
|
52
|
+
const MyButton = () => {
|
|
53
|
+
const trackFeature = useTrackFeature();
|
|
54
|
+
|
|
55
|
+
const handleClick = useCallback(() => {
|
|
56
|
+
trackFeature('button-clicked');
|
|
57
|
+
}, [trackFeature]);
|
|
58
|
+
|
|
59
|
+
return <button onClick={handleClick}>Click me</button>;
|
|
60
|
+
};
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Track with Additional Data
|
|
64
|
+
|
|
65
|
+
Pass a second argument to include custom attributes with the event:
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
import { useCallback } from 'react';
|
|
69
|
+
import { useTrackFeature } from '@equinor/fusion-framework-react-app/analytics';
|
|
70
|
+
|
|
71
|
+
const SaveButton = ({ section }: { section: string }) => {
|
|
72
|
+
const trackFeature = useTrackFeature();
|
|
73
|
+
|
|
74
|
+
const handleSave = useCallback(() => {
|
|
75
|
+
trackFeature('save-clicked', { section, timestamp: Date.now() });
|
|
76
|
+
}, [trackFeature, section]);
|
|
77
|
+
|
|
78
|
+
return <button onClick={handleSave}>Save</button>;
|
|
79
|
+
};
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Track on Component Mount
|
|
83
|
+
|
|
84
|
+
Use `useEffect` to track when a component or page loads:
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
import { useEffect } from 'react';
|
|
88
|
+
import { useTrackFeature } from '@equinor/fusion-framework-react-app/analytics';
|
|
89
|
+
|
|
90
|
+
const Dashboard = () => {
|
|
91
|
+
const trackFeature = useTrackFeature();
|
|
92
|
+
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
trackFeature('dashboard-loaded');
|
|
95
|
+
}, [trackFeature]);
|
|
96
|
+
|
|
97
|
+
return <div>Dashboard content</div>;
|
|
98
|
+
};
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Prerequisites
|
|
102
|
+
|
|
103
|
+
The analytics module must be enabled for the hook to work. **In most cases, no app-level configuration is needed** — the hosting Fusion portal already enables and configures analytics. Your app inherits this automatically.
|
|
104
|
+
|
|
105
|
+
If the module is not available (e.g. in a standalone or custom portal setup), `useTrackFeature` logs an exception via the telemetry provider instead of throwing, so your app will not crash.
|
|
106
|
+
|
|
107
|
+
### Custom or Standalone Setups
|
|
108
|
+
|
|
109
|
+
If you are building a custom portal or running outside the standard Fusion portal, enable the analytics module yourself:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
import { enableAnalytics } from '@equinor/fusion-framework-module-analytics';
|
|
113
|
+
import { ConsoleAnalyticsAdapter } from '@equinor/fusion-framework-module-analytics/adapters';
|
|
114
|
+
|
|
115
|
+
const configure = (configurator) => {
|
|
116
|
+
enableAnalytics(configurator, (builder) => {
|
|
117
|
+
builder.setAdapter('console', async () => new ConsoleAnalyticsAdapter());
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
See the [analytics module documentation](https://equinor.github.io/fusion-framework/modules/analytics/) for adapter and collector setup.
|
package/docs/app.md
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# App (Root Entry Point)
|
|
2
|
+
|
|
3
|
+
Core bootstrapping and module access hooks for Fusion React applications.
|
|
4
|
+
|
|
5
|
+
**Import:**
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { renderApp, useAppModule, useAppModules, useAppEnvironmentVariables } from '@equinor/fusion-framework-react-app';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## renderApp
|
|
12
|
+
|
|
13
|
+
The standard bootstrap function for Fusion React apps. Wraps your root component and an optional configuration callback into a render function that the Fusion portal calls to mount your app.
|
|
14
|
+
|
|
15
|
+
**Signature:**
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
function renderApp(
|
|
19
|
+
Component: React.ElementType,
|
|
20
|
+
configure?: AppModuleInitiator,
|
|
21
|
+
): (el: HTMLElement, args: ComponentRenderArgs) => RenderTeardown;
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`AppModuleInitiator` receives `(configurator, { fusion, env })` and may return `Promise<void>` for async setup.
|
|
25
|
+
|
|
26
|
+
**Returns:** A mount function the portal calls with a DOM element and render args. The returned `RenderTeardown` callback unmounts the app.
|
|
27
|
+
|
|
28
|
+
### How to Use
|
|
29
|
+
|
|
30
|
+
Export `renderApp` as your app's `render` entrypoint:
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
// main.ts
|
|
34
|
+
import { renderApp } from '@equinor/fusion-framework-react-app';
|
|
35
|
+
import { App } from './App';
|
|
36
|
+
import { configure } from './config';
|
|
37
|
+
|
|
38
|
+
export const render = renderApp(App, configure);
|
|
39
|
+
export default render;
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The `configure` callback is an `AppModuleInitiator` — it receives `(configurator, { fusion, env })` and may be async:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
// config.ts
|
|
46
|
+
import type { AppModuleInitiator } from '@equinor/fusion-framework-react-app';
|
|
47
|
+
|
|
48
|
+
export const configure: AppModuleInitiator = (configurator) => {
|
|
49
|
+
configurator.configureHttpClient('my-api', {
|
|
50
|
+
baseUri: 'https://api.example.com',
|
|
51
|
+
defaultScopes: ['api://my-api/.default'],
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## useAppModule
|
|
57
|
+
|
|
58
|
+
Retrieves a single typed module instance from the application scope. Throws if the module is not registered.
|
|
59
|
+
|
|
60
|
+
**Signature:**
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
// Key-based inference (no explicit generic needed for known modules):
|
|
64
|
+
function useAppModule(module: 'auth' | 'context' | ...): InferredModuleType;
|
|
65
|
+
|
|
66
|
+
// Explicit generic for custom/unknown module keys:
|
|
67
|
+
function useAppModule<TType extends AnyModule>(module: string): ModuleType<TType>;
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
When called with a known string literal key (e.g. `'auth'`), the return type is inferred automatically. Pass an explicit generic only when using a custom or unrecognised key.
|
|
71
|
+
|
|
72
|
+
**Example:**
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
import { useAppModule } from '@equinor/fusion-framework-react-app';
|
|
76
|
+
|
|
77
|
+
const MyComponent = () => {
|
|
78
|
+
const auth = useAppModule('auth');
|
|
79
|
+
// auth is typed based on the registered module
|
|
80
|
+
return <button onClick={() => auth.acquireAccessToken()}>Get token</button>;
|
|
81
|
+
};
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## useAppModules
|
|
85
|
+
|
|
86
|
+
Returns the full set of initialised application-scoped modules. Use this when you need to inspect or access multiple modules at once — prefer `useAppModule` for single-module access.
|
|
87
|
+
|
|
88
|
+
**Signature:**
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
function useAppModules<T>(): AppModulesInstance<T>;
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**Example:**
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
import { useAppModules } from '@equinor/fusion-framework-react-app';
|
|
98
|
+
|
|
99
|
+
const DebugPanel = () => {
|
|
100
|
+
const modules = useAppModules();
|
|
101
|
+
return <pre>{Object.keys(modules).join(', ')}</pre>;
|
|
102
|
+
};
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## useAppEnvironmentVariables
|
|
106
|
+
|
|
107
|
+
Returns the app's environment variables as an observable state. The value is loaded asynchronously from the app configuration, so you should handle `complete` and `error` states.
|
|
108
|
+
|
|
109
|
+
**Signature:**
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
function useAppEnvironmentVariables<TEnvironmentVariables>(): ObservableStateReturnType<TEnvironmentVariables>;
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Returns:**
|
|
116
|
+
|
|
117
|
+
| Property | Type | Description |
|
|
118
|
+
| ---------- | ---------------------------- | ---------------------------------------------------- |
|
|
119
|
+
| `value` | `TEnvironmentVariables \| undefined` | The resolved environment variables, or `undefined` before the observable emits |
|
|
120
|
+
| `complete` | `boolean` | `true` when loading is finished |
|
|
121
|
+
| `error` | `unknown \| null` | Error if loading failed, `null` otherwise |
|
|
122
|
+
|
|
123
|
+
**Example:**
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
import { useAppEnvironmentVariables } from '@equinor/fusion-framework-react-app';
|
|
127
|
+
|
|
128
|
+
type MyEnv = {
|
|
129
|
+
apiUrl: string;
|
|
130
|
+
featureFlags: Record<string, boolean>;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const MyComponent = () => {
|
|
134
|
+
const env = useAppEnvironmentVariables<MyEnv>();
|
|
135
|
+
|
|
136
|
+
if (!env.complete) return <p>Loading environment…</p>;
|
|
137
|
+
if (env.error) return <p>Failed to load environment</p>;
|
|
138
|
+
|
|
139
|
+
return <p>API URL: {env.value.apiUrl}</p>;
|
|
140
|
+
};
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Deprecated APIs
|
|
144
|
+
|
|
145
|
+
> [!CAUTION]
|
|
146
|
+
> `createComponent` is **deprecated**. Use `renderApp` instead.
|
|
147
|
+
|
|
148
|
+
These older bootstrapping functions are still exported for backward compatibility but should not be used in new apps.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Apploader
|
|
2
|
+
|
|
3
|
+
Embed a Fusion child application inside a parent Fusion application using the `Apploader` component or `useApploader` hook.
|
|
4
|
+
|
|
5
|
+
> [!WARNING]
|
|
6
|
+
> **Experimental / Proof of Concept**
|
|
7
|
+
>
|
|
8
|
+
> The embedded application will likely have issues with routing, context, and other framework features.
|
|
9
|
+
> Use this only for embedding simple applications such as **PowerBI** or **PowerApps** viewers.
|
|
10
|
+
|
|
11
|
+
**Import:**
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { Apploader, useApploader } from '@equinor/fusion-framework-react-app/apploader';
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## When to Use
|
|
18
|
+
|
|
19
|
+
Use apploader when your Fusion app needs to render another Fusion app inline — for example, embedding a PowerBI report viewer inside a dashboard app. For complex child apps that need their own routing or context module, this approach is not suitable.
|
|
20
|
+
|
|
21
|
+
## Apploader Component
|
|
22
|
+
|
|
23
|
+
The `Apploader` component is the simplest way to embed a child app. It handles loading and error states automatically and mounts the child app's DOM element into a container `div`.
|
|
24
|
+
|
|
25
|
+
**Signature:**
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
function Apploader(props: ApploaderProps): ReactElement;
|
|
29
|
+
|
|
30
|
+
type ApploaderProps = {
|
|
31
|
+
/** The app key identifying the Fusion app to load and mount */
|
|
32
|
+
appKey: string;
|
|
33
|
+
};
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Example:**
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
import { Apploader } from '@equinor/fusion-framework-react-app/apploader';
|
|
40
|
+
|
|
41
|
+
const Dashboard = () => {
|
|
42
|
+
return (
|
|
43
|
+
<section>
|
|
44
|
+
<h2>Embedded Report</h2>
|
|
45
|
+
<Apploader appKey="my-powerbi-app" />
|
|
46
|
+
</section>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The component renders:
|
|
52
|
+
|
|
53
|
+
- `"Loading {appKey}"` while the child app is being fetched and initialized
|
|
54
|
+
- `"Error loading {appKey}. Error: {message}"` if initialization fails
|
|
55
|
+
- The child app's DOM tree once loaded
|
|
56
|
+
|
|
57
|
+
## useApploader Hook
|
|
58
|
+
|
|
59
|
+
Use the `useApploader` hook when you need custom loading or error UI, or when you want more control over how the child app's DOM element is mounted.
|
|
60
|
+
|
|
61
|
+
**Signature:**
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
function useApploader(params: { appKey: string }): {
|
|
65
|
+
loading: boolean;
|
|
66
|
+
error: Error | undefined;
|
|
67
|
+
appRef: React.RefObject<HTMLDivElement | null>;
|
|
68
|
+
};
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Parameters:**
|
|
72
|
+
|
|
73
|
+
- `appKey` — the key of the Fusion app to load and mount
|
|
74
|
+
|
|
75
|
+
**Returns:**
|
|
76
|
+
|
|
77
|
+
| Property | Type | Description |
|
|
78
|
+
| --------- | --------------------------------------- | ------------------------------------------------ |
|
|
79
|
+
| `loading` | `boolean` | `true` while the app is loading |
|
|
80
|
+
| `error` | `Error \| undefined` | Error object if loading fails, otherwise `undefined` |
|
|
81
|
+
| `appRef` | `React.RefObject<HTMLDivElement \| null>` | Ref to the DOM element where the child app is mounted |
|
|
82
|
+
|
|
83
|
+
**Example:**
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
import { useApploader } from '@equinor/fusion-framework-react-app/apploader';
|
|
87
|
+
import { useEffect, useRef } from 'react';
|
|
88
|
+
|
|
89
|
+
const CustomAppEmbed = ({ appKey }: { appKey: string }) => {
|
|
90
|
+
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
91
|
+
const { loading, error, appRef } = useApploader({ appKey });
|
|
92
|
+
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
if (containerRef.current && appRef.current) {
|
|
95
|
+
containerRef.current.appendChild(appRef.current);
|
|
96
|
+
}
|
|
97
|
+
}, [appRef.current]);
|
|
98
|
+
|
|
99
|
+
if (loading) return <p>Loading application…</p>;
|
|
100
|
+
if (error) return <p>Failed to load: {error.message}</p>;
|
|
101
|
+
|
|
102
|
+
return <div ref={containerRef} />;
|
|
103
|
+
};
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Limitations
|
|
107
|
+
|
|
108
|
+
- **Routing:** The child app shares the parent's URL space. Deep-linking and navigation inside the embedded app may conflict with the parent's router.
|
|
109
|
+
- **Context:** The child app receives the parent's framework instance but does not get its own isolated context module.
|
|
110
|
+
- **Scope:** Best suited for simple, self-contained apps (e.g., PowerBI, PowerApps). Complex apps with their own routing or context configuration are not supported.
|
package/docs/bookmark.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Bookmark
|
|
2
|
+
|
|
3
|
+
Save and restore application state snapshots using the Fusion bookmark module.
|
|
4
|
+
|
|
5
|
+
**Import:**
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { useCurrentBookmark, enableBookmark } from '@equinor/fusion-framework-react-app/bookmark';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
Bookmarks let users save the current state of your app (filters, selections, active views) and restore it later. The `useCurrentBookmark` hook is the primary API for app developers — it reads the active bookmark and lets you provide a callback that captures your app's current state when a bookmark is created.
|
|
14
|
+
|
|
15
|
+
## Enable Bookmarks
|
|
16
|
+
|
|
17
|
+
Register the bookmark module in your app's configuration:
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { enableBookmark } from '@equinor/fusion-framework-react-app/bookmark';
|
|
21
|
+
|
|
22
|
+
export const configure = (configurator) => {
|
|
23
|
+
enableBookmark(configurator);
|
|
24
|
+
};
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## useCurrentBookmark
|
|
28
|
+
|
|
29
|
+
The recommended hook for working with bookmarks in your app. Returns the current bookmark (if any) and a setter, filtered to only show bookmarks belonging to your app.
|
|
30
|
+
|
|
31
|
+
**Signature:**
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
function useCurrentBookmark<TData extends BookmarkData>(
|
|
35
|
+
payloadGenerator?: BookmarkPayloadGenerator<TData>,
|
|
36
|
+
): {
|
|
37
|
+
currentBookmark: Bookmark<TData> | null;
|
|
38
|
+
setCurrentBookmark: (bookmark_or_id: Bookmark | string | null) => VoidFunction;
|
|
39
|
+
};
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
| Parameter | Type | Description |
|
|
43
|
+
| ------------------ | ----------------------------------- | -------------------------------------------------------------- |
|
|
44
|
+
| `payloadGenerator` | `BookmarkPayloadGenerator<TData>` _(optional)_ | Callback that returns the current app state to store in the bookmark. **Must be wrapped in `useCallback`.** |
|
|
45
|
+
|
|
46
|
+
### Basic Usage
|
|
47
|
+
|
|
48
|
+
Provide a `payloadGenerator` wrapped in `useCallback` to capture your app state when a bookmark is created:
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
import { useCallback, useState } from 'react';
|
|
52
|
+
import { useCurrentBookmark } from '@equinor/fusion-framework-react-app/bookmark';
|
|
53
|
+
|
|
54
|
+
type MyBookmarkData = {
|
|
55
|
+
selectedFilter: string;
|
|
56
|
+
activeTab: number;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const MyApp = () => {
|
|
60
|
+
const [filter, setFilter] = useState('all');
|
|
61
|
+
const [tab, setTab] = useState(0);
|
|
62
|
+
|
|
63
|
+
const { currentBookmark } = useCurrentBookmark<MyBookmarkData>(
|
|
64
|
+
useCallback(() => ({
|
|
65
|
+
selectedFilter: filter,
|
|
66
|
+
activeTab: tab,
|
|
67
|
+
}), [filter, tab])
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
// Restore state from bookmark when it changes
|
|
71
|
+
// currentBookmark is null when no bookmark is active or the bookmark belongs to a different app
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<div>
|
|
75
|
+
<p>Active bookmark: {currentBookmark?.name ?? 'None'}</p>
|
|
76
|
+
</div>
|
|
77
|
+
);
|
|
78
|
+
};
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## useBookmark (Deprecated)
|
|
82
|
+
|
|
83
|
+
> [!CAUTION]
|
|
84
|
+
> `useBookmark` is **deprecated**. Use `useCurrentBookmark` instead.
|
|
85
|
+
|
|
86
|
+
`useBookmark` provides the full bookmark CRUD API (create, update, delete, list). For app development, `useCurrentBookmark` is sufficient — it handles app-scoping automatically and has a simpler interface.
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
// ❌ Deprecated
|
|
90
|
+
import { useBookmark } from '@equinor/fusion-framework-react-app/bookmark';
|
|
91
|
+
|
|
92
|
+
// ✅ Use instead
|
|
93
|
+
import { useCurrentBookmark } from '@equinor/fusion-framework-react-app/bookmark';
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
If you need the full CRUD API, import directly from `@equinor/fusion-framework-react-module-bookmark`.
|
|
97
|
+
|
|
98
|
+
## Prerequisites
|
|
99
|
+
|
|
100
|
+
- The bookmark module must be enabled via `enableBookmark` in the app configurator
|
|
101
|
+
- `@equinor/fusion-framework-react-module-bookmark` must be installed explicitly in your app
|
package/docs/context.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Context
|
|
2
|
+
|
|
3
|
+
Read the currently selected Fusion context (project, facility, etc.) from your app using the app-scoped context hooks.
|
|
4
|
+
|
|
5
|
+
**Import:**
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { useCurrentContext, useContextProvider } from '@equinor/fusion-framework-react-app/context';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
Fusion apps operate within a **context** — typically a project or facility selected by the user in the portal. The `useCurrentContext` hook returns the active context from your app's own context module. If no context is selected, it returns `undefined`.
|
|
14
|
+
|
|
15
|
+
> [!IMPORTANT]
|
|
16
|
+
> **App-scoped vs Framework-scoped context**
|
|
17
|
+
>
|
|
18
|
+
> - `useCurrentContext` (this sub-path) reads from the **app's own context module**. Your app must have the context module enabled.
|
|
19
|
+
> - `useFrameworkCurrentContext` (from `/framework`) reads from the **portal/host-level context**, regardless of whether your app has its own context module.
|
|
20
|
+
>
|
|
21
|
+
> **Prefer `useCurrentContext`** unless you specifically need portal-level context.
|
|
22
|
+
|
|
23
|
+
## useCurrentContext
|
|
24
|
+
|
|
25
|
+
Returns the currently selected context from the application-scoped context module.
|
|
26
|
+
|
|
27
|
+
**Signature:**
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
function useCurrentContext(): {
|
|
31
|
+
currentContext: ContextItem | null | undefined;
|
|
32
|
+
setCurrentContext: (context?: ContextItem | string | null) => void;
|
|
33
|
+
};
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Returns:** An object with the current context (`ContextItem | null | undefined`) and a setter to change it.
|
|
37
|
+
|
|
38
|
+
### Example
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import { useCurrentContext } from '@equinor/fusion-framework-react-app/context';
|
|
42
|
+
|
|
43
|
+
const ProjectHeader = () => {
|
|
44
|
+
const { currentContext } = useCurrentContext();
|
|
45
|
+
|
|
46
|
+
if (!currentContext) {
|
|
47
|
+
return <p>No context selected</p>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<header>
|
|
52
|
+
<h1>{currentContext.title}</h1>
|
|
53
|
+
<span>Type: {currentContext.type.id}</span>
|
|
54
|
+
</header>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## useContextProvider
|
|
60
|
+
|
|
61
|
+
Returns the app-scoped context module provider instance directly. Use this when you need to interact with the context module beyond just reading the current value — for example, querying available contexts or subscribing to context changes.
|
|
62
|
+
|
|
63
|
+
**Signature:**
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
function useContextProvider(): IContextProvider;
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Throws** if the context module is not registered in the application scope.
|
|
70
|
+
|
|
71
|
+
### Example
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
import { useContextProvider } from '@equinor/fusion-framework-react-app/context';
|
|
75
|
+
|
|
76
|
+
const ContextDebug = () => {
|
|
77
|
+
const contextProvider = useContextProvider();
|
|
78
|
+
// Access the full provider API
|
|
79
|
+
return <pre>{JSON.stringify(contextProvider.currentContext, null, 2)}</pre>;
|
|
80
|
+
};
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Prerequisites
|
|
84
|
+
|
|
85
|
+
- The context module must be enabled in your app's configurator
|
|
86
|
+
- The `useFrameworkCurrentContext` hook is also re-exported from this sub-path for convenience — see the [framework docs](./framework.md) for details
|