@equinor/fusion-framework-module-bookmark 4.0.2 → 4.0.4

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.
Files changed (117) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/esm/BookmarkClient.js +18 -3
  3. package/dist/esm/BookmarkClient.js.map +1 -1
  4. package/dist/esm/{BookmarkProvider.error.js → BookmarkFlowError.js} +9 -7
  5. package/dist/esm/BookmarkFlowError.js.map +1 -0
  6. package/dist/esm/{BookmarkConfigurator.js → BookmarkModuleConfigurator.js} +38 -6
  7. package/dist/esm/BookmarkModuleConfigurator.js.map +1 -0
  8. package/dist/esm/BookmarkProvider.js +112 -23
  9. package/dist/esm/BookmarkProvider.js.map +1 -1
  10. package/dist/esm/BookmarkProvider.selectors.js +8 -0
  11. package/dist/esm/BookmarkProvider.selectors.js.map +1 -1
  12. package/dist/esm/BookmarkProviderError.js +20 -0
  13. package/dist/esm/BookmarkProviderError.js.map +1 -0
  14. package/dist/esm/{BookmarkProvider.actions.js → bookmark-actions.js} +1 -1
  15. package/dist/esm/bookmark-actions.js.map +1 -0
  16. package/dist/esm/bookmark-config.schema.js +2 -0
  17. package/dist/esm/bookmark-config.schema.js.map +1 -1
  18. package/dist/esm/bookmark-flows/bookmark-api-flows.js +28 -0
  19. package/dist/esm/bookmark-flows/bookmark-api-flows.js.map +1 -0
  20. package/dist/esm/bookmark-flows/handle-add-bookmark-as-favorite.js +27 -0
  21. package/dist/esm/bookmark-flows/handle-add-bookmark-as-favorite.js.map +1 -0
  22. package/dist/esm/bookmark-flows/handle-create-bookmark.js +27 -0
  23. package/dist/esm/bookmark-flows/handle-create-bookmark.js.map +1 -0
  24. package/dist/esm/bookmark-flows/handle-delete-bookmark.js +26 -0
  25. package/dist/esm/bookmark-flows/handle-delete-bookmark.js.map +1 -0
  26. package/dist/esm/bookmark-flows/handle-fetch-all-bookmark.js +29 -0
  27. package/dist/esm/bookmark-flows/handle-fetch-all-bookmark.js.map +1 -0
  28. package/dist/esm/bookmark-flows/handle-fetch-bookmark-data.js +26 -0
  29. package/dist/esm/bookmark-flows/handle-fetch-bookmark-data.js.map +1 -0
  30. package/dist/esm/bookmark-flows/handle-fetch-bookmark.js +30 -0
  31. package/dist/esm/bookmark-flows/handle-fetch-bookmark.js.map +1 -0
  32. package/dist/esm/bookmark-flows/handle-remove-bookmark-from-favorites.js +28 -0
  33. package/dist/esm/bookmark-flows/handle-remove-bookmark-from-favorites.js.map +1 -0
  34. package/dist/esm/bookmark-flows/handle-remove-bookmark.js +49 -0
  35. package/dist/esm/bookmark-flows/handle-remove-bookmark.js.map +1 -0
  36. package/dist/esm/bookmark-flows/handle-update-bookmark.js +28 -0
  37. package/dist/esm/bookmark-flows/handle-update-bookmark.js.map +1 -0
  38. package/dist/esm/bookmark-flows/index.js +11 -0
  39. package/dist/esm/bookmark-flows/index.js.map +1 -0
  40. package/dist/esm/bookmark-module.js +2 -2
  41. package/dist/esm/bookmark-module.js.map +1 -1
  42. package/dist/esm/bookmark.schemas.js +9 -3
  43. package/dist/esm/bookmark.schemas.js.map +1 -1
  44. package/dist/esm/create-bookmark-reducer.js +122 -0
  45. package/dist/esm/create-bookmark-reducer.js.map +1 -0
  46. package/dist/esm/{BookmarkProvider.store.js → create-bookmark-store.js} +3 -3
  47. package/dist/esm/create-bookmark-store.js.map +1 -0
  48. package/dist/esm/enable-bookmark.js +2 -1
  49. package/dist/esm/enable-bookmark.js.map +1 -1
  50. package/dist/esm/index.js +12 -1
  51. package/dist/esm/index.js.map +1 -1
  52. package/dist/esm/version.js +1 -1
  53. package/dist/tsconfig.tsbuildinfo +1 -1
  54. package/dist/types/BookmarkClient.d.ts +1 -0
  55. package/dist/types/{BookmarkProvider.error.d.ts → BookmarkFlowError.d.ts} +9 -4
  56. package/dist/types/{BookmarkConfigurator.d.ts → BookmarkModuleConfigurator.d.ts} +10 -4
  57. package/dist/types/BookmarkProvider.d.ts +81 -18
  58. package/dist/types/BookmarkProvider.interface.d.ts +1 -1
  59. package/dist/types/BookmarkProvider.selectors.d.ts +3 -3
  60. package/dist/types/BookmarkProviderError.d.ts +16 -0
  61. package/dist/types/{BookmarkProvider.actions.d.ts → bookmark-actions.d.ts} +3 -3
  62. package/dist/types/bookmark-flows/bookmark-api-flows.d.ts +11 -0
  63. package/dist/types/bookmark-flows/handle-add-bookmark-as-favorite.d.ts +10 -0
  64. package/dist/types/bookmark-flows/handle-create-bookmark.d.ts +10 -0
  65. package/dist/types/bookmark-flows/handle-delete-bookmark.d.ts +10 -0
  66. package/dist/types/bookmark-flows/handle-fetch-all-bookmark.d.ts +10 -0
  67. package/dist/types/bookmark-flows/handle-fetch-bookmark-data.d.ts +10 -0
  68. package/dist/types/bookmark-flows/handle-fetch-bookmark.d.ts +10 -0
  69. package/dist/types/bookmark-flows/handle-remove-bookmark-from-favorites.d.ts +10 -0
  70. package/dist/types/bookmark-flows/handle-remove-bookmark.d.ts +14 -0
  71. package/dist/types/bookmark-flows/handle-update-bookmark.d.ts +10 -0
  72. package/dist/types/bookmark-flows/index.d.ts +10 -0
  73. package/dist/types/bookmark-module.d.ts +1 -1
  74. package/dist/types/{BookmarkProvider.reducer.d.ts → create-bookmark-reducer.d.ts} +39 -39
  75. package/dist/types/{BookmarkProvider.store.d.ts → create-bookmark-store.d.ts} +2 -2
  76. package/dist/types/enable-bookmark.d.ts +1 -1
  77. package/dist/types/index.d.ts +12 -1
  78. package/dist/types/version.d.ts +1 -1
  79. package/package.json +11 -11
  80. package/src/BookmarkClient.ts +21 -3
  81. package/src/{BookmarkProvider.error.ts → BookmarkFlowError.ts} +9 -7
  82. package/src/{BookmarkConfigurator.ts → BookmarkModuleConfigurator.ts} +42 -12
  83. package/src/BookmarkProvider.interface.ts +3 -2
  84. package/src/BookmarkProvider.selectors.ts +10 -2
  85. package/src/BookmarkProvider.ts +112 -23
  86. package/src/BookmarkProviderError.ts +19 -0
  87. package/src/{BookmarkProvider.actions.ts → bookmark-actions.ts} +1 -1
  88. package/src/bookmark-config.schema.ts +2 -0
  89. package/src/bookmark-flows/bookmark-api-flows.ts +45 -0
  90. package/src/bookmark-flows/handle-add-bookmark-as-favorite.ts +49 -0
  91. package/src/bookmark-flows/handle-create-bookmark.ts +47 -0
  92. package/src/bookmark-flows/handle-delete-bookmark.ts +47 -0
  93. package/src/bookmark-flows/handle-fetch-all-bookmark.ts +53 -0
  94. package/src/bookmark-flows/handle-fetch-bookmark-data.ts +58 -0
  95. package/src/bookmark-flows/handle-fetch-bookmark.ts +64 -0
  96. package/src/bookmark-flows/handle-remove-bookmark-from-favorites.ts +49 -0
  97. package/src/bookmark-flows/handle-remove-bookmark.ts +76 -0
  98. package/src/bookmark-flows/handle-update-bookmark.ts +48 -0
  99. package/src/bookmark-flows/index.ts +10 -0
  100. package/src/bookmark-module.ts +2 -2
  101. package/src/bookmark.schemas.ts +10 -4
  102. package/src/create-bookmark-reducer.ts +149 -0
  103. package/src/{BookmarkProvider.store.ts → create-bookmark-store.ts} +4 -4
  104. package/src/enable-bookmark.ts +3 -2
  105. package/src/index.ts +12 -1
  106. package/src/version.ts +1 -1
  107. package/dist/esm/BookmarkConfigurator.js.map +0 -1
  108. package/dist/esm/BookmarkProvider.actions.js.map +0 -1
  109. package/dist/esm/BookmarkProvider.error.js.map +0 -1
  110. package/dist/esm/BookmarkProvider.flows.js +0 -217
  111. package/dist/esm/BookmarkProvider.flows.js.map +0 -1
  112. package/dist/esm/BookmarkProvider.reducer.js +0 -113
  113. package/dist/esm/BookmarkProvider.reducer.js.map +0 -1
  114. package/dist/esm/BookmarkProvider.store.js.map +0 -1
  115. package/dist/types/BookmarkProvider.flows.d.ts +0 -79
  116. package/src/BookmarkProvider.flows.ts +0 -421
  117. package/src/BookmarkProvider.reducer.ts +0 -144
@@ -0,0 +1,49 @@
1
+ import { of, from } from 'rxjs';
2
+ import { concatMap, map, catchError, filter, last } from 'rxjs/operators';
3
+
4
+ import type { Flow, Observable } from '@equinor/fusion-observable';
5
+
6
+ import { bookmarkActions as actions, type BookmarkActions } from '../bookmark-actions';
7
+ import type { IBookmarkClient } from '../BookmarkClient.interface';
8
+ import { BookmarkFlowError } from '../BookmarkFlowError';
9
+
10
+ /**
11
+ * Handles the flow of adding a bookmark as a favorite.
12
+ *
13
+ * @param api - The `IBookmarkClient` API instance to use for interacting with bookmarks.
14
+ * @returns An RxJS `Flow` that handles the `addBookmarkAsFavourite` action.
15
+ */
16
+ export const handleAddBookmarkAsFavorite =
17
+ (api: IBookmarkClient): Flow<BookmarkActions> =>
18
+ (action$: Observable<BookmarkActions>) => {
19
+ /**
20
+ * Handles the flow for adding a bookmark as a favorite.
21
+ *
22
+ * This flow listens for the `addBookmarkAsFavourite` action, and then:
23
+ * 1. Calls the `addBookmarkToFavorites` API to add the bookmark to the user's favorites.
24
+ * 2. If the API call is successful, dispatches the `addBookmarkAsFavourite.success` action.
25
+ * 3. If the API call fails, dispatches the `addBookmarkAsFavourite.failure` action with an error.
26
+ */
27
+ const flow$ = action$.pipe(
28
+ filter(actions.addBookmarkAsFavourite.match),
29
+ concatMap((action) =>
30
+ // Map the API call outcome to a success or failure action for this bookmark.
31
+ from(api.addBookmarkToFavorites(action.payload)).pipe(
32
+ last(),
33
+ map(() => actions.addBookmarkAsFavourite.success(action.payload, action.meta)),
34
+ catchError((error) =>
35
+ of(
36
+ actions.addBookmarkAsFavourite.failure(
37
+ new BookmarkFlowError('Failed to add bookmark as favorite', action, {
38
+ cause: error,
39
+ }),
40
+ action.meta,
41
+ ),
42
+ ),
43
+ ),
44
+ ),
45
+ ),
46
+ );
47
+
48
+ return flow$;
49
+ };
@@ -0,0 +1,47 @@
1
+ import { of, from } from 'rxjs';
2
+ import { concatMap, map, catchError, filter, last } from 'rxjs/operators';
3
+
4
+ import type { Flow, Observable } from '@equinor/fusion-observable';
5
+
6
+ import { bookmarkActions as actions, type BookmarkActions } from '../bookmark-actions';
7
+ import type { IBookmarkClient } from '../BookmarkClient.interface';
8
+ import { BookmarkFlowError } from '../BookmarkFlowError';
9
+
10
+ /**
11
+ * Creates a Flow for handling creating bookmarks.
12
+ *
13
+ * @param api - An instance of the `IBookmarkClient` interface, which provides the necessary API methods for creating bookmarks.
14
+ * @returns A flow that listens for `createBookmark` actions, creates a new bookmark using the provided API.
15
+ */
16
+ export const handleCreateBookmark =
17
+ (api: IBookmarkClient): Flow<BookmarkActions> =>
18
+ (action$: Observable<BookmarkActions>) => {
19
+ /**
20
+ * This flow listens for the `createBookmark` action, and then uses the `api.createBookmark` function to create a new bookmark.
21
+ * If the bookmark is created successfully, it dispatches the `createBookmark.success` action with the new bookmark.
22
+ * If there is an error creating the bookmark, it dispatches the `fetchBookmark.failure` action with an error.
23
+ *
24
+ * The `concatMap` operator is used to prevent aborting the request if a new `createBookmark` action is dispatched while the previous request is in flight.
25
+ */
26
+ const flow$ = action$.pipe(
27
+ filter(actions.createBookmark.match),
28
+ concatMap((action) => {
29
+ // wait for the final emission before mapping to a success/failure action
30
+ return from(api.createBookmark(action.payload)).pipe(
31
+ last(),
32
+ map((bookmark) => actions.createBookmark.success(bookmark, action.meta)),
33
+ catchError((error) =>
34
+ of(
35
+ actions.createBookmark.failure(
36
+ new BookmarkFlowError('Failed to create new bookmark', action, {
37
+ cause: error,
38
+ }),
39
+ action.meta,
40
+ ),
41
+ ),
42
+ ),
43
+ );
44
+ }),
45
+ );
46
+ return flow$;
47
+ };
@@ -0,0 +1,47 @@
1
+ import { of, from } from 'rxjs';
2
+ import { concatMap, map, catchError, filter, last } from 'rxjs/operators';
3
+
4
+ import type { Flow, Observable } from '@equinor/fusion-observable';
5
+
6
+ import { bookmarkActions as actions, type BookmarkActions } from '../bookmark-actions';
7
+ import type { IBookmarkClient } from '../BookmarkClient.interface';
8
+ import { BookmarkFlowError } from '../BookmarkFlowError';
9
+
10
+ /**
11
+ * Creates a flow for handling deleting bookmarks.
12
+ *
13
+ * @param api - An instance of the `IBookmarkClient` interface, which provides the necessary API methods for deleting bookmarks.
14
+ * @returns A flow that listens for `deleteBookmark` actions, deletes the bookmark using the provided API.
15
+ */
16
+ export const handleDeleteBookmark =
17
+ (api: IBookmarkClient): Flow<BookmarkActions> =>
18
+ (action$: Observable<BookmarkActions>) => {
19
+ /**
20
+ * - Listens for the `deleteBookmark` action.
21
+ * - Calls the `api.deleteBookmark` function to delete the bookmark.
22
+ * - Maps the successful response to the `deleteBookmark.success` action.
23
+ * - Handles errors by dispatching the `fetchBookmark.failure` action with a `BookmarkFlowError`.
24
+ * - Uses `concatMap` to prevent aborting the request if a new action is dispatched while the previous request is in flight.
25
+ */
26
+ const flow$ = action$.pipe(
27
+ filter(actions.deleteBookmark.match),
28
+ concatMap((action) =>
29
+ // Map the API call outcome to a success or failure action for this bookmark.
30
+ from(api.deleteBookmark(action.payload)).pipe(
31
+ last(),
32
+ map(() => actions.deleteBookmark.success(action.payload, action.meta)),
33
+ catchError((error) =>
34
+ of(
35
+ actions.deleteBookmark.failure(
36
+ new BookmarkFlowError('Failed to delete bookmark', action, {
37
+ cause: error,
38
+ }),
39
+ action.meta,
40
+ ),
41
+ ),
42
+ ),
43
+ ),
44
+ ),
45
+ );
46
+ return flow$;
47
+ };
@@ -0,0 +1,53 @@
1
+ import { of, from } from 'rxjs';
2
+ import { throttleTime, groupBy, switchMap, map, catchError, filter, last } from 'rxjs/operators';
3
+
4
+ import type { Flow, Observable } from '@equinor/fusion-observable';
5
+
6
+ import { bookmarkActions as actions, type BookmarkActions } from '../bookmark-actions';
7
+ import type { IBookmarkClient } from '../BookmarkClient.interface';
8
+ import { BookmarkFlowError } from '../BookmarkFlowError';
9
+
10
+ const defaultThrottleTime = 200;
11
+
12
+ /**
13
+ * Creates a Flow for handling fetching users bookmarks.
14
+ *
15
+ * @param api - The bookmark API client to use for fetching bookmarks.
16
+ * @returns An observable that emits the result of the bookmark fetch operation.
17
+ */
18
+ export const handleFetchAllBookmark =
19
+ (api: IBookmarkClient): Flow<BookmarkActions> =>
20
+ (action$: Observable<BookmarkActions>) => {
21
+ /**
22
+ * This flow is triggered by the `fetchBookmarks` action and uses the `throttleTime` operator
23
+ * to limit the number of requests made to the API. The `switchMap` operator is used to make
24
+ * the API call and map the response to the appropriate action (success or failure).
25
+ */
26
+ const flow$ = action$.pipe(
27
+ filter(actions.fetchBookmarks.match),
28
+ // group requests by filter so throttling only applies per-filter
29
+ groupBy((action) => JSON.stringify(action.payload)),
30
+ switchMap((group) =>
31
+ // avoid flooding the API with repeated requests for the same filter
32
+ group.pipe(throttleTime(defaultThrottleTime)),
33
+ ),
34
+ switchMap((action) =>
35
+ // Map the API call outcome to a success or failure action for this filter.
36
+ from(api.getAllBookmarks(action.payload)).pipe(
37
+ last(),
38
+ map((value) => actions.fetchBookmarks.success(value, action.meta)),
39
+ catchError((error) =>
40
+ of(
41
+ actions.fetchBookmarks.failure(
42
+ new BookmarkFlowError('Failed to fetch all bookmarks', action, {
43
+ cause: error,
44
+ }),
45
+ action.meta,
46
+ ),
47
+ ),
48
+ ),
49
+ ),
50
+ ),
51
+ );
52
+ return flow$;
53
+ };
@@ -0,0 +1,58 @@
1
+ import { of, from } from 'rxjs';
2
+ import {
3
+ throttleTime,
4
+ groupBy,
5
+ mergeMap,
6
+ switchMap,
7
+ map,
8
+ catchError,
9
+ filter,
10
+ last,
11
+ } from 'rxjs/operators';
12
+
13
+ import type { Flow } from '@equinor/fusion-observable';
14
+
15
+ import { bookmarkActions as actions, type BookmarkActions } from '../bookmark-actions';
16
+ import type { IBookmarkClient } from '../BookmarkClient.interface';
17
+ import { BookmarkFlowError } from '../BookmarkFlowError';
18
+
19
+ const defaultThrottleTime = 200;
20
+
21
+ /**
22
+ * Creates a flow for handling fetching bookmark data.
23
+ *
24
+ * @param api - The bookmark client API.
25
+ * @returns A flow of bookmark actions.
26
+ */
27
+ export const handleFetchBookmarkData =
28
+ (api: IBookmarkClient): Flow<BookmarkActions> =>
29
+ (action$) => {
30
+ // throttle requests per bookmark id, then fetch the data and dispatch success/failure
31
+ const flow$ = action$.pipe(
32
+ filter(actions.fetchBookmarkData.match),
33
+ // group requests by bookmark id so throttling only applies per-id
34
+ groupBy((action) => JSON.stringify(action.payload)),
35
+ mergeMap((group) =>
36
+ // avoid flooding the API with repeated requests for the same bookmark
37
+ group.pipe(throttleTime(defaultThrottleTime)),
38
+ ),
39
+ switchMap((action) => {
40
+ // wait for the final emission before mapping to a success/failure action
41
+ return from(api.getBookmarkData(action.payload)).pipe(
42
+ last(),
43
+ map((data) => actions.fetchBookmarkData.success(action.payload, data, action.meta)),
44
+ catchError((error) =>
45
+ of(
46
+ actions.fetchBookmarkData.failure(
47
+ new BookmarkFlowError('Failed to fetch bookmark payload', action, {
48
+ cause: error,
49
+ }),
50
+ action.meta,
51
+ ),
52
+ ),
53
+ ),
54
+ );
55
+ }),
56
+ );
57
+ return flow$;
58
+ };
@@ -0,0 +1,64 @@
1
+ import { of } from 'rxjs';
2
+ import {
3
+ throttleTime,
4
+ groupBy,
5
+ mergeMap,
6
+ switchMap,
7
+ map,
8
+ catchError,
9
+ filter,
10
+ last,
11
+ } from 'rxjs/operators';
12
+
13
+ import { from } from 'rxjs';
14
+
15
+ import type { Flow } from '@equinor/fusion-observable';
16
+
17
+ import { bookmarkActions as actions, type BookmarkActions } from '../bookmark-actions';
18
+ import type { IBookmarkClient } from '../BookmarkClient.interface';
19
+ import { BookmarkFlowError } from '../BookmarkFlowError';
20
+
21
+ const defaultThrottleTime = 200;
22
+
23
+ /**
24
+ * Handles the fetch bookmark action by making an API request to get the bookmark by its ID.
25
+ *
26
+ * @param api - The bookmark client API.
27
+ * @returns A flow that handles the fetch bookmark action.
28
+ */
29
+ export const handleFetchBookmark =
30
+ (api: IBookmarkClient): Flow<BookmarkActions> =>
31
+ (action$) => {
32
+ /**
33
+ * Observable that represents the flow of fetching bookmarks.
34
+ * It listens for `fetchBookmark` actions, makes an API request to get the bookmark by ID,
35
+ * and emits corresponding success or failure actions based on the API response.
36
+ */
37
+ const flow$ = action$.pipe(
38
+ filter(actions.fetchBookmark.match),
39
+ // group requests by bookmark id so throttling only applies per-id
40
+ groupBy((action) => action.payload),
41
+ mergeMap((group) =>
42
+ // avoid flooding the API with repeated requests for the same bookmark
43
+ group.pipe(throttleTime(defaultThrottleTime)),
44
+ ),
45
+ switchMap((action) =>
46
+ // Map the API call outcome to a success or failure action for this bookmark.
47
+ from(api.getBookmarkById(action.payload)).pipe(
48
+ last(),
49
+ map((bookmark) => actions.fetchBookmark.success(bookmark, action.meta)),
50
+ catchError((error) =>
51
+ of(
52
+ actions.fetchBookmark.failure(
53
+ new BookmarkFlowError('Failed to fetch bookmark', action, {
54
+ cause: error,
55
+ }),
56
+ action.meta,
57
+ ),
58
+ ),
59
+ ),
60
+ ),
61
+ ),
62
+ );
63
+ return flow$;
64
+ };
@@ -0,0 +1,49 @@
1
+ import { of, from } from 'rxjs';
2
+ import { concatMap, map, catchError, filter, last } from 'rxjs/operators';
3
+
4
+ import type { Flow, Observable } from '@equinor/fusion-observable';
5
+
6
+ import { bookmarkActions as actions, type BookmarkActions } from '../bookmark-actions';
7
+ import type { IBookmarkClient } from '../BookmarkClient.interface';
8
+ import { BookmarkFlowError } from '../BookmarkFlowError';
9
+
10
+ /**
11
+ * Creates a Flow for handling removing a bookmark from favorites.
12
+ *
13
+ * @param api - An instance of the `IBookmarkClient` interface, which provides the necessary API methods for managing favorite bookmarks.
14
+ * @returns A flow that listens for `removeBookmarkAsFavorite` actions, removes the bookmark from the user's favorites using the provided API.
15
+ */
16
+ export const handleRemoveBookmarkFromFavorites =
17
+ (api: IBookmarkClient): Flow<BookmarkActions> =>
18
+ (action$: Observable<BookmarkActions>) => {
19
+ /**
20
+ * - Listens for the `removeBookmarkAsFavourite` action.
21
+ * - Calls the `api.removeBookmarkFromFavorites` function to remove the bookmark from favorites.
22
+ * - On success, dispatches the `removeBookmarkAsFavourite.success` action.
23
+ * - On error, dispatches the `fetchBookmark.failure` action with a `BookmarkFlowError`.
24
+ * - Uses `concatMap` to prevent aborting the request if a new action is dispatched while the previous request is in flight.
25
+ */
26
+ const flow$ = action$.pipe(
27
+ filter(actions.removeBookmarkAsFavourite.match),
28
+ // use concatMap to prevent aborting the request if a new action is dispatched while the previous request is in flight
29
+ concatMap((action) =>
30
+ // Map the API call outcome to a success or failure action for this bookmark.
31
+ from(api.removeBookmarkFromFavorites(action.payload)).pipe(
32
+ last(),
33
+ map(() => actions.removeBookmarkAsFavourite.success(action.payload, action.meta)),
34
+ catchError((error) =>
35
+ of(
36
+ actions.removeBookmarkAsFavourite.failure(
37
+ new BookmarkFlowError('Failed to remove bookmark as favorite', action, {
38
+ cause: error,
39
+ }),
40
+ action.meta,
41
+ ),
42
+ ),
43
+ ),
44
+ ),
45
+ ),
46
+ );
47
+
48
+ return flow$;
49
+ };
@@ -0,0 +1,76 @@
1
+ import { concat, merge, from } from 'rxjs';
2
+ import { map, concatMap, filter } from 'rxjs/operators';
3
+
4
+ import { type Flow, getBaseType } from '@equinor/fusion-observable';
5
+
6
+ import { bookmarkActions as actions, type BookmarkActions } from '../bookmark-actions';
7
+ import type { IBookmarkClient } from '../BookmarkClient.interface';
8
+
9
+ /**
10
+ * Creates a flow for handling bookmark removal.
11
+ *
12
+ * This function observes actions related to deleting a bookmark or removing a bookmark as a favorite, and dispatches the appropriate actions for each case.
13
+ * If the bookmark is currently a favorite, it will dispatch an action to remove it as a favorite.
14
+ * If the bookmark is not a favorite, it will dispatch an action to delete it.
15
+ *
16
+ * @param api - An instance of the `IBookmarkClient` interface, which provides the necessary API methods checking if bookmarks are favorites.
17
+ * @returns A flow that handles the removal of a bookmark.
18
+ */
19
+ export const handleRemoveBookmark =
20
+ (api: IBookmarkClient): Flow<BookmarkActions> =>
21
+ (action$) => {
22
+ /**
23
+ * Handles the removal of a bookmark from the application.
24
+ *
25
+ * This function is responsible for determining whether the bookmark being removed is a favorite or not,
26
+ * and then dispatching the appropriate action to either remove the bookmark as a favorite or delete the bookmark entirely.
27
+ *
28
+ * Uses `concatMap` to prevent aborting the request if a new action is dispatched while the previous request is in flight.
29
+ */
30
+ const dispatch$ = action$.pipe(
31
+ filter(actions.removeBookmark.match),
32
+ concatMap(({ payload: bookmarkId }) => {
33
+ // pick which action to dispatch based on the bookmark's favorite status
34
+ return from(api.isBookmarkFavorite(bookmarkId)).pipe(
35
+ map((isFavorite) => {
36
+ const action = isFavorite ? actions.removeBookmarkAsFavourite : actions.deleteBookmark;
37
+ return action(bookmarkId);
38
+ }),
39
+ );
40
+ }),
41
+ );
42
+
43
+ /**
44
+ * Handles failures for deleting a bookmark or removing a bookmark as a favorite.
45
+ */
46
+ const failure$ = merge(
47
+ action$.pipe(filter(actions.deleteBookmark.failure.match)),
48
+ action$.pipe(filter(actions.removeBookmarkAsFavourite.failure.match)),
49
+ ).pipe(map((action) => actions.removeBookmark.failure(action.payload, action.meta)));
50
+
51
+ /**
52
+ * Handles the success of deleting a bookmark or removing a bookmark as a favorite.
53
+ */
54
+ const success$ = merge(
55
+ action$.pipe(filter(actions.deleteBookmark.success.match)),
56
+ action$.pipe(filter(actions.removeBookmarkAsFavourite.success.match)),
57
+ ).pipe(
58
+ map((action) =>
59
+ actions.removeBookmark.success(
60
+ {
61
+ type: getBaseType(action.type),
62
+ bookmarkId: action.payload,
63
+ },
64
+ action.meta,
65
+ ),
66
+ ),
67
+ );
68
+
69
+ /**
70
+ * First dispatch either deletions of bookmark or removals of bookmarks as favorites.
71
+ * Then observer the results of those actions and dispatch the appropriate actions.
72
+ */
73
+ const flow$ = concat(dispatch$, merge(failure$, success$));
74
+
75
+ return flow$;
76
+ };
@@ -0,0 +1,48 @@
1
+ import { of, from } from 'rxjs';
2
+ import { concatMap, map, catchError, filter, last } from 'rxjs/operators';
3
+
4
+ import type { Flow, Observable } from '@equinor/fusion-observable';
5
+
6
+ import { bookmarkActions as actions, type BookmarkActions } from '../bookmark-actions';
7
+ import type { IBookmarkClient } from '../BookmarkClient.interface';
8
+ import { BookmarkFlowError } from '../BookmarkFlowError';
9
+
10
+ /**
11
+ * Creates a Flow for handling updating bookmarks.
12
+ *
13
+ * @param api - An instance of the `IBookmarkClient` interface, which provides the necessary API methods for updating bookmarks.
14
+ * @returns A flow that listens for `updateBookmark` actions, updates the bookmark using the provided API.
15
+ */
16
+ export const handleUpdateBookmark =
17
+ (api: IBookmarkClient): Flow<BookmarkActions> =>
18
+ (action$: Observable<BookmarkActions>) => {
19
+ /**
20
+ * This flow listens for `updateBookmark` actions, then calls the `api.updateBookmark` function with the action payload.
21
+ * If the update is successful, it dispatches a `updateBookmark.success` action with the updated bookmark.
22
+ * If there is an error, it dispatches a `fetchBookmark.failure` action with the error.
23
+ *
24
+ * The `concatMap` operator is used to prevent aborting the request if a new `updateBookmark` action is dispatched while the previous request is in flight.
25
+ */
26
+ const flow$ = action$.pipe(
27
+ filter(actions.updateBookmark.match),
28
+ concatMap((action) => {
29
+ const { bookmarkId, updates } = action.payload;
30
+ // wait for the final emission before mapping to a success/failure action
31
+ return from(api.updateBookmark(bookmarkId, updates)).pipe(
32
+ last(),
33
+ map((bookmark) => actions.updateBookmark.success(bookmark, action.meta)),
34
+ catchError((error) =>
35
+ of(
36
+ actions.updateBookmark.failure(
37
+ new BookmarkFlowError('Failed to update bookmark', action, {
38
+ cause: error,
39
+ }),
40
+ action.meta,
41
+ ),
42
+ ),
43
+ ),
44
+ );
45
+ }),
46
+ );
47
+ return flow$;
48
+ };
@@ -0,0 +1,10 @@
1
+ export { handleFetchBookmark } from './handle-fetch-bookmark';
2
+ export { handleFetchBookmarkData } from './handle-fetch-bookmark-data';
3
+ export { handleFetchAllBookmark } from './handle-fetch-all-bookmark';
4
+ export { handleCreateBookmark } from './handle-create-bookmark';
5
+ export { handleUpdateBookmark } from './handle-update-bookmark';
6
+ export { handleDeleteBookmark } from './handle-delete-bookmark';
7
+ export { handleRemoveBookmark } from './handle-remove-bookmark';
8
+ export { handleRemoveBookmarkFromFavorites } from './handle-remove-bookmark-from-favorites';
9
+ export { handleAddBookmarkAsFavorite } from './handle-add-bookmark-as-favorite';
10
+ export { bookmarkApiFlows } from './bookmark-api-flows';
@@ -8,7 +8,7 @@ import type { ServicesModule } from '@equinor/fusion-framework-module-services';
8
8
  import type { AppModule } from '@equinor/fusion-framework-module-app';
9
9
  import type { ContextModule } from '@equinor/fusion-framework-module-context';
10
10
  import { BookmarkProvider } from './BookmarkProvider';
11
- import { BookmarkModuleConfigurator } from './BookmarkConfigurator';
11
+ import { BookmarkModuleConfigurator } from './BookmarkModuleConfigurator';
12
12
  import { ConsoleLogger, type ILogger } from '@equinor/fusion-log';
13
13
  import { lastValueFrom } from 'rxjs';
14
14
  import { version } from './version';
@@ -33,7 +33,7 @@ export type BookmarkModule = Module<
33
33
  [EventModule, ServicesModule, AppModule, ContextModule]
34
34
  >;
35
35
 
36
- // TODO - remove when all framework uses log
36
+ // TODO(#5134) - remove when all framework uses log
37
37
  const fallbackLogger: ILogger = new ConsoleLogger('BookmarkModule');
38
38
 
39
39
  /**
@@ -56,11 +56,17 @@ export const bookmarkWithDataSchema = <
56
56
  T extends BookmarkData = BookmarkData,
57
57
  S extends z.ZodSchema<T> = z.ZodSchema<T>,
58
58
  >(
59
- schema: S = z.record(z.string(), z.unknown()).or(z.string()).optional() as unknown as S,
60
- ) =>
61
- bookmarkSchema.extend({
62
- payload: schema,
59
+ schema?: S,
60
+ ) => {
61
+ // No payload schema was supplied — fall back to accepting any JSON-serializable value.
62
+ // The generic constraint `S extends z.ZodSchema<T>` can't express this default directly,
63
+ // so the fallback schema must be cast through `unknown` to satisfy `S`.
64
+ const payloadSchema =
65
+ schema ?? (z.record(z.string(), z.unknown()).or(z.string()).optional() as unknown as S);
66
+ return bookmarkSchema.extend({
67
+ payload: payloadSchema,
63
68
  });
69
+ };
64
70
 
65
71
  /**
66
72
  * Parses an unknown value into a typed {@link Bookmark} using {@link bookmarkWithDataSchema}.