@equinor/fusion-framework-module-bookmark 0.1.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 +16 -0
- package/LICENSE +21 -0
- package/README.md +11 -0
- package/dist/esm/bookmark-config-builder.js +70 -0
- package/dist/esm/bookmark-config-builder.js.map +1 -0
- package/dist/esm/bookmark-provider.js +130 -0
- package/dist/esm/bookmark-provider.js.map +1 -0
- package/dist/esm/client/bookmarkActions.js +8 -0
- package/dist/esm/client/bookmarkActions.js.map +1 -0
- package/dist/esm/client/bookmarkClient.js +212 -0
- package/dist/esm/client/bookmarkClient.js.map +1 -0
- package/dist/esm/client/bookmarkFlows.js +30 -0
- package/dist/esm/client/bookmarkFlows.js.map +1 -0
- package/dist/esm/client/bookmarkReducer.js +23 -0
- package/dist/esm/client/bookmarkReducer.js.map +1 -0
- package/dist/esm/configurator.js +172 -0
- package/dist/esm/configurator.js.map +1 -0
- package/dist/esm/enable-bookmark.js +10 -0
- package/dist/esm/enable-bookmark.js.map +1 -0
- package/dist/esm/index.js +6 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/module.js +27 -0
- package/dist/esm/module.js.map +1 -0
- package/dist/esm/types.js +2 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/utils/handle-url.js +11 -0
- package/dist/esm/utils/handle-url.js.map +1 -0
- package/dist/esm/utils/index.js +2 -0
- package/dist/esm/utils/index.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types/bookmark-config-builder.d.ts +25 -0
- package/dist/types/bookmark-provider.d.ts +63 -0
- package/dist/types/client/bookmarkActions.d.ts +21 -0
- package/dist/types/client/bookmarkClient.d.ts +48 -0
- package/dist/types/client/bookmarkFlows.d.ts +22 -0
- package/dist/types/client/bookmarkReducer.d.ts +5 -0
- package/dist/types/configurator.d.ts +47 -0
- package/dist/types/enable-bookmark.d.ts +4 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/module.d.ts +22 -0
- package/dist/types/types.d.ts +54 -0
- package/dist/types/utils/handle-url.d.ts +2 -0
- package/dist/types/utils/index.d.ts +1 -0
- package/package.json +48 -0
- package/src/bookmark-config-builder.ts +171 -0
- package/src/bookmark-provider.ts +288 -0
- package/src/client/bookmarkActions.ts +34 -0
- package/src/client/bookmarkClient.ts +290 -0
- package/src/client/bookmarkFlows.ts +66 -0
- package/src/client/bookmarkReducer.ts +29 -0
- package/src/configurator.ts +260 -0
- package/src/enable-bookmark.ts +32 -0
- package/src/index.ts +18 -0
- package/src/module.ts +40 -0
- package/src/types.ts +65 -0
- package/src/utils/handle-url.ts +13 -0
- package/src/utils/index.ts +1 -0
- package/tsconfig.json +36 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FrameworkEvent,
|
|
3
|
+
FrameworkEventInit,
|
|
4
|
+
IEventModuleProvider,
|
|
5
|
+
} from '@equinor/fusion-framework-module-event';
|
|
6
|
+
import { IHttpClient } from '@equinor/fusion-framework-module-http';
|
|
7
|
+
|
|
8
|
+
import { BookmarksApiClient } from '@equinor/fusion-framework-module-services/bookmarks';
|
|
9
|
+
import { createState } from '@equinor/fusion-observable';
|
|
10
|
+
import { FlowState } from '@equinor/fusion-observable/src/create-state';
|
|
11
|
+
import Query, { type QueryCtorOptions } from '@equinor/fusion-query';
|
|
12
|
+
|
|
13
|
+
import { BehaviorSubject, lastValueFrom, map, Observable, Subscription } from 'rxjs';
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
Bookmark,
|
|
17
|
+
CreateBookmark,
|
|
18
|
+
GetAllBookmarksParameters,
|
|
19
|
+
GetBookmarkParameters,
|
|
20
|
+
SourceSystem,
|
|
21
|
+
} from '../types';
|
|
22
|
+
import { ActionBuilder, actions } from './bookmarkActions';
|
|
23
|
+
import { reducer, State } from './bookmarkReducer';
|
|
24
|
+
import {
|
|
25
|
+
handleBookmarkGetAll,
|
|
26
|
+
handleCreateBookmark,
|
|
27
|
+
handleDeleteBookmark,
|
|
28
|
+
handleUpdateBookmark,
|
|
29
|
+
} from './bookmarkFlows';
|
|
30
|
+
|
|
31
|
+
export type BookmarkClientConfig = {
|
|
32
|
+
client: BookmarksApiClient<'fetch', IHttpClient, Bookmark<unknown>>;
|
|
33
|
+
queryClientConfig: {
|
|
34
|
+
getAllBookmarks: QueryCtorOptions<Array<Bookmark<unknown>>, GetAllBookmarksParameters>;
|
|
35
|
+
getBookmarkById: QueryCtorOptions<Bookmark<unknown>, GetBookmarkParameters>;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export class BookmarkClient {
|
|
40
|
+
#queryBookmarkById: Query<Bookmark<unknown>, GetBookmarkParameters>;
|
|
41
|
+
#queryAllBookmarks: Query<Array<Bookmark<unknown>>, GetAllBookmarksParameters>;
|
|
42
|
+
#bookmarkAPiClient: BookmarksApiClient<'fetch', IHttpClient, unknown>;
|
|
43
|
+
|
|
44
|
+
#currentBookmark$: BehaviorSubject<Bookmark<unknown> | undefined>;
|
|
45
|
+
|
|
46
|
+
#sourceSystem: SourceSystem;
|
|
47
|
+
#event?: IEventModuleProvider;
|
|
48
|
+
|
|
49
|
+
#state: FlowState<State, ActionBuilder>;
|
|
50
|
+
#subscriptions = new Subscription();
|
|
51
|
+
|
|
52
|
+
appRoute?(appKey: string): string;
|
|
53
|
+
|
|
54
|
+
constructor(
|
|
55
|
+
config: BookmarkClientConfig,
|
|
56
|
+
sourceSystem: SourceSystem,
|
|
57
|
+
event?: IEventModuleProvider
|
|
58
|
+
) {
|
|
59
|
+
this.#currentBookmark$ = new BehaviorSubject<Bookmark<unknown> | undefined>(undefined);
|
|
60
|
+
|
|
61
|
+
this.#bookmarkAPiClient = config.client;
|
|
62
|
+
this.#queryBookmarkById = new Query(config.queryClientConfig.getBookmarkById);
|
|
63
|
+
this.#queryAllBookmarks = new Query(config.queryClientConfig.getAllBookmarks);
|
|
64
|
+
|
|
65
|
+
this.#sourceSystem = sourceSystem;
|
|
66
|
+
this.#event = event;
|
|
67
|
+
|
|
68
|
+
this.#state = createState(actions, reducer);
|
|
69
|
+
|
|
70
|
+
// Add Bookmark API calls as flows
|
|
71
|
+
this.#addSubjectFlows();
|
|
72
|
+
|
|
73
|
+
// Add Events to actions success
|
|
74
|
+
this.#addStateEffects();
|
|
75
|
+
|
|
76
|
+
if (event) {
|
|
77
|
+
this.#subscriptions.add(
|
|
78
|
+
this.#currentBookmark$.subscribe((bookmark) => {
|
|
79
|
+
event.dispatchEvent('onBookmarkChanged', {
|
|
80
|
+
detail: bookmark,
|
|
81
|
+
canBubble: true,
|
|
82
|
+
source: this,
|
|
83
|
+
});
|
|
84
|
+
})
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
public get currentBookmark$(): Observable<Bookmark | undefined> {
|
|
90
|
+
return this.#currentBookmark$.asObservable();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
public get bookmarks$(): Observable<Bookmark[]> {
|
|
94
|
+
return this.#state.subject.pipe(
|
|
95
|
+
map((state) => Object.values(state.bookmarks).map((bookmark) => bookmark))
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
public async setCurrentBookmark<T>(idOrItem?: string | Bookmark<T>): Promise<void> {
|
|
100
|
+
if (!idOrItem) {
|
|
101
|
+
return this.#currentBookmark$.next(undefined);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (typeof idOrItem === 'string') {
|
|
105
|
+
// TODO add custom error
|
|
106
|
+
const bookmark = await this.resolverBookmarkAsync<T>(idOrItem);
|
|
107
|
+
return this.setBookmark(bookmark);
|
|
108
|
+
// TODO do a deep fast equal, since propagated bookmarks can be of different instances
|
|
109
|
+
} else if (idOrItem !== this.#currentBookmark$.value) {
|
|
110
|
+
return this.setBookmark(idOrItem);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
public async setBookmark<T>(bookmark?: Bookmark<T>): Promise<void> {
|
|
115
|
+
if (this.#event) {
|
|
116
|
+
/** notify that current bookmark is about to change */
|
|
117
|
+
const event = await this.#event.dispatchEvent('onBookmarkChange', {
|
|
118
|
+
detail: bookmark,
|
|
119
|
+
cancelable: true,
|
|
120
|
+
canBubble: true,
|
|
121
|
+
source: this,
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
/** check if any listeners requested canceling */
|
|
125
|
+
if (!event.canceled) {
|
|
126
|
+
this.#currentBookmark$.next(bookmark);
|
|
127
|
+
}
|
|
128
|
+
} else {
|
|
129
|
+
this.#currentBookmark$.next(bookmark);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
public resolverBookmark<T>(bookmarkId: string): Observable<Bookmark<T>> {
|
|
134
|
+
return this.#queryBookmarkById
|
|
135
|
+
.query({
|
|
136
|
+
id: bookmarkId,
|
|
137
|
+
})
|
|
138
|
+
.pipe(
|
|
139
|
+
map((bookmark) => {
|
|
140
|
+
return bookmark.value;
|
|
141
|
+
})
|
|
142
|
+
) as Observable<Bookmark<T>>;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
public resolverBookmarkAsync<T>(bookmarkId: string): Promise<Bookmark<T>> {
|
|
146
|
+
return lastValueFrom(this.resolverBookmark<T>(bookmarkId));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
public getAllBookmarks(args = { isValid: false }): Observable<Array<Bookmark>> {
|
|
150
|
+
const { isValid } = args;
|
|
151
|
+
return new Observable((subscriber) => {
|
|
152
|
+
this.#state.dispatch.getAll(isValid);
|
|
153
|
+
subscriber.add(
|
|
154
|
+
this.#state.subject.addEffect('getAll::success', (action) => {
|
|
155
|
+
subscriber.next(action.payload);
|
|
156
|
+
subscriber.complete();
|
|
157
|
+
})
|
|
158
|
+
);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
public async getAllBookmarksAsync(args = { isValid: false }): Promise<Array<Bookmark>> {
|
|
163
|
+
return lastValueFrom(this.getAllBookmarks(args));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
public async getBookmarkById<T>(bookmarkId: string): Promise<Bookmark<T>> {
|
|
167
|
+
const result = await this.#bookmarkAPiClient.get('v1', { id: bookmarkId });
|
|
168
|
+
const bookmark = (await result.json()) as Bookmark<T>;
|
|
169
|
+
return bookmark;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
public createBookmark(bookmark: CreateBookmark<unknown>): Observable<Bookmark<unknown>> {
|
|
173
|
+
return new Observable((subscriber) => {
|
|
174
|
+
this.#state.dispatch.create(bookmark);
|
|
175
|
+
subscriber.add(
|
|
176
|
+
this.#state.subject.addEffect('create::success', (action) => {
|
|
177
|
+
subscriber.next(action.payload as Bookmark<unknown>);
|
|
178
|
+
subscriber.complete();
|
|
179
|
+
})
|
|
180
|
+
);
|
|
181
|
+
subscriber.add(
|
|
182
|
+
this.#state.subject.addEffect('create::failure', (action) => {
|
|
183
|
+
subscriber.error(action.payload);
|
|
184
|
+
})
|
|
185
|
+
);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
public async createBookmarkAsync(
|
|
190
|
+
bookmark: CreateBookmark<unknown>
|
|
191
|
+
): Promise<Bookmark<unknown>> {
|
|
192
|
+
return lastValueFrom(this.createBookmark(bookmark));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
public updateBookmark<T>(bookmark: Bookmark<T>): Observable<Bookmark<T>> {
|
|
196
|
+
return new Observable((subscriber) => {
|
|
197
|
+
this.#state.dispatch.update(bookmark);
|
|
198
|
+
subscriber.add(
|
|
199
|
+
this.#state.subject.addEffect('update::success', (action) => {
|
|
200
|
+
subscriber.next(action.payload as Bookmark<T>);
|
|
201
|
+
subscriber.complete();
|
|
202
|
+
})
|
|
203
|
+
);
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
public async updateBookmarkAsync<T>(bookmark: Bookmark<T>): Promise<Bookmark<T>> {
|
|
208
|
+
return lastValueFrom(this.updateBookmark(bookmark));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
public deleteBookmarkById(bookmarkId: string): Observable<string> {
|
|
212
|
+
return new Observable((subscriber) => {
|
|
213
|
+
this.#state.dispatch.delete(bookmarkId);
|
|
214
|
+
subscriber.add(
|
|
215
|
+
this.#state.subject.addEffect('delete::success', (action) => {
|
|
216
|
+
subscriber.next(action.payload);
|
|
217
|
+
subscriber.complete();
|
|
218
|
+
})
|
|
219
|
+
);
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
public async deleteBookmarkByIdAsync(bookmarkId: string): Promise<string> {
|
|
224
|
+
return lastValueFrom(this.deleteBookmarkById(bookmarkId));
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
dispose(): void {
|
|
228
|
+
this.#subscriptions.unsubscribe();
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
#addStateEffects() {
|
|
232
|
+
this.#state.subject.addEffect('create::success', (action) => {
|
|
233
|
+
this.#currentBookmark$.next(action.payload);
|
|
234
|
+
this.#event?.dispatchEvent('onBookmarkCreated', {
|
|
235
|
+
detail: action.payload,
|
|
236
|
+
canBubble: true,
|
|
237
|
+
source: this,
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
this.#state.subject.addEffect('delete::success', (action) => {
|
|
241
|
+
this.#event?.dispatchEvent('onBookmarkDeleted', {
|
|
242
|
+
detail: action.payload,
|
|
243
|
+
canBubble: true,
|
|
244
|
+
source: this,
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
this.#state.subject.addEffect('update::success', (action) => {
|
|
248
|
+
this.#event?.dispatchEvent('onBookmarkUpdated', {
|
|
249
|
+
detail: action.payload,
|
|
250
|
+
canBubble: true,
|
|
251
|
+
source: this,
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
#addSubjectFlows() {
|
|
257
|
+
this.#subscriptions.add(
|
|
258
|
+
this.#state.subject.addFlow(
|
|
259
|
+
handleBookmarkGetAll(this.#queryAllBookmarks, this.#sourceSystem.identifier)
|
|
260
|
+
)
|
|
261
|
+
);
|
|
262
|
+
this.#subscriptions.add(
|
|
263
|
+
this.#state.subject.addFlow(handleCreateBookmark(this.#bookmarkAPiClient))
|
|
264
|
+
);
|
|
265
|
+
this.#subscriptions.add(
|
|
266
|
+
this.#state.subject.addFlow(handleDeleteBookmark(this.#bookmarkAPiClient))
|
|
267
|
+
);
|
|
268
|
+
this.#subscriptions.add(
|
|
269
|
+
this.#state.subject.addFlow(handleUpdateBookmark(this.#bookmarkAPiClient))
|
|
270
|
+
);
|
|
271
|
+
this.#subscriptions.add(
|
|
272
|
+
this.#state.subject.addFlow(handleUpdateBookmark(this.#bookmarkAPiClient))
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
declare module '@equinor/fusion-framework-module-event' {
|
|
278
|
+
interface FrameworkEventMap {
|
|
279
|
+
/** dispatch before bookmark changes */
|
|
280
|
+
onBookmarkChanged: FrameworkEvent<FrameworkEventInit<Bookmark<unknown>, BookmarkClient>>;
|
|
281
|
+
/** dispatch before bookmarks changes */
|
|
282
|
+
onBookmarksChanged: FrameworkEvent<
|
|
283
|
+
FrameworkEventInit<Array<Bookmark<unknown>>, BookmarkClient>
|
|
284
|
+
>;
|
|
285
|
+
onBookmarkCreated: FrameworkEvent<FrameworkEventInit<Bookmark<unknown>, BookmarkClient>>;
|
|
286
|
+
onBookmarkUpdated: FrameworkEvent<FrameworkEventInit<Bookmark<unknown>, BookmarkClient>>;
|
|
287
|
+
onBookmarkDeleted: FrameworkEvent<FrameworkEventInit<boolean, BookmarkClient>>;
|
|
288
|
+
onBookmarkResolved: FrameworkEvent<FrameworkEventInit<Bookmark<unknown>, BookmarkClient>>;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { IHttpClient } from '@equinor/fusion-framework-module-http';
|
|
2
|
+
import { BookmarksApiClient } from '@equinor/fusion-framework-module-services/bookmarks';
|
|
3
|
+
import { Observable } from '@equinor/fusion-observable';
|
|
4
|
+
import { filterAction } from '@equinor/fusion-observable/operators';
|
|
5
|
+
import { Query } from '@equinor/fusion-query';
|
|
6
|
+
import { switchMap, map, catchError, EMPTY } from 'rxjs';
|
|
7
|
+
import { GetAllBookmarksParameters, Bookmark } from '../types';
|
|
8
|
+
import { actions, Actions } from './bookmarkActions';
|
|
9
|
+
|
|
10
|
+
export const handleBookmarkGetAll =
|
|
11
|
+
(
|
|
12
|
+
queryAllBookmarks: Query<Array<Bookmark<unknown>>, GetAllBookmarksParameters>,
|
|
13
|
+
sourceSystemIdentifier: string
|
|
14
|
+
) =>
|
|
15
|
+
(action$: Observable<Actions>) =>
|
|
16
|
+
action$.pipe(
|
|
17
|
+
filterAction(actions.getAll.type),
|
|
18
|
+
switchMap((action) => {
|
|
19
|
+
return queryAllBookmarks.query({ isValid: action.payload }).pipe(
|
|
20
|
+
map((bookmarks) =>
|
|
21
|
+
actions.getAll.success(
|
|
22
|
+
bookmarks.value.filter(
|
|
23
|
+
(bookmark) =>
|
|
24
|
+
bookmark.sourceSystem.identifier === sourceSystemIdentifier
|
|
25
|
+
)
|
|
26
|
+
)
|
|
27
|
+
),
|
|
28
|
+
catchError(() => EMPTY)
|
|
29
|
+
);
|
|
30
|
+
})
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
export const handleCreateBookmark =
|
|
34
|
+
(apiClient: BookmarksApiClient<'fetch', IHttpClient, unknown>) =>
|
|
35
|
+
(action$: Observable<Actions>) =>
|
|
36
|
+
action$.pipe(
|
|
37
|
+
filterAction(actions.create.type),
|
|
38
|
+
switchMap(async (action) => {
|
|
39
|
+
const response = await apiClient.post('v1', action.payload);
|
|
40
|
+
return actions.create.success(await response.json());
|
|
41
|
+
})
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
export const handleUpdateBookmark =
|
|
45
|
+
(apiClient: BookmarksApiClient<'fetch', IHttpClient, unknown>) =>
|
|
46
|
+
(action$: Observable<Actions>) =>
|
|
47
|
+
action$.pipe(
|
|
48
|
+
filterAction(actions.update.type),
|
|
49
|
+
switchMap(async (action) => {
|
|
50
|
+
// Should payload be partial? then api client wil need to change.
|
|
51
|
+
const response = await apiClient.patch('v1', action.payload);
|
|
52
|
+
return actions.update.success(await response.json());
|
|
53
|
+
})
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
export const handleDeleteBookmark =
|
|
57
|
+
(apiClient: BookmarksApiClient<'fetch', IHttpClient, unknown>) =>
|
|
58
|
+
(action$: Observable<Actions>) =>
|
|
59
|
+
action$.pipe(
|
|
60
|
+
filterAction(actions.delete.type),
|
|
61
|
+
switchMap(async (action) => {
|
|
62
|
+
const response = await apiClient.delete('v1', { id: action.payload });
|
|
63
|
+
if (response.ok) return actions.delete.success(action.payload);
|
|
64
|
+
return actions.delete.success(action.payload);
|
|
65
|
+
})
|
|
66
|
+
);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { createReducer } from '@equinor/fusion-observable';
|
|
2
|
+
import { Bookmark } from '../types';
|
|
3
|
+
import { actions } from './bookmarkActions';
|
|
4
|
+
|
|
5
|
+
export type State = {
|
|
6
|
+
bookmarks: Record<string, Bookmark>;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const initialState: State = {
|
|
10
|
+
bookmarks: {},
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const reducer = createReducer<State>(initialState, (builder) => {
|
|
14
|
+
builder
|
|
15
|
+
.addCase(actions.create.success, (state, { payload }) => {
|
|
16
|
+
state.bookmarks[payload.id] = payload;
|
|
17
|
+
})
|
|
18
|
+
.addCase(actions.getAll.success, (state, { payload }) => {
|
|
19
|
+
payload.forEach((bookmark) => {
|
|
20
|
+
state.bookmarks[bookmark.id] = bookmark;
|
|
21
|
+
});
|
|
22
|
+
})
|
|
23
|
+
.addCase(actions.delete.success, (state, { payload }) => {
|
|
24
|
+
delete state.bookmarks[payload];
|
|
25
|
+
})
|
|
26
|
+
.addCase(actions.update.success, (state, { payload }) => {
|
|
27
|
+
state.bookmarks[payload.id] = payload;
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { getBookmarkIdFormURL } from './utils/handle-url';
|
|
2
|
+
import { BookmarkConfigBuilder, BookmarkConfigBuilderCallback } from './bookmark-config-builder';
|
|
3
|
+
|
|
4
|
+
import type { ModuleInitializerArgs, ModulesInstanceType } from '@equinor/fusion-framework-module';
|
|
5
|
+
import type { IApiProvider, ServicesModule } from '@equinor/fusion-framework-module-services';
|
|
6
|
+
import type { SourceSystem } from './types';
|
|
7
|
+
import type { ContextModule, IContextProvider } from '@equinor/fusion-framework-module-context';
|
|
8
|
+
import type { AppModule, AppModuleProvider } from '@equinor/fusion-framework-module-app';
|
|
9
|
+
import type { EventModule, IEventModuleProvider } from '@equinor/fusion-framework-module-event';
|
|
10
|
+
import type { IBookmarkModuleProvider } from './bookmark-provider';
|
|
11
|
+
|
|
12
|
+
import type {
|
|
13
|
+
INavigationProvider,
|
|
14
|
+
NavigationModule,
|
|
15
|
+
} from '@equinor/fusion-framework-module-navigation';
|
|
16
|
+
import type { BookmarkClientConfig } from './client/bookmarkClient';
|
|
17
|
+
|
|
18
|
+
export interface BookmarkModuleConfig {
|
|
19
|
+
/**
|
|
20
|
+
* SourceSystem used when creating a new bookmark,
|
|
21
|
+
* used as the identifier for the current client. Only used in app shell / portal configuration.
|
|
22
|
+
*/
|
|
23
|
+
sourceSystem: SourceSystem;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The clintConfiguration consist of both Api client configuration and query client configuration
|
|
27
|
+
*/
|
|
28
|
+
clientConfiguration: BookmarkClientConfig;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* It is possible to associate a Fusion context with a bookmark and this function is used to resolve the current context id applied.
|
|
32
|
+
* @returns - should return a fusion context id.
|
|
33
|
+
*/
|
|
34
|
+
getContextId: () => string | undefined;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* A bookmark kan be connected to a application this is used to resolve the current applications appKey.
|
|
38
|
+
*/
|
|
39
|
+
getCurrentAppIdentification?(): string | undefined;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The resolves bookmarkId at startup, default configured to resolve id form URL with query parm
|
|
43
|
+
* ?bookmarkId=GUID but this can be resolved for any where if needed.
|
|
44
|
+
*/
|
|
45
|
+
resolveBookmarkId?(): string | null;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* default set to Fusion Events Module.
|
|
49
|
+
*/
|
|
50
|
+
event?: IEventModuleProvider;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export type IBookmarkModuleConfigurator = {
|
|
54
|
+
/**
|
|
55
|
+
* @param init BookmarkConfigBuilderCallback for configuring the bookmark module.
|
|
56
|
+
* Configuration is only needed for application shell / portals.
|
|
57
|
+
*/
|
|
58
|
+
addConfigBuilder(init: BookmarkConfigBuilderCallback): void;
|
|
59
|
+
/**
|
|
60
|
+
* Bookmark Config Factory Providing default configuration if no configuration is provided.
|
|
61
|
+
* @param init ModuleInitializerArgs<IBookmarkModuleConfigurator, [ServicesModule, AppModule, ContextModule]>
|
|
62
|
+
* @param parentProvider Parent IBookmarkModuleProvider
|
|
63
|
+
*/
|
|
64
|
+
createConfig(
|
|
65
|
+
init: ModuleInitializerArgs<
|
|
66
|
+
IBookmarkModuleConfigurator,
|
|
67
|
+
[ServicesModule, AppModule, ContextModule]
|
|
68
|
+
>,
|
|
69
|
+
parentProvider?: IBookmarkModuleProvider
|
|
70
|
+
): Promise<BookmarkModuleConfig>;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export class BookmarkModuleConfigurator implements IBookmarkModuleConfigurator {
|
|
74
|
+
defaultExpireTime = 1 * 60 * 1000;
|
|
75
|
+
|
|
76
|
+
#configBuilders: Array<BookmarkConfigBuilderCallback> = [];
|
|
77
|
+
|
|
78
|
+
addConfigBuilder(init: BookmarkConfigBuilderCallback): void {
|
|
79
|
+
this.#configBuilders.push(init);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async createConfig(
|
|
83
|
+
init: ModuleInitializerArgs<
|
|
84
|
+
IBookmarkModuleConfigurator,
|
|
85
|
+
[ServicesModule, AppModule, ContextModule]
|
|
86
|
+
>,
|
|
87
|
+
parentProvider?: IBookmarkModuleProvider
|
|
88
|
+
): Promise<BookmarkModuleConfig> {
|
|
89
|
+
const config: Partial<BookmarkModuleConfig> = await this.#configBuilders.reduce(
|
|
90
|
+
async (cur, cb) => {
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
92
|
+
const builder = new BookmarkConfigBuilder<any, any>(init, await cur);
|
|
93
|
+
await Promise.resolve(cb(builder));
|
|
94
|
+
return Object.assign(cur, builder.config);
|
|
95
|
+
},
|
|
96
|
+
Promise.resolve({} as Partial<BookmarkModuleConfig>)
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
const appProvider = await this._getAppProvider(init);
|
|
100
|
+
|
|
101
|
+
this.#applyParentProviderConfiguration(parentProvider, config);
|
|
102
|
+
|
|
103
|
+
if (!config.resolveBookmarkId) {
|
|
104
|
+
config.resolveBookmarkId = getBookmarkIdFormURL;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!config.getCurrentAppIdentification) {
|
|
108
|
+
config.getCurrentAppIdentification = () => appProvider.current?.appKey;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (!config.getContextId) {
|
|
112
|
+
const contextProvider = await this._getContextProvider(init);
|
|
113
|
+
config.getContextId = () => {
|
|
114
|
+
return contextProvider.currentContext?.id;
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (!config.event) {
|
|
119
|
+
const event = await this._getEventProvider(init);
|
|
120
|
+
config.event = event;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
config.clientConfiguration = await this._createClientConfiguration(
|
|
124
|
+
init,
|
|
125
|
+
config.clientConfiguration
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
if (!config.sourceSystem) {
|
|
129
|
+
throw Error('missing sourceSystem configuration');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return config as BookmarkModuleConfig;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
#applyParentProviderConfiguration(
|
|
136
|
+
parentProvider: IBookmarkModuleProvider | undefined,
|
|
137
|
+
config: Partial<BookmarkModuleConfig>
|
|
138
|
+
) {
|
|
139
|
+
if (parentProvider) {
|
|
140
|
+
config.clientConfiguration = parentProvider.config.clientConfiguration;
|
|
141
|
+
config.sourceSystem = parentProvider.config.sourceSystem;
|
|
142
|
+
config.getContextId = parentProvider.config.getContextId;
|
|
143
|
+
config.getCurrentAppIdentification = parentProvider.config.getCurrentAppIdentification;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
protected async _createClientConfiguration(
|
|
148
|
+
init: ModuleInitializerArgs<
|
|
149
|
+
IBookmarkModuleConfigurator,
|
|
150
|
+
[ServicesModule, AppModule, ContextModule]
|
|
151
|
+
>,
|
|
152
|
+
config: Partial<BookmarkClientConfig> = {}
|
|
153
|
+
): Promise<BookmarkClientConfig> {
|
|
154
|
+
if (!config.client) {
|
|
155
|
+
const apiProvider = await this._getServiceProvider(init);
|
|
156
|
+
config.client = await apiProvider.createBookmarksClient('fetch');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (!config.queryClientConfig) {
|
|
160
|
+
const apiProvider = await this._getServiceProvider(init);
|
|
161
|
+
const bookmarkClient = await apiProvider.createBookmarksClient('json$');
|
|
162
|
+
|
|
163
|
+
config.queryClientConfig = {
|
|
164
|
+
getBookmarkById: {
|
|
165
|
+
client: {
|
|
166
|
+
fn: (args) => bookmarkClient.get('v1', args),
|
|
167
|
+
},
|
|
168
|
+
key: ({ id }) => id,
|
|
169
|
+
expire: this.defaultExpireTime,
|
|
170
|
+
},
|
|
171
|
+
getAllBookmarks: {
|
|
172
|
+
client: {
|
|
173
|
+
fn: () => bookmarkClient.getAll('v1'),
|
|
174
|
+
},
|
|
175
|
+
key: () => 'all-bookmarks',
|
|
176
|
+
validate: ({ args }) => args.isValid,
|
|
177
|
+
expire: this.defaultExpireTime,
|
|
178
|
+
},
|
|
179
|
+
...bookmarkClient,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return config as BookmarkClientConfig;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
protected async _getServiceProvider(
|
|
187
|
+
init: ModuleInitializerArgs<IBookmarkModuleConfigurator, [ServicesModule]>
|
|
188
|
+
): Promise<IApiProvider> {
|
|
189
|
+
if (init.hasModule('services')) {
|
|
190
|
+
return init.requireInstance('services');
|
|
191
|
+
} else {
|
|
192
|
+
const parentServiceModule = (init.ref as ModulesInstanceType<[ServicesModule]>)
|
|
193
|
+
?.services;
|
|
194
|
+
if (parentServiceModule) {
|
|
195
|
+
return parentServiceModule;
|
|
196
|
+
}
|
|
197
|
+
throw Error('[BookmarkConfigurator] No service provider configures [ServicesModule] ');
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
protected async _getContextProvider(
|
|
202
|
+
init: ModuleInitializerArgs<IBookmarkModuleConfigurator, [ContextModule]>
|
|
203
|
+
): Promise<IContextProvider> {
|
|
204
|
+
if (init.hasModule('context')) {
|
|
205
|
+
return init.requireInstance('context');
|
|
206
|
+
} else {
|
|
207
|
+
const parentContextModule = (init.ref as ModulesInstanceType<[ContextModule]>)?.context;
|
|
208
|
+
if (parentContextModule) {
|
|
209
|
+
return parentContextModule;
|
|
210
|
+
}
|
|
211
|
+
throw Error('[BookmarkConfigurator] No context provider configures [ContextModule]');
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
protected async _getAppProvider(
|
|
216
|
+
init: ModuleInitializerArgs<IBookmarkModuleConfigurator, [AppModule]>
|
|
217
|
+
): Promise<AppModuleProvider> {
|
|
218
|
+
if (init.hasModule('app')) {
|
|
219
|
+
return init.requireInstance('app');
|
|
220
|
+
} else {
|
|
221
|
+
const parentAppModule = (init.ref as ModulesInstanceType<[AppModule]>)?.app;
|
|
222
|
+
if (parentAppModule) {
|
|
223
|
+
return parentAppModule;
|
|
224
|
+
}
|
|
225
|
+
throw Error('[BookmarkConfigurator] No app provider configures [AppModule]');
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
protected async _getEventProvider(
|
|
229
|
+
init: ModuleInitializerArgs<IBookmarkModuleConfigurator, [EventModule]>
|
|
230
|
+
): Promise<IEventModuleProvider> {
|
|
231
|
+
if (init.hasModule('event')) {
|
|
232
|
+
return init.requireInstance('event');
|
|
233
|
+
} else {
|
|
234
|
+
const parentEventModule = (init.ref as ModulesInstanceType<[EventModule]>)?.event;
|
|
235
|
+
if (parentEventModule) {
|
|
236
|
+
return parentEventModule;
|
|
237
|
+
}
|
|
238
|
+
throw Error('[BookmarkConfigurator] No event provider configures [EventModule]');
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
protected async _getNavigationProvider(
|
|
243
|
+
init: ModuleInitializerArgs<IBookmarkModuleConfigurator, [NavigationModule]>
|
|
244
|
+
): Promise<INavigationProvider> {
|
|
245
|
+
if (init.hasModule('navigation')) {
|
|
246
|
+
return init.requireInstance('navigation');
|
|
247
|
+
} else {
|
|
248
|
+
const parentNavigationModule = (init.ref as ModulesInstanceType<[NavigationModule]>)
|
|
249
|
+
?.navigation;
|
|
250
|
+
if (parentNavigationModule) {
|
|
251
|
+
return parentNavigationModule;
|
|
252
|
+
}
|
|
253
|
+
throw Error(
|
|
254
|
+
'[BookmarkConfigurator] No navigation provider configures [NavigationModule]'
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export default BookmarkModuleConfigurator;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AnyModule,
|
|
3
|
+
IModulesConfigurator,
|
|
4
|
+
ModuleInitializerArgs,
|
|
5
|
+
} from '@equinor/fusion-framework-module';
|
|
6
|
+
import { BookmarkConfigBuilder } from './bookmark-config-builder';
|
|
7
|
+
|
|
8
|
+
import { IBookmarkModuleConfigurator } from './configurator';
|
|
9
|
+
|
|
10
|
+
import { module } from './module';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Method for enabling Bookmark module
|
|
14
|
+
* @param configurator - configuration object
|
|
15
|
+
*/
|
|
16
|
+
export const enableBookmark = (
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
18
|
+
configurator: IModulesConfigurator<any, any>,
|
|
19
|
+
builder?: <TDeps extends Array<AnyModule> = []>(
|
|
20
|
+
builder: BookmarkConfigBuilder<
|
|
21
|
+
TDeps,
|
|
22
|
+
ModuleInitializerArgs<IBookmarkModuleConfigurator, TDeps>
|
|
23
|
+
>
|
|
24
|
+
) => void | Promise<void>
|
|
25
|
+
): void => {
|
|
26
|
+
configurator.addConfig({
|
|
27
|
+
module,
|
|
28
|
+
configure: (contextConfigurator) => {
|
|
29
|
+
builder && contextConfigurator.addConfigBuilder(builder);
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export {
|
|
2
|
+
BookmarkModuleConfigurator,
|
|
3
|
+
IBookmarkModuleConfigurator,
|
|
4
|
+
BookmarkModuleConfig,
|
|
5
|
+
} from './configurator';
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
default,
|
|
9
|
+
BookmarkModule,
|
|
10
|
+
module as bookmarkModule,
|
|
11
|
+
moduleKey as bookmarkModuleKey,
|
|
12
|
+
} from './module';
|
|
13
|
+
|
|
14
|
+
export { IBookmarkModuleProvider, BookmarkModuleProvider } from './bookmark-provider';
|
|
15
|
+
|
|
16
|
+
export { enableBookmark } from './enable-bookmark';
|
|
17
|
+
|
|
18
|
+
export * from './types';
|