Bookmark Module
The Bookmark module provides a way to manage bookmarks in the application. It allows users to create, update, and remove bookmarks, as well as manage the current bookmark and the list of bookmarks.
Features
- Create, update, and delete bookmarks
- Manage current bookmark
- Add and remove bookmarks from favorites
- Event listeners for bookmark-related events
Setup
pnpm install @equinor/fusion-framework-module-bookmark
import { enableBookmarkModule } from ' @equinor/fusion-framework-module-bookmark'
const configure = (configurator) => {
enableBookmarkModule(configurator);
}
Configuration
enableBookmarkModule(configurator, async(builder) => {
builder.setSourceSystem({
id: 'source-system-id',
name: 'Source System Name',
});
builder.setFilter('application', true);
builder.setFilter('context', true);
builder.setClient()
builder.setParent()
builder.setContextResolver()
builder.setApplicationResolver()
});
[!NOTE]
When not providing configuration, the configurator will use the parent (ref initiator, example portal framework) configuration, then fallback to default configuration.
SourceSystem
Filter
ContextResolver
ApplicationResolver
BookmarkProvider
The BookmarkProvider
class is responsible for managing bookmarks in the application. It provides methods for creating, updating, and removing bookmarks, as well as managing the current bookmark and the list of bookmarks.
Usage
Creating a Bookmark
To create a new bookmark, use the createBookmark
method:
const newBookmark = {
name: 'My Bookmark',
payload: { },
};
bookmarkProvider.createBookmark(newBookmark).subscribe({
next: (bookmark) => {
console.log('Bookmark created:', bookmark);
},
error: (err) => {
console.error('Failed to create bookmark:', err);
},
});
Updating a Bookmark
To update an existing bookmark, use the updateBookmark
method:
const bookmarkId = 'bookmark-id';
const bookmarkUpdates = {
name: 'Updated Bookmark Name',
payload: { },
};
bookmarkProvider.updateBookmark(bookmarkId, bookmarkUpdates).subscribe({
next: (updatedBookmark) => {
console.log('Bookmark updated:', updatedBookmark);
},
error: (err) => {
console.error('Failed to update bookmark:', err);
},
});
Using payload generator
Callback function which triggers on creation or update of bookmark. It is used to modify the payload of the bookmark.
- payload: The payload of the bookmark, which can be modified of other payload generators.
- initial: The initial payload of the bookmark, which is the payload of the bookmark before any payload generators have been applied.
const bookmarkPayloadGenerator = (payload, initial) => {
payload.counter = payload.counter ?? 0 + initial.counter;
};
Removing a Bookmark
To remove a bookmark, use the removeBookmark
method:
const bookmarkId = 'bookmark-id';
bookmarkProvider.removeBookmark(bookmarkId).subscribe({
next: (result) => {
console.log('Bookmark removed:', result);
},
error: (err) => {
console.error('Failed to remove bookmark:', err);
},
});
Managing Favorites
To add a bookmark to favorites, use the addBookmarkToFavorites
method:
const bookmarkId = 'bookmark-id';
bookmarkProvider.addBookmarkToFavorites(bookmarkId).subscribe({
next: (bookmark) => {
console.log('Bookmark added to favorites:', bookmark);
},
error: (err) => {
console.error('Failed to add bookmark to favorites:', err);
},
});
To remove a bookmark from favorites, use the removeBookmarkFromFavorites
method:
const bookmarkId = 'bookmark-id';
bookmarkProvider.removeBookmarkFromFavorites(bookmarkId).subscribe({
next: (bookmark) => {
console.log('Bookmark removed from favorites:', bookmark);
},
error: (err) => {
console.error('Failed to remove bookmark from favorites:', err);
},
});
To check if a bookmark is in favorites, use the isBookmarkInFavorites
method:
const bookmarkId = 'bookmark-id';
bookmarkProvider.isBookmarkInFavorites(bookmarkId).subscribe({
next: (isFavorite) => {
console.log('Is bookmark in favorites:', isFavorite);
},
error: (err) => {
console.error('Failed to check if bookmark is in favorites:', err);
},
});
Event Listeners
You can register event listeners for various bookmark-related events:
const removeListener = bookmarkProvider.on('onCurrentBookmarkChanged', (event) => {
console.log('Current bookmark changed:', event.detail);
});
removeListener();
Client
The BookmarkClient
class is responsible for fetching bookmarks from the source system. It provides methods for fetching bookmarks by ID, fetching bookmarks by query, and fetching the current bookmark. This is the default implementation of the client and created if not overridden in the configuration.
import { BookmarkClient } from '@equinor/fusion-bookmark';
import { BookmarksApiClient } from '@equinor/fusion-framework-module-services/bookmarks';
import { HttpClient } from '@equinor/fusion-framework-module-http/client';
const httpClient = new HttpClient('https://my-fusion-backend-url.com');
const apiClient = new BookmarksApiClient(httpClient, 'json$');
const client = new BookmarkClient(apiClient);
client.getAllBookmarks().subscribe(bookmarks => {
});
client.getBookmarkById('bookmark-id').subscribe(bookmark => {
});
Custom Client
By implementing the IBookmarkClient
interface, you can create a custom client implementation.
import { IBookmarkClient } from '@equinor/fusion-bookmark';
export class CustomBookmarkClient implements IBookmarkClient {
}
const configure = (configurator) => {
enableBookmarkModule(configurator, async(builder) => {
builder.setClient(new CustomBookmarkClient());
});
};
Tips
Using "shared" creator across multiple components
The bookmark module is designed to allow multiple subscribers to collectively manage the payload of an bookmark. This is done by using a payload generator that is triggered on creation and update of the bookmark. This allows multiple components to share the same payload and update it in a safe way.
To solve this complex problem, internally the bookmark provider uses immer to generate a draft of the payload (a reducer function to update the payload, prevent flux and mutation). This allows the payload to be updated in a safe way, without the need to worry about immutability.
BAD!
const RootComponent = () => {
const {
addBookmarkCreator,
currentBookmark
} = useBookmark();
const payloadRef = useRef(currentBookmark?.payload ?? {});
useEffect(() => {
return addBookmarkCreator(() => payloadRef.current);
}, [bookmarkProvider]);
useEffect(() => {
payloadRef.current = currentBookmark?.payload ?? {};
}, [currentBookmark]);
return (
<>
<Component1 payloadRef={payloadRef} />
<Component2 payloadRef={payloadRef} />
</>
);
}
const Component1 = ({ payloadRef }) => {
return <input
value={ payloadRef.current.foo }
onChange={(e) => payloadRef.current.foo = e.target.value }
/>
}
const Component2 = ({ payloadRef }) => { ... }
this version can be improved by updating the payload generator, but see next example to migrate of deprecated useBookmark
to useCurrentBookmark
.
useEffect(() => {
return addBookmarkCreator((payload) => {
Object.assign(payload, payloadRef.current);
});
}, [bookmarkProvider]);
BETTER!
const RootComponent = () => {
return (
<>
<Component1 />
<Component2 />
</>
);
}
const Component1 = () => {
const ref = useRef(null);
const payloadGenerator = useCallback((payload) => {
payload.foo = ref.current.value;
}, []);
const { currentBookmark } = useCurrentBookmark({ payloadGenerator });
useEffect(() => {
ref.current.value = currentBookmark.foo;
}, [currentBookmark]);
return <input ref={ref} />
}
Component2 = () => { ... }