@equinor/fusion-framework-module-bookmark 4.1.0 → 4.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/BookmarkProvider.js +10 -5
- package/dist/esm/BookmarkProvider.js.map +1 -1
- package/dist/esm/__tests__/BookmarkProvider.test.js +34 -0
- package/dist/esm/__tests__/BookmarkProvider.test.js.map +1 -0
- package/dist/esm/version.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/BookmarkProvider.d.ts +5 -2
- package/dist/types/__tests__/BookmarkProvider.test.d.ts +1 -0
- package/dist/types/version.d.ts +1 -1
- package/package.json +13 -10
- package/CHANGELOG.md +0 -821
- package/src/BookmarkClient.interface.ts +0 -157
- package/src/BookmarkClient.ts +0 -290
- package/src/BookmarkFlowError.ts +0 -38
- package/src/BookmarkModuleConfigurator.ts +0 -412
- package/src/BookmarkProvider.events.ts +0 -87
- package/src/BookmarkProvider.interface.ts +0 -180
- package/src/BookmarkProvider.selectors.ts +0 -69
- package/src/BookmarkProvider.ts +0 -1549
- package/src/BookmarkProviderError.ts +0 -19
- package/src/__tests__/mock/bookmark-mock.test.ts +0 -199
- package/src/bookmark-actions.ts +0 -132
- package/src/bookmark-config.schema.ts +0 -55
- package/src/bookmark-flows/bookmark-api-flows.ts +0 -45
- package/src/bookmark-flows/handle-add-bookmark-as-favorite.ts +0 -49
- package/src/bookmark-flows/handle-create-bookmark.ts +0 -47
- package/src/bookmark-flows/handle-delete-bookmark.ts +0 -47
- package/src/bookmark-flows/handle-fetch-all-bookmark.ts +0 -53
- package/src/bookmark-flows/handle-fetch-bookmark-data.ts +0 -58
- package/src/bookmark-flows/handle-fetch-bookmark.ts +0 -64
- package/src/bookmark-flows/handle-remove-bookmark-from-favorites.ts +0 -49
- package/src/bookmark-flows/handle-remove-bookmark.ts +0 -76
- package/src/bookmark-flows/handle-update-bookmark.ts +0 -48
- package/src/bookmark-flows/index.ts +0 -10
- package/src/bookmark-module.ts +0 -98
- package/src/bookmark.schemas.ts +0 -81
- package/src/create-bookmark-reducer.ts +0 -149
- package/src/create-bookmark-store.ts +0 -61
- package/src/enable-bookmark.ts +0 -44
- package/src/index.ts +0 -43
- package/src/mock/BookmarkMockClient.ts +0 -310
- package/src/mock/BookmarkMockConfigurator.ts +0 -159
- package/src/mock/index.ts +0 -25
- package/src/mock/module.ts +0 -64
- package/src/types.ts +0 -121
- package/src/version.ts +0 -2
- package/tsconfig.json +0 -30
- package/vitest.config.ts +0 -11
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* General-purpose error thrown by {@link BookmarkProvider} methods when a
|
|
3
|
-
* high-level operation (create, update, delete, set current, etc.) fails.
|
|
4
|
-
*
|
|
5
|
-
* Distinct from {@link BookmarkFlowError}, which is scoped to internal
|
|
6
|
-
* store flow pipelines.
|
|
7
|
-
*/
|
|
8
|
-
export class BookmarkProviderError extends Error {
|
|
9
|
-
/**
|
|
10
|
-
* Constructs a new `BookmarkProviderError`.
|
|
11
|
-
*
|
|
12
|
-
* @param message - Human-readable error message.
|
|
13
|
-
* @param options - Optional `ErrorOptions` (e.g. `cause`).
|
|
14
|
-
*/
|
|
15
|
-
constructor(message: string, options?: ErrorOptions) {
|
|
16
|
-
super(message, options);
|
|
17
|
-
this.name = 'BookmarkProviderError';
|
|
18
|
-
}
|
|
19
|
-
}
|
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
import { firstValueFrom, from, type ObservableInput } from 'rxjs';
|
|
2
|
-
import { describe, expect, it } from 'vitest';
|
|
3
|
-
|
|
4
|
-
import { ModulesConfigurator } from '@equinor/fusion-framework-module';
|
|
5
|
-
|
|
6
|
-
import { BookmarkModuleConfigurator } from '../../BookmarkModuleConfigurator';
|
|
7
|
-
import { BookmarkProvider } from '../../BookmarkProvider';
|
|
8
|
-
import type { IBookmarkProvider } from '../../BookmarkProvider.interface';
|
|
9
|
-
import { module as realModule } from '../../bookmark-module';
|
|
10
|
-
import type { Bookmark } from '../../types';
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
BookmarkMockClient,
|
|
14
|
-
BookmarkMockConfigurator,
|
|
15
|
-
bookmarkMockModule,
|
|
16
|
-
enableBookmarkMock,
|
|
17
|
-
} from '../../mock';
|
|
18
|
-
|
|
19
|
-
/** A fully-formed seeded bookmark, so tests only override what they care about. */
|
|
20
|
-
const createBookmark = (overrides: Partial<Bookmark> = {}): Bookmark => ({
|
|
21
|
-
id: 'bookmark-1',
|
|
22
|
-
name: 'My Bookmark',
|
|
23
|
-
appKey: 'test-app',
|
|
24
|
-
created: new Date('2024-01-01T00:00:00.000Z'),
|
|
25
|
-
createdBy: { id: 'seed-user', name: 'Seed User' },
|
|
26
|
-
...overrides,
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Initializes the mock module through the real module system.
|
|
31
|
-
*
|
|
32
|
-
* @remarks
|
|
33
|
-
* Deliberately avoids hand-building initialization arguments — faking the
|
|
34
|
-
* module system is the very cost this mock removes.
|
|
35
|
-
*
|
|
36
|
-
* @param configure - Optional callback to seed bookmarks, current bookmark, or favorites.
|
|
37
|
-
* @returns The `IBookmarkProvider` the module produced.
|
|
38
|
-
*/
|
|
39
|
-
const initializeMockWith = async (
|
|
40
|
-
configure?: (builder: BookmarkMockConfigurator) => void,
|
|
41
|
-
): Promise<IBookmarkProvider> => {
|
|
42
|
-
const configurator = new ModulesConfigurator([]);
|
|
43
|
-
enableBookmarkMock(configurator, configure);
|
|
44
|
-
const instances = await configurator.initialize();
|
|
45
|
-
return (instances as unknown as { bookmark: IBookmarkProvider }).bookmark;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Resolves the first value of an `IBookmarkProvider` call.
|
|
50
|
-
*
|
|
51
|
-
* @remarks
|
|
52
|
-
* `IBookmarkProvider`'s methods are typed as `ObservableInput`, not `Observable`,
|
|
53
|
-
* so this wraps with `from()` before handing off to `firstValueFrom`.
|
|
54
|
-
*
|
|
55
|
-
* @template T - The value the observable input emits.
|
|
56
|
-
* @param input - The observable input to resolve.
|
|
57
|
-
* @returns A promise resolving to the first emitted value.
|
|
58
|
-
*/
|
|
59
|
-
const firstValue = <T>(input: ObservableInput<T>): Promise<T> => firstValueFrom(from(input));
|
|
60
|
-
|
|
61
|
-
describe('bookmarkMockModule', () => {
|
|
62
|
-
it('changes nothing but the configurator', () => {
|
|
63
|
-
expect(bookmarkMockModule.name).toBe(realModule.name);
|
|
64
|
-
expect(bookmarkMockModule.version).toBe(realModule.version);
|
|
65
|
-
// The production initializer, untouched — the mock has no lifecycle of its own
|
|
66
|
-
expect(bookmarkMockModule.initialize).toBe(realModule.initialize);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('builds a real BookmarkModuleConfigurator, so the whole builder stays available', () => {
|
|
70
|
-
const configurator = bookmarkMockModule.configure?.();
|
|
71
|
-
|
|
72
|
-
expect(configurator).toBeInstanceOf(BookmarkModuleConfigurator);
|
|
73
|
-
expect(configurator).toBeInstanceOf(BookmarkMockConfigurator);
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
describe('enableBookmarkMock', () => {
|
|
78
|
-
it('produces the real BookmarkProvider, not a stand-in', async () => {
|
|
79
|
-
const provider = await initializeMockWith();
|
|
80
|
-
|
|
81
|
-
expect(provider).toBeInstanceOf(BookmarkProvider);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it('replaces a bookmark module that is already registered', async () => {
|
|
85
|
-
// A FrameworkConfigurator pre-registers the real bookmark module, so the
|
|
86
|
-
// mock is only useful if registering it afterwards wins
|
|
87
|
-
const configurator = new ModulesConfigurator([realModule]);
|
|
88
|
-
enableBookmarkMock(configurator, (builder) => {
|
|
89
|
-
builder.setBookmarks([createBookmark()]);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
const instances = await configurator.initialize();
|
|
93
|
-
const provider = (instances as unknown as { bookmark: IBookmarkProvider }).bookmark;
|
|
94
|
-
|
|
95
|
-
const bookmarks = await firstValue(provider.getAllBookmarks());
|
|
96
|
-
expect(bookmarks).toHaveLength(1);
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it('reflects seeded bookmarks with no real HTTP', async () => {
|
|
100
|
-
const seeded = createBookmark();
|
|
101
|
-
const provider = await initializeMockWith((builder) => {
|
|
102
|
-
builder.setBookmarks([seeded]);
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
const bookmarks = await firstValue(provider.getAllBookmarks());
|
|
106
|
-
expect(bookmarks.map((b) => b.id)).toEqual([seeded.id]);
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it('reflects the seeded current bookmark', async () => {
|
|
110
|
-
const seeded = createBookmark();
|
|
111
|
-
const provider = await initializeMockWith((builder) => {
|
|
112
|
-
builder.setBookmarks([seeded]);
|
|
113
|
-
builder.setCurrentBookmark(seeded.id);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
expect(provider.currentBookmark?.id).toBe(seeded.id);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it('leaves the current bookmark unset when none is seeded', async () => {
|
|
120
|
-
const provider = await initializeMockWith((builder) => {
|
|
121
|
-
builder.setBookmarks([createBookmark()]);
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
expect(provider.currentBookmark).toBeNull();
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it('reflects a seeded favorite', async () => {
|
|
128
|
-
const seeded = createBookmark();
|
|
129
|
-
const provider = await initializeMockWith((builder) => {
|
|
130
|
-
builder.setBookmarks([seeded]);
|
|
131
|
-
builder.setFavorite(seeded.id, true);
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
await expect(firstValue(provider.isBookmarkInFavorites(seeded.id))).resolves.toBe(true);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it('creates a bookmark through the real create flow', async () => {
|
|
138
|
-
const provider = await initializeMockWith();
|
|
139
|
-
// without a payload generator, generatePayload() never emits and the create
|
|
140
|
-
// flow would hang forever waiting on it
|
|
141
|
-
provider.addPayloadGenerator(() => {});
|
|
142
|
-
|
|
143
|
-
const created = await firstValue(
|
|
144
|
-
provider.createBookmark({ name: 'New Bookmark', appKey: 'test-app' }),
|
|
145
|
-
);
|
|
146
|
-
|
|
147
|
-
expect(created.name).toBe('New Bookmark');
|
|
148
|
-
const bookmarks = await firstValue(provider.getAllBookmarks());
|
|
149
|
-
expect(bookmarks.map((b) => b.id)).toContain(created.id);
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
it('updates a bookmark through the real update flow', async () => {
|
|
153
|
-
const seeded = createBookmark();
|
|
154
|
-
const provider = await initializeMockWith((builder) => {
|
|
155
|
-
builder.setBookmarks([seeded]);
|
|
156
|
-
});
|
|
157
|
-
// the update reducer only applies to bookmarks already tracked in the store,
|
|
158
|
-
// so fetch once first to seed it
|
|
159
|
-
await firstValue(provider.getAllBookmarks());
|
|
160
|
-
|
|
161
|
-
const updated = await firstValue(
|
|
162
|
-
provider.updateBookmark(seeded.id, { name: 'Renamed' }, { excludePayloadGeneration: true }),
|
|
163
|
-
);
|
|
164
|
-
|
|
165
|
-
expect(updated.name).toBe('Renamed');
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
it('surfaces a missing bookmark as an observable error through the real fetch flow', async () => {
|
|
169
|
-
const provider = await initializeMockWith();
|
|
170
|
-
|
|
171
|
-
await expect(firstValue(provider.getBookmark('missing-bookmark'))).rejects.toThrow();
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
it('deletes a bookmark through the real delete flow', async () => {
|
|
175
|
-
const seeded = createBookmark();
|
|
176
|
-
const provider = await initializeMockWith((builder) => {
|
|
177
|
-
builder.setBookmarks([seeded]);
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
await firstValue(provider.deleteBookmark(seeded.id));
|
|
181
|
-
|
|
182
|
-
const bookmarks = await firstValue(provider.getAllBookmarks());
|
|
183
|
-
expect(bookmarks.map((b) => b.id)).not.toContain(seeded.id);
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
it('lets setClient() replace the mock client outright', async () => {
|
|
187
|
-
const ownClient = new BookmarkMockClient();
|
|
188
|
-
ownClient.setBookmarks([createBookmark({ id: 'own-bookmark' })]);
|
|
189
|
-
|
|
190
|
-
const provider = await initializeMockWith((builder) => {
|
|
191
|
-
// the escape hatch is inherited unchanged from BookmarkModuleConfigurator
|
|
192
|
-
builder.setBookmarks([createBookmark({ id: 'ignored-bookmark' })]);
|
|
193
|
-
builder.setClient(ownClient);
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
const bookmarks = await firstValue(provider.getAllBookmarks());
|
|
197
|
-
expect(bookmarks.map((b) => b.id)).toEqual(['own-bookmark']);
|
|
198
|
-
});
|
|
199
|
-
});
|
package/src/bookmark-actions.ts
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type Action,
|
|
3
|
-
createAction,
|
|
4
|
-
createAsyncAction,
|
|
5
|
-
type ActionTypes,
|
|
6
|
-
} from '@equinor/fusion-observable';
|
|
7
|
-
|
|
8
|
-
import type { Bookmark, BookmarkData, BookmarkWithoutData, Bookmarks } from './types';
|
|
9
|
-
|
|
10
|
-
import type { BookmarkNew, BookmarkUpdate, BookmarksFilter } from './BookmarkClient.interface';
|
|
11
|
-
import type { BookmarkFlowError } from './BookmarkFlowError';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Represents the metadata associated with a bookmark action.
|
|
15
|
-
*/
|
|
16
|
-
type BookmarkActionMeta = {
|
|
17
|
-
// A reference identifier for the request.
|
|
18
|
-
ref: string;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Actions related to the BookmarkProvider provider state.
|
|
23
|
-
*
|
|
24
|
-
* Exports a set of actions that can be used to manage bookmarks.
|
|
25
|
-
*/
|
|
26
|
-
export const bookmarkActions = {
|
|
27
|
-
aborted: createAction('action_aborted', (action: Action) => ({
|
|
28
|
-
payload: action,
|
|
29
|
-
})),
|
|
30
|
-
setBookmark: createAction('set_bookmark', (bookmark: BookmarkWithoutData) => {
|
|
31
|
-
return { payload: bookmark };
|
|
32
|
-
}),
|
|
33
|
-
setCurrentBookmark: createAction('set_current_bookmark', (bookmark: Bookmark | null) => {
|
|
34
|
-
return { payload: bookmark };
|
|
35
|
-
}),
|
|
36
|
-
fetchBookmark: createAsyncAction(
|
|
37
|
-
'fetch_bookmark',
|
|
38
|
-
(bookmarkId: string, meta?: BookmarkActionMeta) => ({
|
|
39
|
-
payload: bookmarkId,
|
|
40
|
-
meta,
|
|
41
|
-
}),
|
|
42
|
-
(bookmark: BookmarkWithoutData, meta?: BookmarkActionMeta) => ({ payload: bookmark, meta }),
|
|
43
|
-
(error: BookmarkFlowError, meta?: BookmarkActionMeta) => ({ payload: error, meta }),
|
|
44
|
-
),
|
|
45
|
-
fetchBookmarkData: createAsyncAction(
|
|
46
|
-
'fetch_bookmark_payload',
|
|
47
|
-
(bookmarkId: string, meta?: BookmarkActionMeta) => ({ payload: bookmarkId, meta }),
|
|
48
|
-
(bookmarkId: string, data: BookmarkData, meta?: BookmarkActionMeta) => ({
|
|
49
|
-
payload: { bookmarkId, data },
|
|
50
|
-
meta,
|
|
51
|
-
}),
|
|
52
|
-
(error: BookmarkFlowError, meta?: BookmarkActionMeta) => ({ payload: error, meta }),
|
|
53
|
-
),
|
|
54
|
-
fetchBookmarks: createAsyncAction(
|
|
55
|
-
'fetch_bookmarks',
|
|
56
|
-
(filter?: BookmarksFilter, meta?: BookmarkActionMeta) => ({ payload: filter, meta }),
|
|
57
|
-
(bookmarks: Bookmarks, meta?: BookmarkActionMeta) => ({ payload: bookmarks, meta }),
|
|
58
|
-
(error: BookmarkFlowError, meta?: BookmarkActionMeta) => ({ payload: error, meta }),
|
|
59
|
-
),
|
|
60
|
-
updateBookmark: createAsyncAction(
|
|
61
|
-
'set_bookmark',
|
|
62
|
-
(payload: { bookmarkId: string; updates: BookmarkUpdate }, meta: BookmarkActionMeta) => ({
|
|
63
|
-
payload,
|
|
64
|
-
meta,
|
|
65
|
-
}),
|
|
66
|
-
(payload: Bookmark, meta: BookmarkActionMeta) => ({ payload, meta }),
|
|
67
|
-
(payload: BookmarkFlowError, meta: BookmarkActionMeta) => ({ payload, meta }),
|
|
68
|
-
),
|
|
69
|
-
createBookmark: createAsyncAction(
|
|
70
|
-
'create_bookmark',
|
|
71
|
-
(payload: BookmarkNew, meta: BookmarkActionMeta) => ({ payload, meta }),
|
|
72
|
-
(payload: Bookmark, meta: BookmarkActionMeta) => ({ payload, meta }),
|
|
73
|
-
(payload: BookmarkFlowError, meta: BookmarkActionMeta) => ({ payload, meta }),
|
|
74
|
-
),
|
|
75
|
-
deleteBookmark: createAsyncAction(
|
|
76
|
-
'delete_bookmark',
|
|
77
|
-
(bookmarkId: string, meta?: BookmarkActionMeta) => ({
|
|
78
|
-
payload: bookmarkId,
|
|
79
|
-
meta: { ref: bookmarkId, ...meta },
|
|
80
|
-
}),
|
|
81
|
-
(bookmarkId: string, meta?: BookmarkActionMeta) => ({
|
|
82
|
-
payload: bookmarkId,
|
|
83
|
-
meta: { ref: bookmarkId, ...meta },
|
|
84
|
-
}),
|
|
85
|
-
(payload: BookmarkFlowError, meta: BookmarkActionMeta) => ({ payload, meta }),
|
|
86
|
-
),
|
|
87
|
-
removeBookmark: createAsyncAction(
|
|
88
|
-
'remove_bookmark',
|
|
89
|
-
(bookmarkId: string, meta?: BookmarkActionMeta) => ({
|
|
90
|
-
payload: bookmarkId,
|
|
91
|
-
meta: { ref: bookmarkId, ...meta },
|
|
92
|
-
}),
|
|
93
|
-
(
|
|
94
|
-
payload: {
|
|
95
|
-
type: 'delete_bookmark' | 'remove_favourite_bookmark';
|
|
96
|
-
bookmarkId: string;
|
|
97
|
-
},
|
|
98
|
-
meta: BookmarkActionMeta,
|
|
99
|
-
) => ({ payload, meta }),
|
|
100
|
-
(payload: BookmarkFlowError, meta: BookmarkActionMeta) => ({
|
|
101
|
-
payload,
|
|
102
|
-
meta,
|
|
103
|
-
}),
|
|
104
|
-
),
|
|
105
|
-
addBookmarkAsFavourite: createAsyncAction(
|
|
106
|
-
'add_favourite_bookmark',
|
|
107
|
-
(bookmarkId: string, meta?: BookmarkActionMeta) => ({
|
|
108
|
-
payload: bookmarkId,
|
|
109
|
-
meta: { ref: bookmarkId, ...meta },
|
|
110
|
-
}),
|
|
111
|
-
(bookmarkId: string, meta?: BookmarkActionMeta) => ({
|
|
112
|
-
payload: bookmarkId,
|
|
113
|
-
meta: { ref: bookmarkId, ...meta },
|
|
114
|
-
}),
|
|
115
|
-
(error: BookmarkFlowError, meta: BookmarkActionMeta) => ({ payload: error, meta }),
|
|
116
|
-
),
|
|
117
|
-
removeBookmarkAsFavourite: createAsyncAction(
|
|
118
|
-
'remove_favourite_bookmark',
|
|
119
|
-
(bookmarkId: string, meta?: BookmarkActionMeta) => ({
|
|
120
|
-
payload: bookmarkId,
|
|
121
|
-
meta: { ref: bookmarkId, ...meta },
|
|
122
|
-
}),
|
|
123
|
-
(bookmarkId: string, meta?: BookmarkActionMeta) => ({
|
|
124
|
-
payload: bookmarkId,
|
|
125
|
-
meta: { ref: bookmarkId, ...meta },
|
|
126
|
-
}),
|
|
127
|
-
(error: BookmarkFlowError, meta: BookmarkActionMeta) => ({ payload: error, meta }),
|
|
128
|
-
),
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
/** Union type of all action objects produced by {@link bookmarkActions}. */
|
|
132
|
-
export type BookmarkActions = ActionTypes<typeof bookmarkActions>;
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
|
|
3
|
-
import { LogLevel, type ILogger } from '@equinor/fusion-log';
|
|
4
|
-
|
|
5
|
-
import type { IEventModuleProvider } from '@equinor/fusion-framework-module-event';
|
|
6
|
-
|
|
7
|
-
import type { IBookmarkProvider } from './BookmarkProvider.interface';
|
|
8
|
-
import type { IBookmarkClient } from './BookmarkClient.interface';
|
|
9
|
-
|
|
10
|
-
import { bookmarkSourceSystemSchema } from './bookmark.schemas';
|
|
11
|
-
import type { BookmarkModuleConfig } from './types';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Zod schema that validates the full {@link BookmarkModuleConfig} object.
|
|
15
|
-
*
|
|
16
|
-
* Used internally by {@link BookmarkModuleConfigurator} to verify the resolved
|
|
17
|
-
* configuration before the bookmark module is initialised.
|
|
18
|
-
*/
|
|
19
|
-
export const bookmarkConfigSchema = z.object({
|
|
20
|
-
log: z.custom<ILogger>().optional(),
|
|
21
|
-
logLevel: z.nativeEnum(LogLevel).optional(),
|
|
22
|
-
eventProvider: z.custom<IEventModuleProvider>().optional(),
|
|
23
|
-
sourceSystem: bookmarkSourceSystemSchema
|
|
24
|
-
.optional()
|
|
25
|
-
.describe('The source system for the bookmarks'),
|
|
26
|
-
parent: z.custom<IBookmarkProvider>().describe('Parent Bookmark provider').optional().nullable(),
|
|
27
|
-
client: z.custom<IBookmarkClient>().describe('API client for interacting with bookmarks'),
|
|
28
|
-
resolve: z
|
|
29
|
-
.object({
|
|
30
|
-
context: z.function(),
|
|
31
|
-
application: z.function(),
|
|
32
|
-
})
|
|
33
|
-
.describe('Functions for resolving context and application'),
|
|
34
|
-
filters: z
|
|
35
|
-
.object({
|
|
36
|
-
context: z.boolean().optional().default(false),
|
|
37
|
-
application: z.boolean().optional().default(false),
|
|
38
|
-
})
|
|
39
|
-
.describe('Flags for enabling resolving when fetching bookmarks')
|
|
40
|
-
.optional()
|
|
41
|
-
.default({ context: false, application: false }),
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Parses an unknown configuration object against {@link bookmarkConfigSchema}.
|
|
46
|
-
*
|
|
47
|
-
* @param config - The raw config value to validate.
|
|
48
|
-
* @returns A validated {@link BookmarkModuleConfig}.
|
|
49
|
-
* @throws {ZodError} When validation fails.
|
|
50
|
-
*/
|
|
51
|
-
// tightly coupled parse helper for the schema above
|
|
52
|
-
// fusion-lint-disable-next-line single-export-per-file
|
|
53
|
-
export const parseBookmarkConfig = (config: unknown): BookmarkModuleConfig => {
|
|
54
|
-
return bookmarkConfigSchema.parse(config) as BookmarkModuleConfig;
|
|
55
|
-
};
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { of, type Observable } from 'rxjs';
|
|
2
|
-
import { mergeMap } from 'rxjs/operators';
|
|
3
|
-
|
|
4
|
-
import type { Flow } from '@equinor/fusion-observable';
|
|
5
|
-
|
|
6
|
-
import type { BookmarkActions } from '../bookmark-actions';
|
|
7
|
-
import type { BookmarkState } from '../create-bookmark-store';
|
|
8
|
-
import type { IBookmarkClient } from '../BookmarkClient.interface';
|
|
9
|
-
|
|
10
|
-
import { handleFetchBookmark } from './handle-fetch-bookmark';
|
|
11
|
-
import { handleFetchBookmarkData } from './handle-fetch-bookmark-data';
|
|
12
|
-
import { handleFetchAllBookmark } from './handle-fetch-all-bookmark';
|
|
13
|
-
import { handleCreateBookmark } from './handle-create-bookmark';
|
|
14
|
-
import { handleUpdateBookmark } from './handle-update-bookmark';
|
|
15
|
-
import { handleDeleteBookmark } from './handle-delete-bookmark';
|
|
16
|
-
import { handleRemoveBookmark } from './handle-remove-bookmark';
|
|
17
|
-
import { handleRemoveBookmarkFromFavorites } from './handle-remove-bookmark-from-favorites';
|
|
18
|
-
import { handleAddBookmarkAsFavorite } from './handle-add-bookmark-as-favorite';
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Defines a set of flows that handle various bookmark-related actions, such as fetching, creating, updating, and deleting bookmarks.
|
|
22
|
-
*
|
|
23
|
-
* @param api - An instance of `IBookmarkClient` that provides the necessary API methods for interacting with the bookmark service.
|
|
24
|
-
* @returns A combined flow that handles all the bookmark-related actions.
|
|
25
|
-
*/
|
|
26
|
-
export const bookmarkApiFlows = (api: IBookmarkClient): Flow<BookmarkActions, BookmarkState> => {
|
|
27
|
-
/**
|
|
28
|
-
* Combines multiple Bookmark-related observable flows into a single observable stream.
|
|
29
|
-
* The resulting observable stream emits the combined effects of these flows,
|
|
30
|
-
* which can be used to update the application state.
|
|
31
|
-
*/
|
|
32
|
-
return (actions$: Observable<BookmarkActions>, state$: Observable<BookmarkState>) =>
|
|
33
|
-
// Invoke every bookmark flow with the shared api client and merge their emissions.
|
|
34
|
-
of(
|
|
35
|
-
handleFetchBookmark,
|
|
36
|
-
handleFetchBookmarkData,
|
|
37
|
-
handleFetchAllBookmark,
|
|
38
|
-
handleCreateBookmark,
|
|
39
|
-
handleUpdateBookmark,
|
|
40
|
-
handleDeleteBookmark,
|
|
41
|
-
handleRemoveBookmark,
|
|
42
|
-
handleRemoveBookmarkFromFavorites,
|
|
43
|
-
handleAddBookmarkAsFavorite,
|
|
44
|
-
).pipe(mergeMap((flow) => flow(api)(actions$, state$)));
|
|
45
|
-
};
|
|
@@ -1,49 +0,0 @@
|
|
|
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
|
-
};
|
|
@@ -1,47 +0,0 @@
|
|
|
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
|
-
};
|
|
@@ -1,47 +0,0 @@
|
|
|
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
|
-
};
|
|
@@ -1,53 +0,0 @@
|
|
|
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
|
-
};
|