@equinor/fusion-framework-react-components-bookmark 0.5.3 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/esm/components/Bookmark.js +29 -17
  3. package/dist/esm/components/Bookmark.js.map +1 -1
  4. package/dist/esm/components/BookmarkProvider.js +47 -9
  5. package/dist/esm/components/BookmarkProvider.js.map +1 -1
  6. package/dist/esm/components/create-bookmark/CreateBookmark.js +31 -12
  7. package/dist/esm/components/create-bookmark/CreateBookmark.js.map +1 -1
  8. package/dist/esm/components/create-bookmark/index.js +1 -1
  9. package/dist/esm/components/create-bookmark/index.js.map +1 -1
  10. package/dist/esm/components/edit-bookmark/EditBookmark.js +44 -19
  11. package/dist/esm/components/edit-bookmark/EditBookmark.js.map +1 -1
  12. package/dist/esm/components/import-bookmark/ImportBookmark.js +42 -13
  13. package/dist/esm/components/import-bookmark/ImportBookmark.js.map +1 -1
  14. package/dist/esm/components/row/Row.js +3 -3
  15. package/dist/esm/components/row/Row.js.map +1 -1
  16. package/dist/esm/components/sectionList/SectionList.js +69 -67
  17. package/dist/esm/components/sectionList/SectionList.js.map +1 -1
  18. package/dist/esm/hooks/useBookmarkGrouping.js.map +1 -1
  19. package/dist/esm/utils/utils.js.map +1 -1
  20. package/dist/esm/version.js +1 -1
  21. package/dist/tsconfig.tsbuildinfo +1 -1
  22. package/dist/types/components/BookmarkProvider.d.ts +16 -1
  23. package/dist/types/components/create-bookmark/index.d.ts +1 -1
  24. package/dist/types/components/edit-bookmark/EditBookmark.d.ts +1 -1
  25. package/dist/types/hooks/useBookmarkGrouping.d.ts +40 -4
  26. package/dist/types/utils/utils.d.ts +3 -3
  27. package/dist/types/version.d.ts +1 -1
  28. package/package.json +6 -4
  29. package/src/components/Bookmark.tsx +42 -31
  30. package/src/components/BookmarkProvider.tsx +74 -14
  31. package/src/components/create-bookmark/CreateBookmark.tsx +30 -13
  32. package/src/components/create-bookmark/index.ts +1 -1
  33. package/src/components/edit-bookmark/EditBookmark.tsx +60 -23
  34. package/src/components/import-bookmark/ImportBookmark.tsx +35 -15
  35. package/src/components/row/Row.tsx +3 -3
  36. package/src/components/sectionList/SectionList.tsx +77 -97
  37. package/src/hooks/useBookmarkGrouping.ts +6 -6
  38. package/src/utils/utils.ts +4 -3
  39. package/src/version.ts +1 -1
@@ -1,6 +1,20 @@
1
1
  import type { FrameworkEvent, FrameworkEventInit } from '@equinor/fusion-framework-module-event';
2
2
  import { PropsWithChildren } from 'react';
3
- export declare const BookmarkProvider: ({ children }: PropsWithChildren<unknown>) => import("react/jsx-runtime").JSX.Element;
3
+ import { type BookmarkProvider as IBookmarkProvider } from '@equinor/fusion-framework-module-bookmark';
4
+ type BookmarkApp = {
5
+ appKey: string;
6
+ name?: string;
7
+ };
8
+ type ProviderState = {
9
+ provider: IBookmarkProvider;
10
+ currentApp?: BookmarkApp | null;
11
+ };
12
+ type BookmarkProviderProps = {
13
+ readonly provider?: IBookmarkProvider | null;
14
+ };
15
+ export declare const useBookmarkComponentContext: () => ProviderState;
16
+ export declare const useBookmarkProvider: () => IBookmarkProvider;
17
+ export declare const BookmarkProvider: (props: PropsWithChildren<BookmarkProviderProps>) => import("react/jsx-runtime").JSX.Element | null;
4
18
  declare module '@equinor/fusion-framework-module-event' {
5
19
  interface FrameworkEventMap {
6
20
  onBookmarkOpen: FrameworkEvent<FrameworkEventInit<boolean, unknown>>;
@@ -12,3 +26,4 @@ declare module '@equinor/fusion-framework-module-event' {
12
26
  }, unknown>>;
13
27
  }
14
28
  }
29
+ export {};
@@ -1 +1 @@
1
- export * from './CreateBookmark';
1
+ export { CreateBookmarkModal } from './CreateBookmark';
@@ -1,5 +1,5 @@
1
1
  export declare const EditBookmarkModal: ({ isOpen, onClose, bookmarkId, }: {
2
2
  readonly isOpen: boolean;
3
3
  readonly onClose: (b: boolean) => void;
4
- readonly bookmarkId?: string;
4
+ readonly bookmarkId: string;
5
5
  }) => import("react/jsx-runtime").JSX.Element;
@@ -1,13 +1,49 @@
1
- import { Bookmark } from '@equinor/fusion-framework-module-bookmark';
1
+ import { Bookmarks, BookmarkWithoutData } from '@equinor/fusion-framework-module-bookmark';
2
2
  export type GroupingKeys = 'Group by app' | 'Created by' | 'Group by Context';
3
- export declare const useBookmarkGrouping: (bookmarks?: Bookmark[]) => {
3
+ export declare const useBookmarkGrouping: (bookmarks?: Bookmarks) => {
4
4
  setGroupBy: import("react").Dispatch<import("react").SetStateAction<GroupingKeys>>;
5
5
  setSearchText: import("react").Dispatch<import("react").SetStateAction<string | null>>;
6
6
  searchText: string | null;
7
7
  bookmarkGroups: {
8
8
  groupingProperty: string;
9
- values: Bookmark<unknown>[];
9
+ values: {
10
+ name: string;
11
+ id: string;
12
+ appKey: string;
13
+ created: Date;
14
+ createdBy: {
15
+ azureUniqueId: string;
16
+ name: string;
17
+ mail?: string | undefined;
18
+ phoneNumber?: string | undefined;
19
+ jobTitle?: string | undefined;
20
+ accountType?: "Employee" | "Consultant" | "External" | "Application" | "Local" | undefined;
21
+ accountClassification?: "External" | "Unclassified" | "Internal" | undefined;
22
+ };
23
+ description?: string | undefined;
24
+ isShared?: boolean | undefined;
25
+ updated?: Date | undefined;
26
+ updatedBy?: {
27
+ azureUniqueId: string;
28
+ name: string;
29
+ mail?: string | undefined;
30
+ phoneNumber?: string | undefined;
31
+ jobTitle?: string | undefined;
32
+ accountType?: "Employee" | "Consultant" | "External" | "Application" | "Local" | undefined;
33
+ accountClassification?: "External" | "Unclassified" | "Internal" | undefined;
34
+ } | undefined;
35
+ context?: {
36
+ id: string;
37
+ name?: string | undefined;
38
+ type?: string | undefined;
39
+ } | undefined;
40
+ sourceSystem?: {
41
+ identifier: string;
42
+ name?: string | undefined;
43
+ subSystem?: string | undefined;
44
+ } | undefined;
45
+ }[];
10
46
  }[];
11
- groupingModes: Record<GroupingKeys, (_item: Bookmark) => string>;
47
+ groupingModes: Record<GroupingKeys, (_item: BookmarkWithoutData) => string>;
12
48
  groupByKey: GroupingKeys;
13
49
  };
@@ -1,7 +1,7 @@
1
- import { Bookmark } from '@equinor/fusion-framework-module-bookmark';
1
+ import { Bookmarks, BookmarkWithoutData } from '@equinor/fusion-framework-module-bookmark';
2
2
  /** Helpers.. */
3
3
  export declare const filterEmptyGroups: (i: {
4
- values: Bookmark[];
4
+ values: Bookmarks;
5
5
  }) => number;
6
- export declare const sortByName: (a: Bookmark, b: Bookmark) => number;
6
+ export declare const sortByName: (a: BookmarkWithoutData, b: BookmarkWithoutData) => number;
7
7
  export declare const toHumanReadable: (val: string) => string;
@@ -1 +1 @@
1
- export declare const version = "0.5.3";
1
+ export declare const version = "1.0.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@equinor/fusion-framework-react-components-bookmark",
3
- "version": "0.5.3",
3
+ "version": "1.0.0",
4
4
  "description": "",
5
5
  "main": "dist/esm/index.js",
6
6
  "exports": {
@@ -22,8 +22,10 @@
22
22
  "directory": "packages/react/components/bookmark"
23
23
  },
24
24
  "dependencies": {
25
- "@equinor/fusion-framework-react-module-bookmark": "^2.1.19",
26
- "@equinor/fusion-framework-react": "^7.3.1"
25
+ "@equinor/fusion-observable": "^8.3.3",
26
+ "rxjs": "^7.8.1",
27
+ "@equinor/fusion-framework-react": "^7.3.2",
28
+ "@equinor/fusion-framework-react-module-bookmark": "^2.2.0"
27
29
  },
28
30
  "devDependencies": {
29
31
  "@equinor/eds-core-react": "^0.42.0",
@@ -35,7 +37,7 @@
35
37
  "styled-components": "^6.0.7",
36
38
  "typescript": "^5.5.4",
37
39
  "@equinor/fusion-framework-module-app": "^6.0.2",
38
- "@equinor/fusion-framework-module-bookmark": "^1.2.13",
40
+ "@equinor/fusion-framework-module-bookmark": "^2.0.0",
39
41
  "@equinor/fusion-framework-module-event": "^4.2.4"
40
42
  },
41
43
  "peerDependencies": {
@@ -1,8 +1,8 @@
1
- import { useBookmark } from '@equinor/fusion-framework-react-module-bookmark';
1
+ import { EMPTY } from 'rxjs';
2
2
  import { useBookmarkGrouping } from '../hooks';
3
3
  import { BookmarkFilter } from './filter/Filter';
4
4
  import { SectionList } from './sectionList/SectionList';
5
- import { useEffect, useState } from 'react';
5
+ import { useEffect, useMemo, useState } from 'react';
6
6
 
7
7
  import { Icon } from '@equinor/eds-core-react';
8
8
  import { chevron_down, chevron_right, share, more_vertical, add } from '@equinor/eds-icons';
@@ -10,7 +10,8 @@ import { chevron_down, chevron_right, share, more_vertical, add } from '@equinor
10
10
  import styled from 'styled-components';
11
11
  import { Message } from './messages/Message';
12
12
  import { Loading } from './loading/Loading';
13
- import { useFramework } from '@equinor/fusion-framework-react';
13
+ import { useBookmarkComponentContext } from './BookmarkProvider';
14
+ import { useObservableState } from '@equinor/fusion-observable/react';
14
15
 
15
16
  Icon.add({
16
17
  chevron_down,
@@ -42,30 +43,52 @@ const Styled = {
42
43
  };
43
44
 
44
45
  export const Bookmark = () => {
45
- const { bookmarks, getAllBookmarks } = useBookmark();
46
+ const { provider } = useBookmarkComponentContext();
47
+
46
48
  const [loading, setLoading] = useState(true);
49
+ const [error, setError] = useState<Error | null>(null);
47
50
 
48
- const { event } = useFramework().modules;
51
+ const { value: bookmarks } = useObservableState(
52
+ useMemo(() => provider?.bookmarks$ || EMPTY, [provider]),
53
+ { initial: provider?.bookmarks },
54
+ );
49
55
 
50
56
  useEffect(() => {
51
- return event.addEventListener('onBookmarksChanged', () => {
52
- setLoading(false);
57
+ const sub = provider?.getAllBookmarks().subscribe({
58
+ complete: () => {
59
+ setLoading(false);
60
+ },
61
+ error: (err) => {
62
+ setError(err);
63
+ },
53
64
  });
54
- }, [event]);
55
-
56
- useEffect(() => {
57
- if (bookmarks.length > 0) {
58
- setLoading(false);
59
- }
60
- }, [bookmarks]);
61
-
62
- useEffect(() => {
63
- getAllBookmarks();
64
- }, [getAllBookmarks]);
65
+ return () => sub?.unsubscribe();
66
+ }, [provider]);
65
67
 
66
68
  const { bookmarkGroups, groupingModes, searchText, setGroupBy, setSearchText, groupByKey } =
67
69
  useBookmarkGrouping(bookmarks);
68
70
 
71
+ const content = useMemo(() => {
72
+ if (error) {
73
+ return (
74
+ <Message title="Error" type="Error">
75
+ {error.message}
76
+ </Message>
77
+ );
78
+ }
79
+ if (loading) {
80
+ return <Loading />;
81
+ }
82
+ if (bookmarkGroups.length === 0) {
83
+ return (
84
+ <Message title="No Bookmarks" type="NoContent">
85
+ You have not created any bookmarks yet.
86
+ </Message>
87
+ );
88
+ }
89
+ return <SectionList bookmarkGroups={bookmarkGroups} />;
90
+ }, [error, loading, bookmarkGroups]);
91
+
69
92
  return (
70
93
  <Styled.Wrapper>
71
94
  <BookmarkFilter
@@ -75,19 +98,7 @@ export const Bookmark = () => {
75
98
  setGroupBy={setGroupBy}
76
99
  setSearchText={setSearchText}
77
100
  />
78
- <Styled.List>
79
- {bookmarkGroups.length > 0 ? (
80
- <SectionList bookmarkGroups={bookmarkGroups} />
81
- ) : loading ? (
82
- <Loading />
83
- ) : (
84
- <Styled.NoContentWrapper>
85
- <Message title="No Bookmarks" type="NoContent">
86
- You have not created any bookmarks yet.
87
- </Message>
88
- </Styled.NoContentWrapper>
89
- )}
90
- </Styled.List>
101
+ <Styled.List>{content}</Styled.List>
91
102
  </Styled.Wrapper>
92
103
  );
93
104
  };
@@ -1,30 +1,84 @@
1
1
  import { Snackbar } from '@equinor/eds-core-react';
2
2
  import type { FrameworkEvent, FrameworkEventInit } from '@equinor/fusion-framework-module-event';
3
3
  import { useFramework } from '@equinor/fusion-framework-react';
4
- import { PropsWithChildren, useEffect, useState } from 'react';
4
+ import { PropsWithChildren, createContext, useContext, useEffect, useMemo, useState } from 'react';
5
5
  import { CreateBookmarkModal } from './create-bookmark';
6
6
  import { EditBookmarkModal } from './edit-bookmark';
7
7
  import { ImportBookmarkModal } from './import-bookmark';
8
+ import {
9
+ BookmarkModule,
10
+ type BookmarkProvider as IBookmarkProvider,
11
+ } from '@equinor/fusion-framework-module-bookmark';
12
+ import { Observable, of } from 'rxjs';
13
+ import { useObservableState } from '@equinor/fusion-observable/react';
14
+
15
+ type BookmarkApp = {
16
+ appKey: string;
17
+ name?: string;
18
+ };
19
+
20
+ type ProviderState = {
21
+ provider: IBookmarkProvider;
22
+ currentApp?: BookmarkApp | null;
23
+ };
24
+
25
+ const bookmarkProviderContext = createContext<ProviderState | null>(null);
26
+
27
+ type BookmarkProviderProps = {
28
+ readonly provider?: IBookmarkProvider | null;
29
+ };
30
+
31
+ export const useBookmarkComponentContext = () =>
32
+ useContext(bookmarkProviderContext) as ProviderState;
33
+
34
+ export const useBookmarkProvider = () => useBookmarkComponentContext().provider;
35
+
36
+ export const BookmarkProvider = (props: PropsWithChildren<BookmarkProviderProps>) => {
37
+ const { event: eventProvider } = useFramework<[BookmarkModule]>().modules;
38
+
39
+ const { provider, children } = props;
8
40
 
9
- export const BookmarkProvider = ({ children }: PropsWithChildren<unknown>) => {
10
41
  const [isCreateBookmarkOpen, setIsCreateBookmarkOpen] = useState(false);
11
42
  const [isEditBookmarkOpen, setIsEditBookmarkOpen] = useState(false);
12
43
  const [editBookmarkId, setEditBookmarkId] = useState<string | undefined>();
13
44
  const [isBookmarkCopy, setIsBookmarkCopy] = useState(false);
14
45
 
15
- const { event } = useFramework().modules;
46
+ // get the current app
47
+ const { value: currentApp } = useObservableState(
48
+ useMemo(() => {
49
+ // if no provider, return null, this should not happen
50
+ if (!provider) {
51
+ return of(null);
52
+ }
53
+ return new Observable<BookmarkApp | null>((observer) => {
54
+ // resolve the application
55
+ const resolveApp = async () => {
56
+ // get the resolved application
57
+ const app = await provider.resolvedApplication();
58
+ // emit the resolved application
59
+ observer.next(app);
60
+ };
61
+ // re-resolve the application when the current app changes
62
+ eventProvider.addEventListener('onCurrentAppChanged', resolveApp);
63
+
64
+ // initial resolve
65
+ resolveApp();
66
+ });
67
+ }, [eventProvider, provider]),
68
+ { initial: undefined },
69
+ );
16
70
 
17
71
  useEffect(() => {
18
- const subOnBookmarkOpen = event.addEventListener('onBookmarkOpen', (e) => {
72
+ const subOnBookmarkOpen = eventProvider.addEventListener('onBookmarkOpen', (e) => {
19
73
  setIsCreateBookmarkOpen(e.detail);
20
74
  });
21
75
 
22
- const subOnBookmarkEdit = event.addEventListener('onBookmarkEdit', (e) => {
76
+ const subOnBookmarkEdit = eventProvider.addEventListener('onBookmarkEdit', (e) => {
23
77
  setEditBookmarkId(e.detail.bookmarkId);
24
78
  setIsEditBookmarkOpen(true);
25
79
  });
26
80
 
27
- const subOnBookmarkUrlCopy = event.addEventListener('onBookmarkUrlCopy', () => {
81
+ const subOnBookmarkUrlCopy = eventProvider.addEventListener('onBookmarkUrlCopy', () => {
28
82
  setIsBookmarkCopy(true);
29
83
  });
30
84
 
@@ -33,16 +87,22 @@ export const BookmarkProvider = ({ children }: PropsWithChildren<unknown>) => {
33
87
  subOnBookmarkOpen();
34
88
  subOnBookmarkUrlCopy();
35
89
  };
36
- }, [event]);
90
+ }, [eventProvider]);
91
+
92
+ if (!provider) {
93
+ return null;
94
+ }
37
95
 
38
96
  return (
39
- <>
97
+ <bookmarkProviderContext.Provider value={{ provider, currentApp }}>
40
98
  <CreateBookmarkModal isOpen={isCreateBookmarkOpen} onClose={setIsCreateBookmarkOpen} />
41
- <EditBookmarkModal
42
- isOpen={isEditBookmarkOpen}
43
- onClose={setIsEditBookmarkOpen}
44
- bookmarkId={editBookmarkId}
45
- />
99
+ {editBookmarkId && (
100
+ <EditBookmarkModal
101
+ isOpen={isEditBookmarkOpen}
102
+ onClose={setIsEditBookmarkOpen}
103
+ bookmarkId={editBookmarkId}
104
+ />
105
+ )}
46
106
  <ImportBookmarkModal />
47
107
  <Snackbar
48
108
  autoHideDuration={2000}
@@ -52,7 +112,7 @@ export const BookmarkProvider = ({ children }: PropsWithChildren<unknown>) => {
52
112
  Bookmark url copied to clipboard
53
113
  </Snackbar>
54
114
  {children}
55
- </>
115
+ </bookmarkProviderContext.Provider>
56
116
  );
57
117
  };
58
118
 
@@ -1,10 +1,11 @@
1
- import { Button, Checkbox, Dialog, Input, Label, TextField } from '@equinor/eds-core-react';
2
- import type { AppModule } from '@equinor/fusion-framework-module-app';
3
- import { useFramework } from '@equinor/fusion-framework-react';
4
- import { useBookmark } from '@equinor/fusion-framework-react-module-bookmark';
5
- import { ChangeEvent, useState } from 'react';
1
+ import { ChangeEvent, useCallback, useEffect, useState } from 'react';
2
+
3
+ import { BookmarkCreateArgs } from '@equinor/fusion-framework-module-bookmark';
4
+ import { useBookmarkComponentContext } from '../BookmarkProvider';
6
5
 
6
+ import { Button, Checkbox, Dialog, Input, Label, TextField } from '@equinor/eds-core-react';
7
7
  import styled from 'styled-components';
8
+
8
9
  // TODO
9
10
  const StyledContent = styled(Dialog.Content)`
10
11
  display: flex;
@@ -19,15 +20,33 @@ export const CreateBookmarkModal = ({
19
20
  readonly isOpen: boolean;
20
21
  readonly onClose: (b: boolean) => void;
21
22
  }) => {
22
- const [state, setState] = useState<{ name: string; description: string; isShared: boolean }>({
23
+ const { provider, currentApp } = useBookmarkComponentContext();
24
+
25
+ const [state, setState] = useState<BookmarkCreateArgs<never>>({
23
26
  name: '',
24
27
  description: '',
25
28
  isShared: false,
26
29
  });
27
30
 
28
- const { current } = useFramework<[AppModule]>().modules.app;
31
+ useEffect(() => {
32
+ setState((s) => ({ ...s, appKey: currentApp?.appKey || '' }));
33
+ }, [currentApp]);
29
34
 
30
- const { createBookmark } = useBookmark();
35
+ const createBookmark = useCallback(
36
+ async (args: BookmarkCreateArgs<never>) => {
37
+ try {
38
+ await provider.createBookmarkAsync(args);
39
+ // TODO: Show success message
40
+ // TODO: should this call onCreated, with the new bookmark?
41
+ // TODO: should current bookmark be updated?
42
+ onClose(false);
43
+ } catch (error) {
44
+ console.error('Failed to create bookmark', error);
45
+ // TODO: Show error message
46
+ }
47
+ },
48
+ [onClose, provider],
49
+ );
31
50
 
32
51
  return (
33
52
  <Dialog style={{ width: '400px' }} open={isOpen}>
@@ -58,7 +77,7 @@ export const CreateBookmarkModal = ({
58
77
  </div>
59
78
  <div>
60
79
  <Label htmlFor="app" label="App" />
61
- <Input readOnly={true} value={current?.manifest?.displayName || ''} />
80
+ <Input readOnly={true} value={currentApp?.name || currentApp?.appKey || ''} />
62
81
  </div>
63
82
 
64
83
  <div>
@@ -77,11 +96,9 @@ export const CreateBookmarkModal = ({
77
96
  Cancel
78
97
  </Button>
79
98
  <Button
99
+ disabled={!currentApp || !state.name}
80
100
  onClick={() => {
81
- state &&
82
- createBookmark(state).then(() => {
83
- onClose(false);
84
- });
101
+ createBookmark(state);
85
102
  }}
86
103
  >
87
104
  Create
@@ -1 +1 @@
1
- export * from './CreateBookmark';
1
+ export { CreateBookmarkModal } from './CreateBookmark';
@@ -1,15 +1,19 @@
1
- import { ChangeEvent, useEffect, useState } from 'react';
1
+ import { ChangeEvent, useCallback, useEffect, useMemo, useState } from 'react';
2
2
 
3
- import { Button, Checkbox, Dialog, Input, Label, TextField } from '@equinor/eds-core-react';
3
+ import { of } from 'rxjs';
4
+
5
+ import { useObservableState } from '@equinor/fusion-observable/react';
6
+
7
+ import { useFramework, useFrameworkModule } from '@equinor/fusion-framework-react';
4
8
  import type { AppModule } from '@equinor/fusion-framework-module-app';
5
- // TODO - export from `@equinor/fusion-framework-react-module-bookmark`
6
- import type { PatchBookmark } from '@equinor/fusion-framework-module-bookmark';
7
- import { useFramework } from '@equinor/fusion-framework-react';
8
- import { useBookmark } from '@equinor/fusion-framework-react-module-bookmark';
9
- import { appendBookmarkIdToUrl } from '../../utils/append-bookmark-to-uri';
9
+ import type { BookmarkUpdate } from '@equinor/fusion-framework-module-bookmark';
10
10
 
11
+ import { Button, Checkbox, Dialog, Input, Label, TextField } from '@equinor/eds-core-react';
11
12
  import styled from 'styled-components';
12
13
 
14
+ import { useBookmarkComponentContext } from '../BookmarkProvider';
15
+ import { appendBookmarkIdToUrl } from '../../utils/append-bookmark-to-uri';
16
+
13
17
  const Styled = {
14
18
  Dialog: styled(Dialog)`
15
19
  width: 500px;
@@ -36,11 +40,11 @@ export const EditBookmarkModal = ({
36
40
  }: {
37
41
  readonly isOpen: boolean;
38
42
  readonly onClose: (b: boolean) => void;
39
- readonly bookmarkId?: string;
43
+ readonly bookmarkId: string;
40
44
  }) => {
41
- const [state, setState] = useState<PatchBookmark>({
42
- id: '',
43
- appKey: '',
45
+ const { provider } = useBookmarkComponentContext();
46
+
47
+ const [state, setState] = useState<BookmarkUpdate>({
44
48
  name: '',
45
49
  description: '',
46
50
  isShared: false,
@@ -48,17 +52,52 @@ export const EditBookmarkModal = ({
48
52
 
49
53
  const [updatePayload, setUpdatePayload] = useState(false);
50
54
 
51
- const { app, event } = useFramework<[AppModule]>().modules;
52
- const { current } = app;
55
+ const { event } = useFramework<[AppModule]>().modules;
53
56
 
54
- const { updateBookmark, bookmarks } = useBookmark();
57
+ const bookmark$ = useMemo(
58
+ () => provider.getBookmark(bookmarkId, { excludePayload: true }),
59
+ [provider, bookmarkId],
60
+ );
61
+
62
+ const { value: bookmark, complete: isLoadingBookmark } = useObservableState(bookmark$);
55
63
 
64
+ // set the state when the bookmark is loaded
56
65
  useEffect(() => {
57
- const bookmark = bookmarks.find((b) => b.id === bookmarkId);
58
66
  if (bookmark) {
59
- setState(bookmark);
67
+ setState({
68
+ name: bookmark.name,
69
+ description: bookmark.description,
70
+ isShared: bookmark.isShared,
71
+ });
60
72
  }
61
- }, [bookmarkId, bookmarks]);
73
+ }, [bookmark]);
74
+
75
+ // TODO - this should be on the bookmark object
76
+ const appProvider = useFrameworkModule<AppModule>('app');
77
+ const { value: appName } = useObservableState(
78
+ useMemo(
79
+ () =>
80
+ bookmark && appProvider
81
+ ? appProvider.getAppManifest(bookmark.appKey)
82
+ : of(undefined),
83
+ [appProvider, bookmark],
84
+ ),
85
+ );
86
+
87
+ const updateBookmark = useCallback(
88
+ async (updates: BookmarkUpdate) => {
89
+ await provider.updateBookmarkAsync(bookmarkId, updates, {
90
+ excludePayloadGeneration: !updatePayload,
91
+ });
92
+ // TODO: Show success message
93
+ // TODO: should this call onUpdated, with the updated bookmark?
94
+ onClose(false);
95
+ },
96
+ [onClose, provider, bookmarkId, updatePayload],
97
+ );
98
+
99
+ // TODO - add loading spinner
100
+ isLoadingBookmark;
62
101
 
63
102
  return (
64
103
  <Styled.Dialog open={isOpen}>
@@ -90,7 +129,8 @@ export const EditBookmarkModal = ({
90
129
  </div>
91
130
  <div>
92
131
  <Label htmlFor="app" label="App" />
93
- <Input readOnly={true} value={current?.manifest?.displayName || ''} />
132
+ {/** TODO - show ghost while loading app name */}
133
+ <Input readOnly={true} value={appName || ''} />
94
134
  </div>
95
135
 
96
136
  <Styled.CheckboxWrapper>
@@ -99,7 +139,7 @@ export const EditBookmarkModal = ({
99
139
  checked={state.isShared}
100
140
  onChange={(changeEvent: ChangeEvent<HTMLInputElement>) => {
101
141
  if (changeEvent.target.checked) {
102
- const url = appendBookmarkIdToUrl(state.id);
142
+ const url = appendBookmarkIdToUrl(bookmark?.id || '');
103
143
  navigator.clipboard.writeText(url);
104
144
  event.dispatchEvent('onBookmarkUrlCopy', { detail: { url } });
105
145
  }
@@ -122,10 +162,7 @@ export const EditBookmarkModal = ({
122
162
  </Button>
123
163
  <Button
124
164
  onClick={() => {
125
- state &&
126
- updateBookmark(state, { updatePayload }).then(() => {
127
- onClose(false);
128
- });
165
+ updateBookmark(state);
129
166
  }}
130
167
  >
131
168
  Save
@@ -1,8 +1,10 @@
1
1
  import { Button, Dialog } from '@equinor/eds-core-react';
2
- import { useBookmark } from '@equinor/fusion-framework-react-module-bookmark';
3
- import { useEffect, useState } from 'react';
2
+ import { useObservableState } from '@equinor/fusion-observable/react';
3
+ import { useCallback, useEffect, useMemo, useState } from 'react';
4
4
 
5
5
  import styled from 'styled-components';
6
+ import { useBookmarkComponentContext } from '../BookmarkProvider';
7
+ import { useCurrentBookmark } from '@equinor/fusion-framework-react-module-bookmark';
6
8
 
7
9
  const Styled = {
8
10
  Actions: styled.div`
@@ -14,15 +16,40 @@ const Styled = {
14
16
  export const ImportBookmarkModal = () => {
15
17
  const [isOpen, setIsOpen] = useState(false);
16
18
 
17
- const { currentBookmark, bookmarks, addBookmarkFavorite } = useBookmark();
19
+ const { provider } = useBookmarkComponentContext();
20
+ const { value: bookmarks, complete: bookmarksLoaded } = useObservableState(
21
+ useMemo(() => provider.bookmarks$, [provider]),
22
+ { initial: [] },
23
+ );
24
+
25
+ const { currentBookmark } = useCurrentBookmark({ provider });
18
26
 
19
27
  useEffect(() => {
20
- if (!bookmarks || !currentBookmark || bookmarks.length === 0) return;
28
+ if (bookmarksLoaded && currentBookmark) {
29
+ // TODO: this should rather use the provider.isFavorite, but the bookmark should have flag for if the bookmark is created by the user
30
+ const hasBookmark = bookmarks.find(({ id }) => id === currentBookmark.id);
31
+ if (!hasBookmark) {
32
+ setIsOpen(true);
33
+ }
34
+ }
35
+ }, [bookmarks, currentBookmark, bookmarksLoaded]);
21
36
 
22
- if (bookmarks.findIndex(({ id }) => id === currentBookmark.id) === -1) {
23
- setIsOpen(true);
37
+ const onAddBookmarkFavorite = useCallback(async () => {
38
+ if (currentBookmark) {
39
+ try {
40
+ // TODO: missing state for disabling button
41
+ await provider.addBookmarkToFavoritesAsync(currentBookmark.id);
42
+ // TODO: Show success message
43
+ } catch (error) {
44
+ console.error('Failed to add bookmark to favorites', error);
45
+ // TODO: Show error message
46
+ }
47
+ await provider.addBookmarkToFavoritesAsync(currentBookmark.id);
48
+ } else {
49
+ console.error('No bookmark to add to favorites');
50
+ // TODO: Show error message
24
51
  }
25
- }, [bookmarks, currentBookmark]);
52
+ }, [provider, currentBookmark]);
26
53
 
27
54
  return (
28
55
  <Dialog style={{ width: '600px' }} open={isOpen}>
@@ -40,14 +67,7 @@ export const ImportBookmarkModal = () => {
40
67
  >
41
68
  No
42
69
  </Button>
43
- <Button
44
- onClick={() => {
45
- console.log(currentBookmark?.id);
46
- currentBookmark && addBookmarkFavorite(currentBookmark.id);
47
- setIsOpen(false);
48
- }}
49
- variant="ghost"
50
- >
70
+ <Button onClick={onAddBookmarkFavorite} variant="ghost">
51
71
  Import
52
72
  </Button>
53
73
  </Styled.Actions>