@equinor/fusion-framework-module-bookmark 3.0.6 → 4.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 +30 -18
- package/README.md +156 -255
- package/dist/esm/BookmarkClient.js +10 -0
- package/dist/esm/BookmarkClient.js.map +1 -1
- package/dist/esm/BookmarkConfigurator.js +8 -1
- package/dist/esm/BookmarkConfigurator.js.map +1 -1
- package/dist/esm/BookmarkProvider.error.js +17 -1
- package/dist/esm/BookmarkProvider.error.js.map +1 -1
- package/dist/esm/BookmarkProvider.selectors.js +14 -7
- package/dist/esm/BookmarkProvider.selectors.js.map +1 -1
- package/dist/esm/BookmarkProvider.store.js +6 -5
- package/dist/esm/BookmarkProvider.store.js.map +1 -1
- package/dist/esm/bookmark-config.schema.js +13 -0
- package/dist/esm/bookmark-config.schema.js.map +1 -1
- package/dist/esm/bookmark-module.js +16 -0
- package/dist/esm/bookmark-module.js.map +1 -1
- package/dist/esm/bookmark.schemas.js +22 -0
- package/dist/esm/bookmark.schemas.js.map +1 -1
- package/dist/esm/enable-bookmark.js +21 -3
- package/dist/esm/enable-bookmark.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/BookmarkClient.d.ts +10 -0
- package/dist/types/BookmarkConfigurator.d.ts +8 -1
- package/dist/types/BookmarkProvider.actions.d.ts +1 -0
- package/dist/types/BookmarkProvider.error.d.ts +18 -1
- package/dist/types/BookmarkProvider.interface.d.ts +37 -0
- package/dist/types/BookmarkProvider.selectors.d.ts +14 -7
- package/dist/types/BookmarkProvider.store.d.ts +16 -7
- package/dist/types/bookmark-config.schema.d.ts +13 -0
- package/dist/types/bookmark-module.d.ts +23 -0
- package/dist/types/bookmark.schemas.d.ts +22 -0
- package/dist/types/enable-bookmark.d.ts +21 -3
- package/dist/types/version.d.ts +1 -1
- package/package.json +12 -13
- package/src/BookmarkClient.ts +10 -0
- package/src/BookmarkConfigurator.ts +8 -1
- package/src/BookmarkProvider.actions.ts +1 -0
- package/src/BookmarkProvider.error.ts +15 -0
- package/src/BookmarkProvider.interface.ts +37 -0
- package/src/BookmarkProvider.selectors.ts +14 -7
- package/src/BookmarkProvider.store.ts +16 -7
- package/src/bookmark-config.schema.ts +13 -0
- package/src/bookmark-module.ts +23 -0
- package/src/bookmark.schemas.ts +22 -0
- package/src/enable-bookmark.ts +21 -3
- package/src/version.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 4.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- abffa53: Major version bump for Fusion Framework React 19 release.
|
|
8
|
+
|
|
9
|
+
All packages are bumped to the next major version as part of the React 19 upgrade. This release drops support for React versions below 18 and includes breaking changes across the framework.
|
|
10
|
+
|
|
11
|
+
**Breaking changes:**
|
|
12
|
+
- Peer dependencies now require React 18 or 19 (`^18.0.0 || ^19.0.0`)
|
|
13
|
+
- React Router upgraded from v6 to v7
|
|
14
|
+
- Navigation module refactored with new history API
|
|
15
|
+
- `renderComponent` and `renderApp` now use `createRoot` API
|
|
16
|
+
|
|
17
|
+
**Migration:**
|
|
18
|
+
- Update your React version to 18.0.0 or higher before upgrading
|
|
19
|
+
- Replace `NavigationProvider.createRouter()` with `@equinor/fusion-framework-react-router`
|
|
20
|
+
- See individual package changelogs for package-specific migration steps
|
|
21
|
+
|
|
22
|
+
### Patch Changes
|
|
23
|
+
|
|
24
|
+
- Updated dependencies [abffa53]
|
|
25
|
+
- Updated dependencies [abffa53]
|
|
26
|
+
- Updated dependencies [abffa53]
|
|
27
|
+
- Updated dependencies [abffa53]
|
|
28
|
+
- @equinor/fusion-framework-module@6.0.0
|
|
29
|
+
- @equinor/fusion-log@2.0.0
|
|
30
|
+
- @equinor/fusion-observable@9.0.0
|
|
31
|
+
- @equinor/fusion-query@7.0.0
|
|
32
|
+
|
|
3
33
|
## 3.0.6
|
|
4
34
|
|
|
5
35
|
### Patch Changes
|
|
@@ -57,7 +87,6 @@
|
|
|
57
87
|
### Patch Changes
|
|
58
88
|
|
|
59
89
|
- [#3428](https://github.com/equinor/fusion-framework/pull/3428) [`1700ca8`](https://github.com/equinor/fusion-framework/commit/1700ca8851fa108e55e9729fd24f595272766e63) Thanks [@dependabot](https://github.com/apps/dependabot)! - Update zod from 4.1.9 to 4.1.11
|
|
60
|
-
|
|
61
90
|
- **v4.1.10**: Fixed shape caching issue (#5263) improving validation performance for complex schemas
|
|
62
91
|
- **v4.1.11**: Maintenance release with general improvements
|
|
63
92
|
|
|
@@ -77,7 +106,6 @@
|
|
|
77
106
|
Updated source code to migrate from zod v3 to v4. Updated zod dependency from v3.25.76 to v4.1.8 and modified schema definitions in the bookmark module to use explicit key and value types for records, simplified function schema definitions, and replaced zod-inferred types with explicit TypeScript interfaces.
|
|
78
107
|
|
|
79
108
|
Key changes in source code:
|
|
80
|
-
|
|
81
109
|
- Fixed record schema definitions to use explicit key and value types (`z.record(z.string(), z.unknown())`)
|
|
82
110
|
- Simplified function schema definitions by removing complex chaining (`.args()` and `.returns()`)
|
|
83
111
|
- Replaced zod-inferred types with explicit TypeScript interfaces for better performance
|
|
@@ -87,7 +115,6 @@
|
|
|
87
115
|
Breaking changes: Record schemas must specify both key and value types explicitly. Function schema definitions now require explicit typing.
|
|
88
116
|
|
|
89
117
|
Links:
|
|
90
|
-
|
|
91
118
|
- [Zod v4 Migration Guide](https://github.com/colinhacks/zod/releases/tag/v4.0.0)
|
|
92
119
|
- [Zod v4.1.8 Release Notes](https://github.com/colinhacks/zod/releases/tag/v4.1.8)
|
|
93
120
|
|
|
@@ -98,19 +125,16 @@
|
|
|
98
125
|
- [#3395](https://github.com/equinor/fusion-framework/pull/3395) [`29f6710`](https://github.com/equinor/fusion-framework/commit/29f6710238baf9b29f42394b30cb8b97f25462c3) Thanks [@odinr](https://github.com/odinr)! - Updated immer from 9.0.16 to 10.1.3 across all packages.
|
|
99
126
|
|
|
100
127
|
### Breaking Changes
|
|
101
|
-
|
|
102
128
|
- Immer 10.x introduces stricter TypeScript types for draft functions
|
|
103
129
|
- `ValidRecipeReturnType` type constraints have changed
|
|
104
130
|
- Promise return types in draft functions are no longer automatically handled
|
|
105
131
|
|
|
106
132
|
### Fixes Applied
|
|
107
|
-
|
|
108
133
|
- Updated BookmarkProvider to handle new immer type constraints
|
|
109
134
|
- Fixed ObservableInput type assignments in mergeScan operations
|
|
110
135
|
- Removed async/await from immer draft functions to comply with new type requirements
|
|
111
136
|
|
|
112
137
|
### Links
|
|
113
|
-
|
|
114
138
|
- [Immer 10.0.0 Release Notes](https://github.com/immerjs/immer/releases/tag/v10.0.0)
|
|
115
139
|
- [Immer Migration Guide](https://github.com/immerjs/immer/blob/main/MIGRATION.md)
|
|
116
140
|
|
|
@@ -119,32 +143,27 @@
|
|
|
119
143
|
Updated TypeScript type definitions for UUID operations across multiple packages. This major version update provides improved type safety and compatibility with the latest UUID library features.
|
|
120
144
|
|
|
121
145
|
### Affected Packages
|
|
122
|
-
|
|
123
146
|
- @equinor/fusion-framework-module-bookmark: @types/uuid ^9.0.8 → ^11.0.0
|
|
124
147
|
- @equinor/fusion-framework-module-feature-flag: @types/uuid ^10.0.0 → ^11.0.0
|
|
125
148
|
- @equinor/fusion-observable: @types/uuid ^10.0.0 → ^11.0.0
|
|
126
149
|
- @equinor/fusion-query: @types/uuid ^10.0.0 → ^11.0.0
|
|
127
150
|
|
|
128
151
|
### Links
|
|
129
|
-
|
|
130
152
|
- [@types/uuid on npm](https://www.npmjs.com/package/@types/uuid)
|
|
131
153
|
- [DefinitelyTyped @types/uuid](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/uuid)
|
|
132
154
|
|
|
133
155
|
- [#3347](https://github.com/equinor/fusion-framework/pull/3347) [`11143fa`](https://github.com/equinor/fusion-framework/commit/11143fa3002fb8a6c095052a04c7e596c56bafa8) Thanks [@dependabot](https://github.com/apps/dependabot)! - chore: bump uuid from 11.0.3 to 13.0.0
|
|
134
156
|
|
|
135
157
|
### Breaking Changes
|
|
136
|
-
|
|
137
158
|
- v13.0.0: Make browser exports the default
|
|
138
159
|
- v12.0.0: Update to TypeScript 5.2, remove CommonJS support, drop Node 16 support
|
|
139
160
|
|
|
140
161
|
### New Features
|
|
141
|
-
|
|
142
162
|
- Improved v4() performance
|
|
143
163
|
- Added Node 24 to CI matrix
|
|
144
164
|
- Restored node: prefix support
|
|
145
165
|
|
|
146
166
|
### Links
|
|
147
|
-
|
|
148
167
|
- [GitHub releases](https://github.com/uuidjs/uuid/releases/tag/v13.0.0)
|
|
149
168
|
- [npm changelog](https://www.npmjs.com/package/uuid?activeTab=versions)
|
|
150
169
|
|
|
@@ -159,14 +178,12 @@
|
|
|
159
178
|
- [#3075](https://github.com/equinor/fusion-framework/pull/3075) [`8fffbfb`](https://github.com/equinor/fusion-framework/commit/8fffbfb12daa9748bf5290e5084cd4d409aed253) Thanks [@odinr](https://github.com/odinr)! - Refactored the `Bookmark` type to be an intersection of `BookmarkWithoutData` and an optional `payload` property, improving type safety and flexibility. Updated `useBookmarkNavigate` to use proper TypeScript typing for bookmark events.
|
|
160
179
|
|
|
161
180
|
**Module Bookmark Changes:**
|
|
162
|
-
|
|
163
181
|
- Refactored `Bookmark` type in `packages/modules/bookmark/src/types.ts`
|
|
164
182
|
- Added export for `BookmarkProviderEvents` type in `packages/modules/bookmark/src/index.ts`
|
|
165
183
|
- Updated JSDoc comment from `@note` to `@remarks` in `packages/modules/bookmark/src/BookmarkClient.ts`
|
|
166
184
|
- Reordered tsconfig references (event before services)
|
|
167
185
|
|
|
168
186
|
**React Changes:**
|
|
169
|
-
|
|
170
187
|
- Updated `packages/react/modules/bookmark/src/portal/useBookmarkNavigate.ts` to use proper TypeScript typing for bookmark provider events
|
|
171
188
|
- Removed React paths configuration from `packages/react/app/tsconfig.json`
|
|
172
189
|
|
|
@@ -201,7 +218,6 @@
|
|
|
201
218
|
### Patch Changes
|
|
202
219
|
|
|
203
220
|
- [#3088](https://github.com/equinor/fusion-framework/pull/3088) [`7441b13`](https://github.com/equinor/fusion-framework/commit/7441b13aa50dd7362d1629086a27b6b4e571575d) Thanks [@eikeland](https://github.com/eikeland)! - chore: update package typesVersions
|
|
204
|
-
|
|
205
221
|
- Updated package.json typesVersions.
|
|
206
222
|
- Ensures backward compatibility with older node versions.
|
|
207
223
|
- Ensured consistency with workspace and repository configuration.
|
|
@@ -355,7 +371,6 @@
|
|
|
355
371
|
The new implementation has better state management and error handling, and should be easier to work with than the v1 implementation.
|
|
356
372
|
|
|
357
373
|
**Highlights:**
|
|
358
|
-
|
|
359
374
|
- has validation of configuration of the module.
|
|
360
375
|
- uses the `BaseConfigBuilder` pattern for configuration.
|
|
361
376
|
- has validation of requests and responses using zod schemas.
|
|
@@ -367,12 +382,10 @@
|
|
|
367
382
|
- has better logging.
|
|
368
383
|
|
|
369
384
|
**Migration:**
|
|
370
|
-
|
|
371
385
|
- update config for enabling the module
|
|
372
386
|
- check all direct access to provider interface if they are still valid
|
|
373
387
|
|
|
374
388
|
**Breaking changes:**
|
|
375
|
-
|
|
376
389
|
- The provider interface has changed
|
|
377
390
|
- The client interface has changed
|
|
378
391
|
- The configuration interface has changed
|
|
@@ -426,7 +439,6 @@
|
|
|
426
439
|
- [#2320](https://github.com/equinor/fusion-framework/pull/2320) [`1dd85f3`](https://github.com/equinor/fusion-framework/commit/1dd85f3a408a73df556d1812a5f280945cc100ee) Thanks [@odinr](https://github.com/odinr)! - Removed the `removeComments` option from the `tsconfig.base.json` file.
|
|
427
440
|
|
|
428
441
|
Removing the `removeComments` option allows TypeScript to preserve comments in the compiled JavaScript output. This can be beneficial for several reasons:
|
|
429
|
-
|
|
430
442
|
1. Improved debugging: Preserved comments can help developers understand the code better during debugging sessions.
|
|
431
443
|
2. Documentation: JSDoc comments and other important code documentation will be retained in the compiled output.
|
|
432
444
|
3. Source map accuracy: Keeping comments can lead to more accurate source maps, which is crucial for debugging and error tracking.
|
package/README.md
CHANGED
|
@@ -1,341 +1,242 @@
|
|
|
1
1
|
# Bookmark Module
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`@equinor/fusion-framework-module-bookmark` provides bookmark management for Fusion Framework applications. It lets users **create, update, delete, and favourite bookmarks**, track a **current (active) bookmark**, and react to bookmark lifecycle events.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Under the hood the module uses an RxJS-based state store with side-effect flows, an API client backed by `@equinor/fusion-framework-module-services`, and an event system powered by `@equinor/fusion-framework-module-event`.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- **Manage current bookmark**
|
|
9
|
-
- **Add and remove bookmarks from favorites**
|
|
10
|
-
- **Event listeners for bookmark-related events**
|
|
7
|
+
## Key Concepts
|
|
11
8
|
|
|
12
|
-
|
|
9
|
+
| Concept | Description |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| **BookmarkProvider** | Runtime service exposed after the module initialises. All CRUD, favourites, and current-bookmark operations go through this class. |
|
|
12
|
+
| **BookmarkModuleConfigurator** | Builder used during the configure phase to set the source system, filters, resolvers, and custom client. |
|
|
13
|
+
| **Payload Generator** | Callback registered via `addPayloadGenerator` that participates in building the bookmark payload during create and update. The callback receives an Immer draft — mutate in place. |
|
|
14
|
+
| **Source System** | Identifies which system owns the bookmarks (used for filtering and creation). |
|
|
15
|
+
| **Filters** | Optional flags (`application`, `context`) that restrict bookmark queries to the current app and/or context. |
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
13
18
|
|
|
14
19
|
```bash
|
|
15
|
-
pnpm
|
|
20
|
+
pnpm add @equinor/fusion-framework-module-bookmark
|
|
16
21
|
```
|
|
17
22
|
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
The simplest setup — no custom configuration, inherits everything from the parent (e.g. the portal framework):
|
|
26
|
+
|
|
18
27
|
```ts
|
|
19
|
-
import {
|
|
28
|
+
import { enableBookmark } from '@equinor/fusion-framework-module-bookmark';
|
|
29
|
+
|
|
20
30
|
const configure = (configurator) => {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
31
|
+
enableBookmark(configurator);
|
|
32
|
+
};
|
|
24
33
|
```
|
|
25
34
|
|
|
26
35
|
## Configuration
|
|
36
|
+
|
|
37
|
+
Use the callback form of `enableBookmark` to customise behaviour:
|
|
38
|
+
|
|
27
39
|
```ts
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
40
|
+
import { enableBookmark } from '@equinor/fusion-framework-module-bookmark';
|
|
41
|
+
|
|
42
|
+
const configure = (configurator) => {
|
|
43
|
+
enableBookmark(configurator, (builder) => {
|
|
44
|
+
// Tag bookmarks with their originating system
|
|
31
45
|
builder.setSourceSystem({
|
|
32
|
-
|
|
33
|
-
|
|
46
|
+
identifier: 'my-app-id',
|
|
47
|
+
name: 'My Application',
|
|
34
48
|
});
|
|
35
49
|
|
|
36
|
-
|
|
50
|
+
// Only return bookmarks for the current application
|
|
37
51
|
builder.setFilter('application', true);
|
|
38
52
|
|
|
39
|
-
|
|
53
|
+
// Only return bookmarks for the current context
|
|
40
54
|
builder.setFilter('context', true);
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
```
|
|
41
58
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
/** override default implementations */
|
|
45
|
-
builder.setClient(/** custom client implementation */)
|
|
46
|
-
builder.setParent(/** custom parent implementation */)
|
|
59
|
+
### Advanced Configuration
|
|
47
60
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
61
|
+
```ts
|
|
62
|
+
enableBookmark(configurator, (builder) => {
|
|
63
|
+
// Provide a custom API client (must implement IBookmarkClient)
|
|
64
|
+
builder.setClient(myCustomClient);
|
|
65
|
+
|
|
66
|
+
// Inherit bookmarks from a different parent provider
|
|
67
|
+
builder.setParent(parentProvider);
|
|
68
|
+
|
|
69
|
+
// Override how the current context is resolved
|
|
70
|
+
builder.setContextResolver(async (init) => {
|
|
71
|
+
return async () => ({ id: 'custom-context-id' });
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Override how the current application is resolved
|
|
75
|
+
builder.setApplicationResolver(async (init) => {
|
|
76
|
+
return async () => ({ appKey: 'my-app' });
|
|
77
|
+
});
|
|
51
78
|
});
|
|
52
79
|
```
|
|
53
80
|
|
|
54
|
-
|
|
55
81
|
> [!NOTE]
|
|
56
|
-
> When
|
|
57
|
-
>
|
|
58
|
-
> -
|
|
59
|
-
> -
|
|
60
|
-
> -
|
|
61
|
-
>
|
|
82
|
+
> When no explicit configuration is provided, the configurator resolves values
|
|
83
|
+
> from the parent framework (portal) and falls back to defaults for:
|
|
84
|
+
> - Source system
|
|
85
|
+
> - Filters
|
|
86
|
+
> - Context resolver
|
|
87
|
+
> - Application resolver
|
|
62
88
|
|
|
63
89
|
## BookmarkProvider
|
|
64
90
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
### Usage
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
#### Creating a Bookmark
|
|
91
|
+
`BookmarkProvider` is the runtime service you interact with after the module is initialised. It exposes both **Observable** and **async/Promise** APIs for every operation.
|
|
71
92
|
|
|
72
|
-
|
|
93
|
+
### Creating a Bookmark
|
|
73
94
|
|
|
74
95
|
```ts
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
96
|
+
bookmarkProvider.createBookmark({
|
|
97
|
+
name: 'My Bookmark',
|
|
98
|
+
payload: { filters: { status: 'active' } },
|
|
99
|
+
}).subscribe({
|
|
100
|
+
next: (bookmark) => console.log('Created:', bookmark.id),
|
|
101
|
+
error: (err) => console.error('Create failed:', err),
|
|
102
|
+
});
|
|
79
103
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
error: (err) => {
|
|
85
|
-
console.error('Failed to create bookmark:', err);
|
|
86
|
-
},
|
|
104
|
+
// Or with async/await:
|
|
105
|
+
const bookmark = await bookmarkProvider.createBookmarkAsync({
|
|
106
|
+
name: 'My Bookmark',
|
|
107
|
+
payload: { filters: { status: 'active' } },
|
|
87
108
|
});
|
|
88
109
|
```
|
|
89
110
|
|
|
90
|
-
|
|
91
|
-
#### Updating a Bookmark
|
|
92
|
-
|
|
93
|
-
To update an existing bookmark, use the `updateBookmark` method:
|
|
111
|
+
### Updating a Bookmark
|
|
94
112
|
|
|
95
113
|
```ts
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
bookmarkProvider.updateBookmark(bookmarkId, bookmarkUpdates).subscribe({
|
|
103
|
-
next: (updatedBookmark) => {
|
|
104
|
-
console.log('Bookmark updated:', updatedBookmark);
|
|
105
|
-
},
|
|
106
|
-
error: (err) => {
|
|
107
|
-
console.error('Failed to update bookmark:', err);
|
|
108
|
-
},
|
|
114
|
+
bookmarkProvider.updateBookmark('bookmark-id', {
|
|
115
|
+
name: 'Updated Name',
|
|
116
|
+
payload: { filters: { status: 'closed' } },
|
|
117
|
+
}).subscribe({
|
|
118
|
+
next: (updated) => console.log('Updated:', updated.id),
|
|
119
|
+
error: (err) => console.error('Update failed:', err),
|
|
109
120
|
});
|
|
110
121
|
```
|
|
111
122
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
Callback function which triggers on creation or update of bookmark. It is used to modify the payload of the bookmark.
|
|
115
|
-
|
|
116
|
-
- payload: The payload of the bookmark, which can be modified of other payload generators.
|
|
117
|
-
- initial: The initial payload of the bookmark, which is the payload of the bookmark before any payload generators have been applied.
|
|
123
|
+
### Deleting a Bookmark
|
|
118
124
|
|
|
119
125
|
```ts
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
126
|
+
bookmarkProvider.deleteBookmark('bookmark-id').subscribe({
|
|
127
|
+
next: () => console.log('Deleted'),
|
|
128
|
+
error: (err) => console.error('Delete failed:', err),
|
|
129
|
+
});
|
|
123
130
|
```
|
|
124
131
|
|
|
125
|
-
|
|
132
|
+
### Payload Generators
|
|
126
133
|
|
|
127
|
-
|
|
134
|
+
Register a callback that runs during create and update to build or transform the bookmark payload. The callback receives an **Immer draft** — mutate it in place:
|
|
128
135
|
|
|
129
136
|
```ts
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
console.log('Bookmark removed:', result);
|
|
135
|
-
},
|
|
136
|
-
error: (err) => {
|
|
137
|
-
console.error('Failed to remove bookmark:', err);
|
|
138
|
-
},
|
|
137
|
+
const unregister = bookmarkProvider.addPayloadGenerator((payload, initial) => {
|
|
138
|
+
// `payload` is an Immer draft — mutate directly
|
|
139
|
+
payload.savedAt = new Date().toISOString();
|
|
140
|
+
payload.counter = (initial?.counter ?? 0) + 1;
|
|
139
141
|
});
|
|
142
|
+
|
|
143
|
+
// Call unregister() when the component unmounts to remove the generator
|
|
140
144
|
```
|
|
141
145
|
|
|
146
|
+
`canCreateBookmarks` returns `true` only when at least one payload generator is registered.
|
|
142
147
|
|
|
143
|
-
|
|
148
|
+
### Current Bookmark
|
|
144
149
|
|
|
145
|
-
|
|
150
|
+
Set, observe, or clear the active bookmark:
|
|
146
151
|
|
|
147
152
|
```ts
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
bookmarkProvider.addBookmarkToFavorites(bookmarkId).subscribe({
|
|
151
|
-
next: (bookmark) => {
|
|
152
|
-
console.log('Bookmark added to favorites:', bookmark);
|
|
153
|
-
},
|
|
154
|
-
error: (err) => {
|
|
155
|
-
console.error('Failed to add bookmark to favorites:', err);
|
|
156
|
-
},
|
|
157
|
-
});
|
|
158
|
-
```
|
|
153
|
+
// Set current bookmark by ID (fetches full data automatically)
|
|
154
|
+
bookmarkProvider.setCurrentBookmark('bookmark-id').subscribe();
|
|
159
155
|
|
|
160
|
-
|
|
156
|
+
// Clear the current bookmark
|
|
157
|
+
bookmarkProvider.setCurrentBookmark(null).subscribe();
|
|
161
158
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
next: (bookmark) => {
|
|
166
|
-
console.log('Bookmark removed from favorites:', bookmark);
|
|
167
|
-
},
|
|
168
|
-
error: (err) => {
|
|
169
|
-
console.error('Failed to remove bookmark from favorites:', err);
|
|
170
|
-
},
|
|
159
|
+
// Observe changes
|
|
160
|
+
bookmarkProvider.currentBookmark$.subscribe((bookmark) => {
|
|
161
|
+
console.log('Active bookmark:', bookmark);
|
|
171
162
|
});
|
|
172
163
|
```
|
|
173
164
|
|
|
174
|
-
|
|
175
|
-
To check if a bookmark is in favorites, use the `isBookmarkInFavorites` method:
|
|
165
|
+
### Favourites
|
|
176
166
|
|
|
177
167
|
```ts
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
bookmarkProvider.isBookmarkInFavorites(bookmarkId).subscribe({
|
|
181
|
-
next: (isFavorite) => {
|
|
182
|
-
console.log('Is bookmark in favorites:', isFavorite);
|
|
183
|
-
},
|
|
184
|
-
error: (err) => {
|
|
185
|
-
console.error('Failed to check if bookmark is in favorites:', err);
|
|
186
|
-
},
|
|
187
|
-
});
|
|
188
|
-
```
|
|
168
|
+
// Add to favourites
|
|
169
|
+
bookmarkProvider.addBookmarkToFavorites('bookmark-id').subscribe();
|
|
189
170
|
|
|
171
|
+
// Remove from favourites
|
|
172
|
+
bookmarkProvider.removeBookmarkAsFavorite('bookmark-id').subscribe();
|
|
190
173
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
```ts
|
|
196
|
-
const removeListener = bookmarkProvider.on('onCurrentBookmarkChanged', (event) => {
|
|
197
|
-
console.log('Current bookmark changed:', event.detail);
|
|
174
|
+
// Check favourite status
|
|
175
|
+
bookmarkProvider.isBookmarkInFavorites('bookmark-id').subscribe((isFav) => {
|
|
176
|
+
console.log('Is favourite:', isFav);
|
|
198
177
|
});
|
|
199
|
-
|
|
200
|
-
// To remove the event listener
|
|
201
|
-
removeListener();
|
|
202
178
|
```
|
|
203
179
|
|
|
204
|
-
|
|
180
|
+
### Event Listeners
|
|
205
181
|
|
|
206
|
-
|
|
182
|
+
Subscribe to lifecycle events emitted by the provider:
|
|
207
183
|
|
|
208
184
|
```ts
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
import { BookmarksApiClient } from '@equinor/fusion-framework-module-services/bookmarks';
|
|
212
|
-
import { HttpClient } from '@equinor/fusion-framework-module-http/client';
|
|
213
|
-
|
|
214
|
-
const httpClient = new HttpClient('https://my-fusion-backend-url.com');
|
|
215
|
-
const apiClient = new BookmarksApiClient(httpClient, 'json$');
|
|
216
|
-
const client = new BookmarkClient(apiClient);
|
|
217
|
-
|
|
218
|
-
client.getAllBookmarks().subscribe(bookmarks => {
|
|
219
|
-
// do something with bookmarks
|
|
185
|
+
const unsubscribe = bookmarkProvider.on('onCurrentBookmarkChanged', (event) => {
|
|
186
|
+
console.log('Current bookmark changed:', event.detail);
|
|
220
187
|
});
|
|
221
188
|
|
|
222
|
-
|
|
223
|
-
// do something with bookmark
|
|
224
|
-
});
|
|
189
|
+
// Call unsubscribe() to remove the listener
|
|
225
190
|
```
|
|
226
191
|
|
|
227
|
-
|
|
192
|
+
Available events:
|
|
228
193
|
|
|
229
|
-
|
|
194
|
+
| Event | When it fires |
|
|
195
|
+
| --- | --- |
|
|
196
|
+
| `onCurrentBookmarkChange` | **Before** the current bookmark changes (cancelable) |
|
|
197
|
+
| `onCurrentBookmarkChanged` | **After** the current bookmark has changed |
|
|
198
|
+
| `onBookmarkCreate` | Before a bookmark is created (cancelable) |
|
|
199
|
+
| `onBookmarkCreated` | After a bookmark has been created |
|
|
200
|
+
| `onBookmarkUpdate` | Before a bookmark is updated (cancelable) |
|
|
201
|
+
| `onBookmarkUpdated` | After a bookmark has been updated |
|
|
202
|
+
| `onBookmarkDelete` | Before a bookmark is deleted (cancelable) |
|
|
203
|
+
| `onBookmarkDeleted` | After a bookmark has been deleted |
|
|
204
|
+
| `onBookmarkFavouriteAdd` | Before a bookmark is added to favourites (cancelable) |
|
|
205
|
+
| `onBookmarkFavouriteAdded` | After a bookmark has been added to favourites |
|
|
206
|
+
| `onBookmarkFavouriteRemove` | Before a bookmark is removed from favourites (cancelable) |
|
|
207
|
+
| `onBookmarkFavouriteRemoved` | After a bookmark has been removed from favourites |
|
|
208
|
+
| `onBookmarkPayloadCreatorAdded` | When a new payload generator is registered |
|
|
230
209
|
|
|
231
|
-
|
|
232
|
-
import { IBookmarkClient } from '@equinor/fusion-bookmark';
|
|
210
|
+
## Custom Bookmark Client
|
|
233
211
|
|
|
234
|
-
|
|
235
|
-
// Implement the interface methods
|
|
236
|
-
}
|
|
212
|
+
To use a different backend, implement the `IBookmarkClient` interface and pass it to the configurator:
|
|
237
213
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
214
|
+
```ts
|
|
215
|
+
import type { IBookmarkClient } from '@equinor/fusion-framework-module-bookmark';
|
|
216
|
+
|
|
217
|
+
const myClient: IBookmarkClient = {
|
|
218
|
+
getAllBookmarks: (filter) => { /* ... */ },
|
|
219
|
+
getBookmarkById: (id) => { /* ... */ },
|
|
220
|
+
getBookmarkData: (id) => { /* ... */ },
|
|
221
|
+
setBookmarkData: (id, data) => { /* ... */ },
|
|
222
|
+
createBookmark: (bookmark) => { /* ... */ },
|
|
223
|
+
updateBookmark: (id, updates) => { /* ... */ },
|
|
224
|
+
deleteBookmark: (id) => { /* ... */ },
|
|
225
|
+
addBookmarkToFavorites: (id) => { /* ... */ },
|
|
226
|
+
removeBookmarkFromFavorites: (id) => { /* ... */ },
|
|
227
|
+
isBookmarkFavorite: (id) => { /* ... */ },
|
|
242
228
|
};
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
## Tips
|
|
246
|
-
|
|
247
|
-
## Using "shared" creator across multiple components
|
|
248
|
-
|
|
249
|
-
The bookmark module is designed to allow multiple subscribers to collectively manage the payload of an bookmark. This is done by using a payload generator that is triggered on creation and update of the bookmark. This allows multiple components to share the same payload and update it in a safe way.
|
|
250
|
-
|
|
251
|
-
To solve this complex problem, internally the bookmark provider uses immer to generate a draft of the payload (a reducer function to update the payload, prevent flux and mutation). This allows the payload to be updated in a safe way, without the need to worry about immutability.
|
|
252
|
-
|
|
253
|
-
__BAD!__
|
|
254
|
-
```tsx
|
|
255
|
-
/**
|
|
256
|
-
* In this example, the mutation of the payload will fail since the currentBookmark is immutable.
|
|
257
|
-
*/
|
|
258
|
-
const RootComponent = () => {
|
|
259
|
-
// note deprecated useBookmark
|
|
260
|
-
const {
|
|
261
|
-
addBookmarkCreator,
|
|
262
|
-
currentBookmark
|
|
263
|
-
} = useBookmark();
|
|
264
|
-
|
|
265
|
-
const payloadRef = useRef(currentBookmark?.payload ?? {});
|
|
266
229
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
return addBookmarkCreator(() => payloadRef.current);
|
|
271
|
-
}, [bookmarkProvider]);
|
|
272
|
-
|
|
273
|
-
// updates the payloadRef when the current bookmark changes
|
|
274
|
-
useEffect(() => {
|
|
275
|
-
payloadRef.current = currentBookmark?.payload ?? {};
|
|
276
|
-
}, [currentBookmark]);
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
return (
|
|
280
|
-
<>
|
|
281
|
-
<Component1 payloadRef={payloadRef} />
|
|
282
|
-
<Component2 payloadRef={payloadRef} />
|
|
283
|
-
</>
|
|
284
|
-
);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
const Component1 = ({ payloadRef }) => {
|
|
288
|
-
return <input
|
|
289
|
-
value={ payloadRef.current.foo }
|
|
290
|
-
onChange={(e) => payloadRef.current.foo = e.target.value }
|
|
291
|
-
/>
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
const Component2 = ({ payloadRef }) => { ... }
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
this version can be improved by updating the payload generator, but see next example to migrate of deprecated `useBookmark` to `useCurrentBookmark`.
|
|
298
|
-
|
|
299
|
-
```ts
|
|
300
|
-
// fix issue with payload generator
|
|
301
|
-
useEffect(() => {
|
|
302
|
-
return addBookmarkCreator((payload) => {
|
|
303
|
-
Object.assign(payload, payloadRef.current);
|
|
304
|
-
});
|
|
305
|
-
}, [bookmarkProvider]);
|
|
230
|
+
enableBookmark(configurator, (builder) => {
|
|
231
|
+
builder.setClient(myClient);
|
|
232
|
+
});
|
|
306
233
|
```
|
|
307
234
|
|
|
235
|
+
## Error Handling
|
|
308
236
|
|
|
309
|
-
|
|
310
|
-
```tsx
|
|
311
|
-
|
|
312
|
-
const RootComponent = () => {
|
|
313
|
-
return (
|
|
314
|
-
<>
|
|
315
|
-
<Component1 />
|
|
316
|
-
<Component2 />
|
|
317
|
-
</>
|
|
318
|
-
);
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
const Component1 = () => {
|
|
322
|
-
const ref = useRef(null);
|
|
237
|
+
The module exposes two error classes:
|
|
323
238
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
payload.foo = ref.current.value;
|
|
327
|
-
}, []);
|
|
239
|
+
- **`BookmarkProviderError`** — thrown by `BookmarkProvider` methods when a high-level operation fails (e.g. timeout, cancelled event, resolution failure).
|
|
240
|
+
- **`BookmarkFlowError`** — thrown inside internal store flows when an API call fails. Carries a reference to the originating request action.
|
|
328
241
|
|
|
329
|
-
|
|
330
|
-
const { currentBookmark } = useCurrentBookmark({ payloadGenerator });
|
|
331
|
-
|
|
332
|
-
// when the current bookmark changes, update the input value
|
|
333
|
-
useEffect(() => {
|
|
334
|
-
ref.current.value = currentBookmark.foo;
|
|
335
|
-
}, [currentBookmark]);
|
|
336
|
-
|
|
337
|
-
return <input ref={ref} />
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
Component2 = () => { ... }
|
|
341
|
-
```
|
|
242
|
+
Errors are also collected in the store and accessible via `bookmarkProvider.errors$`.
|