@equinor/fusion-framework-react-components-bookmark 1.0.8 → 1.0.10

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 (50) hide show
  1. package/CHANGELOG.md +234 -215
  2. package/dist/esm/components/Bookmark.js.map +1 -1
  3. package/dist/esm/components/BookmarkProvider.js.map +1 -1
  4. package/dist/esm/components/create-bookmark/CreateBookmark.js.map +1 -1
  5. package/dist/esm/components/edit-bookmark/EditBookmark.js +1 -3
  6. package/dist/esm/components/edit-bookmark/EditBookmark.js.map +1 -1
  7. package/dist/esm/components/filter/Filter.js +2 -5
  8. package/dist/esm/components/filter/Filter.js.map +1 -1
  9. package/dist/esm/components/import-bookmark/ImportBookmark.js.map +1 -1
  10. package/dist/esm/components/loading/Loading.js.map +1 -1
  11. package/dist/esm/components/messages/Message.js.map +1 -1
  12. package/dist/esm/components/row/MoreMenu.js.map +1 -1
  13. package/dist/esm/components/row/Row.js.map +1 -1
  14. package/dist/esm/components/section/Section.js.map +1 -1
  15. package/dist/esm/components/sectionList/SectionList.js.map +1 -1
  16. package/dist/esm/components/shared/SharedIcon.js.map +1 -1
  17. package/dist/esm/hooks/useBookmarkGrouping.js.map +1 -1
  18. package/dist/esm/utils/append-bookmark-to-uri.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/esm/version.js.map +1 -1
  22. package/dist/tsconfig.tsbuildinfo +1 -1
  23. package/dist/types/components/BookmarkProvider.d.ts +1 -1
  24. package/dist/types/components/filter/Filter.d.ts +1 -1
  25. package/dist/types/components/messages/Message.d.ts +1 -1
  26. package/dist/types/components/row/MoreMenu.d.ts +2 -2
  27. package/dist/types/components/row/Row.d.ts +1 -1
  28. package/dist/types/components/section/Section.d.ts +1 -1
  29. package/dist/types/components/sectionList/SectionList.d.ts +1 -1
  30. package/dist/types/hooks/useBookmarkGrouping.d.ts +1 -1
  31. package/dist/types/utils/utils.d.ts +1 -1
  32. package/dist/types/version.d.ts +1 -1
  33. package/package.json +8 -8
  34. package/src/components/Bookmark.tsx +46 -47
  35. package/src/components/BookmarkProvider.tsx +78 -78
  36. package/src/components/create-bookmark/CreateBookmark.tsx +96 -96
  37. package/src/components/edit-bookmark/EditBookmark.tsx +149 -152
  38. package/src/components/filter/Filter.tsx +21 -41
  39. package/src/components/import-bookmark/ImportBookmark.tsx +61 -65
  40. package/src/components/loading/Loading.tsx +11 -11
  41. package/src/components/messages/Message.tsx +47 -47
  42. package/src/components/row/MoreMenu.tsx +27 -27
  43. package/src/components/row/Row.tsx +56 -56
  44. package/src/components/section/Section.tsx +17 -17
  45. package/src/components/sectionList/SectionList.tsx +137 -143
  46. package/src/components/shared/SharedIcon.tsx +19 -19
  47. package/src/hooks/useBookmarkGrouping.ts +37 -37
  48. package/src/utils/append-bookmark-to-uri.ts +3 -3
  49. package/src/utils/utils.ts +6 -6
  50. package/src/version.ts +1 -1
@@ -1,4 +1,4 @@
1
- import { ChangeEvent, useCallback, useEffect, useMemo, useState } from 'react';
1
+ import { type ChangeEvent, useCallback, useEffect, useMemo, useState } from 'react';
2
2
 
3
3
  import { EMPTY, from, of } from 'rxjs';
4
4
 
@@ -14,173 +14,170 @@ import styled from 'styled-components';
14
14
  import { useBookmarkComponentContext } from '../BookmarkProvider';
15
15
 
16
16
  const Styled = {
17
- Dialog: styled(Dialog)`
17
+ Dialog: styled(Dialog)`
18
18
  width: 500px;
19
19
  `,
20
- DialogContent: styled(Dialog.Content)`
20
+ DialogContent: styled(Dialog.Content)`
21
21
  display: flex;
22
22
  flex-direction: column;
23
23
  gap: 1rem;
24
24
  `,
25
- CheckboxWrapper: styled.div`
25
+ CheckboxWrapper: styled.div`
26
26
  display: flex;
27
27
  gap: 1rem;
28
28
  `,
29
- Actions: styled.div`
29
+ Actions: styled.div`
30
30
  display: flex;
31
31
  gap: 0.2em;
32
32
  `,
33
33
  };
34
34
 
35
35
  export const EditBookmarkModal = ({
36
- isOpen,
37
- onClose,
38
- bookmarkId,
36
+ isOpen,
37
+ onClose,
38
+ bookmarkId,
39
39
  }: {
40
- readonly isOpen: boolean;
41
- readonly onClose: (b: boolean) => void;
42
- readonly bookmarkId: string;
40
+ readonly isOpen: boolean;
41
+ readonly onClose: (b: boolean) => void;
42
+ readonly bookmarkId: string;
43
43
  }) => {
44
- const { provider, addBookmarkToClipboard, currentApp } = useBookmarkComponentContext();
45
-
46
- const [state, setState] = useState<BookmarkUpdate>({
47
- name: '',
48
- description: '',
49
- isShared: false,
50
- });
51
-
52
- const [updatePayload, setUpdatePayload] = useState(false);
53
-
54
- const bookmark$ = useMemo(
55
- () => from(provider ? provider.getBookmark(bookmarkId) : EMPTY),
56
- [provider, bookmarkId],
57
- );
58
-
59
- const { value: bookmark, complete: isLoadingBookmark } = useObservableState(bookmark$);
60
-
61
- // set the state when the bookmark is loaded
62
- useEffect(() => {
63
- if (bookmark) {
64
- const { name, description, isShared } = bookmark;
65
- setState({ name, description, isShared });
66
- }
67
- }, [bookmark]);
68
-
69
- // TODO - this should be on the bookmark object
70
- const appProvider = useFrameworkModule<AppModule>('app');
71
- const { value: appName } = useObservableState(
72
- useMemo(
73
- () =>
74
- bookmark && appProvider
75
- ? appProvider.getAppManifest(bookmark.appKey)
76
- : of(undefined),
77
- [appProvider, bookmark],
78
- ),
79
- );
80
-
81
- const updateBookmark = useCallback(
82
- async (updates: BookmarkUpdate) => {
83
- if (!provider) {
84
- console.error('Provider not available');
85
- return;
86
- }
87
- from(
88
- provider.updateBookmark(bookmarkId, updates, {
89
- excludePayloadGeneration: !updatePayload,
90
- }),
91
- ).subscribe({
92
- next: (updatedBookmark) => {
93
- console.debug('Bookmark updated', updatedBookmark);
94
- },
95
- error: (error) => {
96
- console.error('Failed to update bookmark', error);
97
- },
98
- complete: () => {
99
- onClose(false);
100
- },
101
- });
102
- // TODO: Show success message
103
- // TODO: should this call onUpdated, with the updated bookmark?
104
- onClose(false);
44
+ const { provider, addBookmarkToClipboard, currentApp } = useBookmarkComponentContext();
45
+
46
+ const [state, setState] = useState<BookmarkUpdate>({
47
+ name: '',
48
+ description: '',
49
+ isShared: false,
50
+ });
51
+
52
+ const [updatePayload, setUpdatePayload] = useState(false);
53
+
54
+ const bookmark$ = useMemo(
55
+ () => from(provider ? provider.getBookmark(bookmarkId) : EMPTY),
56
+ [provider, bookmarkId],
57
+ );
58
+
59
+ const { value: bookmark, complete: isLoadingBookmark } = useObservableState(bookmark$);
60
+
61
+ // set the state when the bookmark is loaded
62
+ useEffect(() => {
63
+ if (bookmark) {
64
+ const { name, description, isShared } = bookmark;
65
+ setState({ name, description, isShared });
66
+ }
67
+ }, [bookmark]);
68
+
69
+ // TODO - this should be on the bookmark object
70
+ const appProvider = useFrameworkModule<AppModule>('app');
71
+ const { value: appName } = useObservableState(
72
+ useMemo(
73
+ () => (bookmark && appProvider ? appProvider.getAppManifest(bookmark.appKey) : of(undefined)),
74
+ [appProvider, bookmark],
75
+ ),
76
+ );
77
+
78
+ const updateBookmark = useCallback(
79
+ async (updates: BookmarkUpdate) => {
80
+ if (!provider) {
81
+ console.error('Provider not available');
82
+ return;
83
+ }
84
+ from(
85
+ provider.updateBookmark(bookmarkId, updates, {
86
+ excludePayloadGeneration: !updatePayload,
87
+ }),
88
+ ).subscribe({
89
+ next: (updatedBookmark) => {
90
+ console.debug('Bookmark updated', updatedBookmark);
105
91
  },
106
- [onClose, provider, bookmarkId, updatePayload],
107
- );
108
-
109
- // TODO - add loading spinner
110
- isLoadingBookmark;
111
-
112
- return (
113
- <Styled.Dialog open={isOpen}>
114
- <Dialog.Header>Edit bookmark</Dialog.Header>
115
- <Styled.DialogContent>
116
- <div>
117
- <Label htmlFor="name" label="Name" />
118
- <Input
119
- id="name"
120
- autoComplete="off"
121
- value={state?.name}
122
- onChange={(event: ChangeEvent<HTMLInputElement>) => {
123
- setState((s) => ({ ...s, name: event.target.value }));
124
- }}
125
- />
126
- </div>
127
- <div>
128
- <TextField
129
- id="storybook-multiline-three"
130
- label="Description"
131
- value={state?.description}
132
- multiline
133
- rows={3}
134
- rowsMax={10}
135
- onChange={(event: ChangeEvent<HTMLInputElement>) => {
136
- setState((s) => ({ ...s, description: event.target.value }));
137
- }}
138
- />
139
- </div>
140
- <div>
141
- <Label htmlFor="app" label="App" />
142
- {/** TODO - show ghost while loading app name */}
143
- <Input readOnly={true} value={appName?.displayName || ''} />
144
- </div>
145
-
146
- <Styled.CheckboxWrapper>
147
- <Checkbox
148
- label="Is Shared"
149
- checked={state.isShared}
150
- onChange={(changeEvent: ChangeEvent<HTMLInputElement>) => {
151
- const isShared = changeEvent.target.checked;
152
- if (isShared) {
153
- addBookmarkToClipboard(bookmarkId);
154
- }
155
- setState((s) => ({ ...s, isShared }));
156
- }}
157
- />
158
- {/* only allow updating payload if the app is the same as the creator of the app */}
159
- {bookmark?.appKey === currentApp?.name && provider?.canCreateBookmarks && (
160
- <Checkbox
161
- label="Update bookmark with current view"
162
- checked={updatePayload}
163
- onChange={() => {
164
- setUpdatePayload((s) => !s);
165
- }}
166
- />
167
- )}
168
- </Styled.CheckboxWrapper>
169
- </Styled.DialogContent>
170
- <Dialog.Actions>
171
- <Styled.Actions>
172
- <Button onClick={() => onClose(false)} variant="ghost">
173
- Cancel
174
- </Button>
175
- <Button
176
- onClick={() => {
177
- updateBookmark(state);
178
- }}
179
- >
180
- Save
181
- </Button>
182
- </Styled.Actions>
183
- </Dialog.Actions>
184
- </Styled.Dialog>
185
- );
92
+ error: (error) => {
93
+ console.error('Failed to update bookmark', error);
94
+ },
95
+ complete: () => {
96
+ onClose(false);
97
+ },
98
+ });
99
+ // TODO: Show success message
100
+ // TODO: should this call onUpdated, with the updated bookmark?
101
+ onClose(false);
102
+ },
103
+ [onClose, provider, bookmarkId, updatePayload],
104
+ );
105
+
106
+ // TODO - add loading spinner
107
+ isLoadingBookmark;
108
+
109
+ return (
110
+ <Styled.Dialog open={isOpen}>
111
+ <Dialog.Header>Edit bookmark</Dialog.Header>
112
+ <Styled.DialogContent>
113
+ <div>
114
+ <Label htmlFor="name" label="Name" />
115
+ <Input
116
+ id="name"
117
+ autoComplete="off"
118
+ value={state?.name}
119
+ onChange={(event: ChangeEvent<HTMLInputElement>) => {
120
+ setState((s) => ({ ...s, name: event.target.value }));
121
+ }}
122
+ />
123
+ </div>
124
+ <div>
125
+ <TextField
126
+ id="storybook-multiline-three"
127
+ label="Description"
128
+ value={state?.description}
129
+ multiline
130
+ rows={3}
131
+ rowsMax={10}
132
+ onChange={(event: ChangeEvent<HTMLInputElement>) => {
133
+ setState((s) => ({ ...s, description: event.target.value }));
134
+ }}
135
+ />
136
+ </div>
137
+ <div>
138
+ <Label htmlFor="app" label="App" />
139
+ {/** TODO - show ghost while loading app name */}
140
+ <Input readOnly={true} value={appName?.displayName || ''} />
141
+ </div>
142
+
143
+ <Styled.CheckboxWrapper>
144
+ <Checkbox
145
+ label="Is Shared"
146
+ checked={state.isShared}
147
+ onChange={(changeEvent: ChangeEvent<HTMLInputElement>) => {
148
+ const isShared = changeEvent.target.checked;
149
+ if (isShared) {
150
+ addBookmarkToClipboard(bookmarkId);
151
+ }
152
+ setState((s) => ({ ...s, isShared }));
153
+ }}
154
+ />
155
+ {/* only allow updating payload if the app is the same as the creator of the app */}
156
+ {bookmark?.appKey === currentApp?.name && provider?.canCreateBookmarks && (
157
+ <Checkbox
158
+ label="Update bookmark with current view"
159
+ checked={updatePayload}
160
+ onChange={() => {
161
+ setUpdatePayload((s) => !s);
162
+ }}
163
+ />
164
+ )}
165
+ </Styled.CheckboxWrapper>
166
+ </Styled.DialogContent>
167
+ <Dialog.Actions>
168
+ <Styled.Actions>
169
+ <Button onClick={() => onClose(false)} variant="ghost">
170
+ Cancel
171
+ </Button>
172
+ <Button
173
+ onClick={() => {
174
+ updateBookmark(state);
175
+ }}
176
+ >
177
+ Save
178
+ </Button>
179
+ </Styled.Actions>
180
+ </Dialog.Actions>
181
+ </Styled.Dialog>
182
+ );
186
183
  };
@@ -1,18 +1,18 @@
1
1
  import { Search, Autocomplete } from '@equinor/eds-core-react';
2
- import { GroupingKeys } from '../../hooks/useBookmarkGrouping';
2
+ import type { GroupingKeys } from '../../hooks/useBookmarkGrouping';
3
3
 
4
4
  import styled from 'styled-components';
5
5
 
6
6
  type BookmarkFilterProps = {
7
- readonly searchText: string;
8
- readonly setSearchText: (newVal: string | null) => void;
9
- readonly setGroupBy: (groupBy: GroupingKeys) => void;
10
- readonly groupingModes: string[];
11
- readonly groupBy: string;
7
+ readonly searchText: string;
8
+ readonly setSearchText: (newVal: string | null) => void;
9
+ readonly setGroupBy: (groupBy: GroupingKeys) => void;
10
+ readonly groupingModes: string[];
11
+ readonly groupBy: string;
12
12
  };
13
13
 
14
14
  const Styled = {
15
- Root: styled.div`
15
+ Root: styled.div`
16
16
  display: flex;
17
17
  align-items: center;
18
18
  justify-content: space-between;
@@ -20,39 +20,19 @@ const Styled = {
20
20
  };
21
21
 
22
22
  export const BookmarkFilter = ({
23
- searchText,
24
- setGroupBy,
25
- setSearchText,
26
- groupingModes,
27
- groupBy,
23
+ searchText,
24
+ setGroupBy,
25
+ setSearchText,
26
+ groupingModes,
27
+ groupBy,
28
28
  }: BookmarkFilterProps) => {
29
- return (
30
- <Search
31
- placeholder="Search in my bookmarks"
32
- value={searchText ?? ''}
33
- onChange={(e) => {
34
- setSearchText(e.currentTarget.value.length ? e.currentTarget.value : null);
35
- }}
36
- />
37
- );
38
- return (
39
- <Styled.Root>
40
- <Search
41
- placeholder="Search in my bookmarks"
42
- value={searchText ?? ''}
43
- onChange={(e) => {
44
- setSearchText(e.currentTarget.value.length ? e.currentTarget.value : null);
45
- }}
46
- />
47
- <Autocomplete
48
- options={groupingModes}
49
- selectedOptions={[groupBy]}
50
- multiple={false}
51
- hideClearButton
52
- autoWidth
53
- onOptionsChange={(changes) => setGroupBy(changes.selectedItems[0] as GroupingKeys)}
54
- label={''}
55
- />
56
- </Styled.Root>
57
- );
29
+ return (
30
+ <Search
31
+ placeholder="Search in my bookmarks"
32
+ value={searchText ?? ''}
33
+ onChange={(e) => {
34
+ setSearchText(e.currentTarget.value.length ? e.currentTarget.value : null);
35
+ }}
36
+ />
37
+ );
58
38
  };
@@ -8,85 +8,81 @@ import { map, switchMap } from 'rxjs/operators';
8
8
  import { useObservableState } from '@equinor/fusion-observable/react';
9
9
 
10
10
  const Styled = {
11
- Actions: styled.div`
11
+ Actions: styled.div`
12
12
  display: flex;
13
13
  gap: 1rem;
14
14
  `,
15
15
  };
16
16
 
17
17
  export const ImportBookmarkModal = () => {
18
- const [isOpen, setIsOpen] = useState(false);
18
+ const [isOpen, setIsOpen] = useState(false);
19
19
 
20
- const { provider, currentUser } = useBookmarkComponentContext();
20
+ const { provider, currentUser } = useBookmarkComponentContext();
21
21
 
22
- // Observe changes to current bookmark and check if it is already in bookmarks or favorites
23
- const newBookmark$ = useMemo(() => {
24
- if (!provider) {
25
- return of(null);
22
+ // Observe changes to current bookmark and check if it is already in bookmarks or favorites
23
+ const newBookmark$ = useMemo(() => {
24
+ if (!provider) {
25
+ return of(null);
26
+ }
27
+ return provider.currentBookmark$.pipe(
28
+ // filter out null values, not interested in those
29
+ filter((bookmark) => !!bookmark),
30
+ switchMap((bookmark) => {
31
+ const checkBookmark = bookmark && bookmark.createdBy.id !== currentUser?.id;
32
+ if (!checkBookmark) {
33
+ return of(null);
26
34
  }
27
- return provider.currentBookmark$.pipe(
28
- // filter out null values, not interested in those
29
- filter((bookmark) => !!bookmark),
30
- switchMap((bookmark) => {
31
- const checkBookmark = bookmark && bookmark.createdBy.id !== currentUser?.id;
32
- if (!checkBookmark) {
33
- return of(null);
34
- }
35
- return from(provider.isBookmarkInFavorites(bookmark.id)).pipe(
36
- map((isFavorite) => (isFavorite ? null : bookmark)),
37
- );
38
- }),
35
+ return from(provider.isBookmarkInFavorites(bookmark.id)).pipe(
36
+ map((isFavorite) => (isFavorite ? null : bookmark)),
39
37
  );
40
- }, [provider, currentUser?.id]);
38
+ }),
39
+ );
40
+ }, [provider, currentUser?.id]);
41
41
 
42
- const { value: newBookmark } = useObservableState(newBookmark$);
42
+ const { value: newBookmark } = useObservableState(newBookmark$);
43
43
 
44
- useEffect(() => {
45
- if (newBookmark) {
46
- setIsOpen(true);
47
- }
48
- }, [newBookmark]);
44
+ useEffect(() => {
45
+ if (newBookmark) {
46
+ setIsOpen(true);
47
+ }
48
+ }, [newBookmark]);
49
49
 
50
- const onAddBookmarkFavorite = useCallback(
51
- (e: React.MouseEvent<HTMLButtonElement>) => {
52
- if (!provider) {
53
- console.error('Provider not available');
54
- return;
55
- }
56
- from(provider.addBookmarkToFavorites(e.currentTarget.value)).subscribe({
57
- complete: () => {
58
- setIsOpen(false);
59
- },
60
- });
50
+ const onAddBookmarkFavorite = useCallback(
51
+ (e: React.MouseEvent<HTMLButtonElement>) => {
52
+ if (!provider) {
53
+ console.error('Provider not available');
54
+ return;
55
+ }
56
+ from(provider.addBookmarkToFavorites(e.currentTarget.value)).subscribe({
57
+ complete: () => {
58
+ setIsOpen(false);
61
59
  },
62
- [provider],
63
- );
60
+ });
61
+ },
62
+ [provider],
63
+ );
64
64
 
65
- if (!newBookmark) {
66
- return null;
67
- }
65
+ if (!newBookmark) {
66
+ return null;
67
+ }
68
68
 
69
- return (
70
- <Dialog style={{ width: '600px' }} open={isOpen}>
71
- <Dialog.Header>Import bookmark</Dialog.Header>
72
- <Dialog.Content>
73
- <p>This bookmark was created by {newBookmark.createdBy.name}</p>
74
- <p>Would you like to import it?</p>
75
- </Dialog.Content>
76
- <Dialog.Actions>
77
- <Styled.Actions>
78
- <Button
79
- onClick={() => setIsOpen(false)}
80
- variant={'ghost'}
81
- style={{ width: '70px' }}
82
- >
83
- No
84
- </Button>
85
- <Button value={newBookmark.id} onClick={onAddBookmarkFavorite} variant="ghost">
86
- Import
87
- </Button>
88
- </Styled.Actions>
89
- </Dialog.Actions>
90
- </Dialog>
91
- );
69
+ return (
70
+ <Dialog style={{ width: '600px' }} open={isOpen}>
71
+ <Dialog.Header>Import bookmark</Dialog.Header>
72
+ <Dialog.Content>
73
+ <p>This bookmark was created by {newBookmark.createdBy.name}</p>
74
+ <p>Would you like to import it?</p>
75
+ </Dialog.Content>
76
+ <Dialog.Actions>
77
+ <Styled.Actions>
78
+ <Button onClick={() => setIsOpen(false)} variant={'ghost'} style={{ width: '70px' }}>
79
+ No
80
+ </Button>
81
+ <Button value={newBookmark.id} onClick={onAddBookmarkFavorite} variant="ghost">
82
+ Import
83
+ </Button>
84
+ </Styled.Actions>
85
+ </Dialog.Actions>
86
+ </Dialog>
87
+ );
92
88
  };
@@ -2,15 +2,15 @@ import { CircularProgress } from '@equinor/eds-core-react';
2
2
  import React from 'react';
3
3
 
4
4
  export const Loading = () => (
5
- <div
6
- style={{
7
- display: 'flex',
8
- alignItems: 'center',
9
- justifyContent: 'center',
10
- height: '100%',
11
- width: '100%',
12
- }}
13
- >
14
- <CircularProgress />
15
- </div>
5
+ <div
6
+ style={{
7
+ display: 'flex',
8
+ alignItems: 'center',
9
+ justifyContent: 'center',
10
+ height: '100%',
11
+ width: '100%',
12
+ }}
13
+ >
14
+ <CircularProgress />
15
+ </div>
16
16
  );