@axinom/mosaic-ui 0.75.0-rc.5 → 0.77.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/dist/THIRD-PARTY-LICENSES.txt +1296 -0
- package/dist/cjs/components/ActionBar/ActionBar.d.ts +26 -0
- package/dist/cjs/components/ActionBar/ActionBar.d.ts.map +1 -0
- package/dist/cjs/components/ActionBar/ActionBar.model.d.ts +49 -0
- package/dist/cjs/components/ActionBar/ActionBar.model.d.ts.map +1 -0
- package/dist/cjs/components/ActionBar/ActionBarButton/ActionBarButton.d.ts +22 -0
- package/dist/cjs/components/ActionBar/ActionBarButton/ActionBarButton.d.ts.map +1 -0
- package/dist/cjs/components/ActionBar/helpers.d.ts +22 -0
- package/dist/cjs/components/ActionBar/helpers.d.ts.map +1 -0
- package/dist/cjs/components/ActionBar/index.d.ts +3 -0
- package/dist/cjs/components/ActionBar/index.d.ts.map +1 -0
- package/dist/cjs/components/Actions/Action/Action.d.ts.map +1 -1
- package/dist/cjs/components/ConfirmDialog/index.d.ts +1 -0
- package/dist/cjs/components/ConfirmDialog/index.d.ts.map +1 -1
- package/dist/cjs/components/ConfirmDialog/useConfirmableAction.d.ts +55 -0
- package/dist/cjs/components/ConfirmDialog/useConfirmableAction.d.ts.map +1 -0
- package/dist/cjs/components/Explorer/BulkEdit/useBulkEdit.d.ts.map +1 -1
- package/dist/cjs/components/Explorer/Explorer.d.ts.map +1 -1
- package/dist/cjs/components/Explorer/QuickEdit/useQuickEdit.d.ts +14 -3
- package/dist/cjs/components/Explorer/QuickEdit/useQuickEdit.d.ts.map +1 -1
- package/dist/cjs/components/Explorer/helpers/useActions.d.ts +15 -4
- package/dist/cjs/components/Explorer/helpers/useActions.d.ts.map +1 -1
- package/dist/cjs/components/Explorer/helpers/useSubtitle.d.ts.map +1 -1
- package/dist/cjs/components/List/List.d.ts +17 -3
- package/dist/cjs/components/List/List.d.ts.map +1 -1
- package/dist/cjs/components/List/List.model.d.ts +5 -1
- package/dist/cjs/components/List/List.model.d.ts.map +1 -1
- package/dist/cjs/components/List/ListHeader/ListHeader.d.ts +10 -1
- package/dist/cjs/components/List/ListHeader/ListHeader.d.ts.map +1 -1
- package/dist/cjs/components/List/ListRow/ListRow.d.ts +16 -5
- package/dist/cjs/components/List/ListRow/ListRow.d.ts.map +1 -1
- package/dist/cjs/components/List/ListRowRenderer/ListRowRenderer.d.ts.map +1 -1
- package/dist/cjs/components/List/helpers.d.ts +11 -3
- package/dist/cjs/components/List/helpers.d.ts.map +1 -1
- package/dist/cjs/components/List/useColumnsSize.d.ts +4 -2
- package/dist/cjs/components/List/useColumnsSize.d.ts.map +1 -1
- package/dist/cjs/components/PageHeader/PageHeader.d.ts +4 -1
- package/dist/cjs/components/PageHeader/PageHeader.d.ts.map +1 -1
- package/dist/cjs/components/PageHeader/PageHeader.model.d.ts +37 -1
- package/dist/cjs/components/PageHeader/PageHeader.model.d.ts.map +1 -1
- package/dist/cjs/components/PageHeader/PageHeaderAction/PageHeaderAction.d.ts +3 -0
- package/dist/cjs/components/PageHeader/PageHeaderAction/PageHeaderAction.d.ts.map +1 -1
- package/dist/cjs/components/PageHeader/PageHeaderAction/PageHeaderAction.model.d.ts +8 -0
- package/dist/cjs/components/PageHeader/PageHeaderAction/PageHeaderAction.model.d.ts.map +1 -1
- package/dist/cjs/components/PageHeader/helpers.d.ts +9 -0
- package/dist/cjs/components/PageHeader/helpers.d.ts.map +1 -0
- package/dist/cjs/components/index.d.ts +1 -0
- package/dist/cjs/components/index.d.ts.map +1 -1
- package/dist/cjs/hooks/index.d.ts +1 -0
- package/dist/cjs/hooks/index.d.ts.map +1 -1
- package/dist/cjs/hooks/useElementWidthObserver/useElementWidthObserver.d.ts.map +1 -0
- package/dist/cjs/index.js +4 -4
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/components/ActionBar/ActionBar.d.ts +26 -0
- package/dist/esm/components/ActionBar/ActionBar.d.ts.map +1 -0
- package/dist/esm/components/ActionBar/ActionBar.model.d.ts +49 -0
- package/dist/esm/components/ActionBar/ActionBar.model.d.ts.map +1 -0
- package/dist/esm/components/ActionBar/ActionBarButton/ActionBarButton.d.ts +22 -0
- package/dist/esm/components/ActionBar/ActionBarButton/ActionBarButton.d.ts.map +1 -0
- package/dist/esm/components/ActionBar/helpers.d.ts +22 -0
- package/dist/esm/components/ActionBar/helpers.d.ts.map +1 -0
- package/dist/esm/components/ActionBar/index.d.ts +3 -0
- package/dist/esm/components/ActionBar/index.d.ts.map +1 -0
- package/dist/esm/components/Actions/Action/Action.d.ts.map +1 -1
- package/dist/esm/components/ConfirmDialog/index.d.ts +1 -0
- package/dist/esm/components/ConfirmDialog/index.d.ts.map +1 -1
- package/dist/esm/components/ConfirmDialog/useConfirmableAction.d.ts +55 -0
- package/dist/esm/components/ConfirmDialog/useConfirmableAction.d.ts.map +1 -0
- package/dist/esm/components/Explorer/BulkEdit/useBulkEdit.d.ts.map +1 -1
- package/dist/esm/components/Explorer/Explorer.d.ts.map +1 -1
- package/dist/esm/components/Explorer/QuickEdit/useQuickEdit.d.ts +14 -3
- package/dist/esm/components/Explorer/QuickEdit/useQuickEdit.d.ts.map +1 -1
- package/dist/esm/components/Explorer/helpers/useActions.d.ts +15 -4
- package/dist/esm/components/Explorer/helpers/useActions.d.ts.map +1 -1
- package/dist/esm/components/Explorer/helpers/useSubtitle.d.ts.map +1 -1
- package/dist/esm/components/List/List.d.ts +17 -3
- package/dist/esm/components/List/List.d.ts.map +1 -1
- package/dist/esm/components/List/List.model.d.ts +5 -1
- package/dist/esm/components/List/List.model.d.ts.map +1 -1
- package/dist/esm/components/List/ListHeader/ListHeader.d.ts +10 -1
- package/dist/esm/components/List/ListHeader/ListHeader.d.ts.map +1 -1
- package/dist/esm/components/List/ListRow/ListRow.d.ts +16 -5
- package/dist/esm/components/List/ListRow/ListRow.d.ts.map +1 -1
- package/dist/esm/components/List/ListRowRenderer/ListRowRenderer.d.ts.map +1 -1
- package/dist/esm/components/List/helpers.d.ts +11 -3
- package/dist/esm/components/List/helpers.d.ts.map +1 -1
- package/dist/esm/components/List/useColumnsSize.d.ts +4 -2
- package/dist/esm/components/List/useColumnsSize.d.ts.map +1 -1
- package/dist/esm/components/PageHeader/PageHeader.d.ts +4 -1
- package/dist/esm/components/PageHeader/PageHeader.d.ts.map +1 -1
- package/dist/esm/components/PageHeader/PageHeader.model.d.ts +37 -1
- package/dist/esm/components/PageHeader/PageHeader.model.d.ts.map +1 -1
- package/dist/esm/components/PageHeader/PageHeaderAction/PageHeaderAction.d.ts +3 -0
- package/dist/esm/components/PageHeader/PageHeaderAction/PageHeaderAction.d.ts.map +1 -1
- package/dist/esm/components/PageHeader/PageHeaderAction/PageHeaderAction.model.d.ts +8 -0
- package/dist/esm/components/PageHeader/PageHeaderAction/PageHeaderAction.model.d.ts.map +1 -1
- package/dist/esm/components/PageHeader/helpers.d.ts +9 -0
- package/dist/esm/components/PageHeader/helpers.d.ts.map +1 -0
- package/dist/esm/components/index.d.ts +1 -0
- package/dist/esm/components/index.d.ts.map +1 -1
- package/dist/esm/hooks/index.d.ts +1 -0
- package/dist/esm/hooks/index.d.ts.map +1 -1
- package/dist/esm/hooks/useElementWidthObserver/useElementWidthObserver.d.ts.map +1 -0
- package/dist/esm/index.js +4 -4
- package/dist/esm/index.js.map +1 -1
- package/package.json +7 -3
- package/src/components/ActionBar/ActionBar.model.ts +61 -0
- package/src/components/ActionBar/ActionBar.module.scss +64 -0
- package/src/components/ActionBar/ActionBar.spec.tsx +398 -0
- package/src/components/ActionBar/ActionBar.stories.tsx +205 -0
- package/src/components/ActionBar/ActionBar.tsx +170 -0
- package/src/components/ActionBar/ActionBarButton/ActionBarButton.module.scss +140 -0
- package/src/components/ActionBar/ActionBarButton/ActionBarButton.tsx +193 -0
- package/src/components/ActionBar/helpers.spec.ts +41 -0
- package/src/components/ActionBar/helpers.ts +54 -0
- package/src/components/ActionBar/index.ts +2 -0
- package/src/components/Actions/Action/Action.spec.tsx +64 -2
- package/src/components/Actions/Action/Action.tsx +6 -1
- package/src/components/ConfirmDialog/index.ts +1 -0
- package/src/components/ConfirmDialog/useConfirmableAction.tsx +159 -0
- package/src/components/EmptyStation/EmptyStation.stories.tsx +97 -0
- package/src/components/Explorer/BulkEdit/useBulkEdit.tsx +2 -0
- package/src/components/Explorer/Explorer.spec.tsx +97 -8
- package/src/components/Explorer/Explorer.tsx +26 -13
- package/src/components/Explorer/NavigationExplorer/NavigationExplorer.stories.tsx +124 -1
- package/src/components/Explorer/QuickEdit/useQuickEdit.spec.tsx +94 -50
- package/src/components/Explorer/QuickEdit/useQuickEdit.tsx +101 -42
- package/src/components/Explorer/SelectionExplorer/SelectionExplorer.spec.tsx +46 -13
- package/src/components/Explorer/helpers/useActions.ts +125 -73
- package/src/components/Explorer/helpers/useSubtitle.spec.tsx +33 -23
- package/src/components/Explorer/helpers/useSubtitle.tsx +18 -26
- package/src/components/List/List.model.ts +5 -1
- package/src/components/List/List.module.scss +25 -6
- package/src/components/List/List.spec.tsx +498 -1
- package/src/components/List/List.stories.tsx +137 -8
- package/src/components/List/List.tsx +305 -194
- package/src/components/List/ListHeader/ListHeader.module.scss +14 -0
- package/src/components/List/ListHeader/ListHeader.spec.tsx +1 -0
- package/src/components/List/ListHeader/ListHeader.tsx +25 -8
- package/src/components/List/ListRow/ListRow.module.scss +1 -1
- package/src/components/List/ListRow/ListRow.spec.tsx +109 -22
- package/src/components/List/ListRow/ListRow.tsx +52 -13
- package/src/components/List/ListRowRenderer/ListRowRenderer.tsx +28 -22
- package/src/components/List/helpers.spec.ts +29 -0
- package/src/components/List/helpers.ts +17 -9
- package/src/components/List/useColumnsSize.ts +17 -7
- package/src/components/PageHeader/PageHeader.model.ts +38 -1
- package/src/components/PageHeader/PageHeader.module.scss +39 -18
- package/src/components/PageHeader/PageHeader.spec.tsx +407 -18
- package/src/components/PageHeader/PageHeader.stories.tsx +95 -12
- package/src/components/PageHeader/PageHeader.tsx +89 -38
- package/src/components/PageHeader/PageHeaderAction/PageHeaderAction.model.ts +8 -0
- package/src/components/PageHeader/PageHeaderAction/PageHeaderAction.module.scss +50 -42
- package/src/components/PageHeader/PageHeaderAction/PageHeaderAction.spec.tsx +193 -1
- package/src/components/PageHeader/PageHeaderAction/PageHeaderAction.stories.tsx +36 -0
- package/src/components/PageHeader/PageHeaderAction/PageHeaderAction.tsx +81 -130
- package/src/components/PageHeader/helpers.spec.ts +60 -0
- package/src/components/PageHeader/helpers.ts +36 -0
- package/src/components/index.ts +1 -0
- package/src/hooks/index.ts +1 -0
- package/src/styles/variables.scss +41 -7
- package/dist/cjs/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.d.ts +0 -35
- package/dist/cjs/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.d.ts.map +0 -1
- package/dist/cjs/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContext.d.ts +0 -6
- package/dist/cjs/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContext.d.ts.map +0 -1
- package/dist/cjs/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContextProvider.d.ts +0 -3
- package/dist/cjs/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContextProvider.d.ts.map +0 -1
- package/dist/cjs/components/PageHeader/helpers/useElementWidthObserver.d.ts.map +0 -1
- package/dist/esm/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.d.ts +0 -35
- package/dist/esm/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.d.ts.map +0 -1
- package/dist/esm/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContext.d.ts +0 -6
- package/dist/esm/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContext.d.ts.map +0 -1
- package/dist/esm/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContextProvider.d.ts +0 -3
- package/dist/esm/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContextProvider.d.ts.map +0 -1
- package/dist/esm/components/PageHeader/helpers/useElementWidthObserver.d.ts.map +0 -1
- package/src/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.module.scss +0 -77
- package/src/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.spec.tsx +0 -122
- package/src/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.tsx +0 -235
- package/src/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContext.ts +0 -15
- package/src/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContextProvider.tsx +0 -37
- /package/dist/cjs/{components/PageHeader/helpers → hooks/useElementWidthObserver}/useElementWidthObserver.d.ts +0 -0
- /package/dist/esm/{components/PageHeader/helpers → hooks/useElementWidthObserver}/useElementWidthObserver.d.ts +0 -0
- /package/src/{components/PageHeader/helpers → hooks/useElementWidthObserver}/useElementWidthObserver.tsx +0 -0
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import type { LocationDescriptor } from 'history';
|
|
2
|
-
import React, { useCallback, useMemo, useState } from 'react';
|
|
2
|
+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
3
3
|
import type { Data } from '../../../types';
|
|
4
|
+
import type { ActionBarData } from '../../ActionBar';
|
|
4
5
|
import { IconName } from '../../Icons';
|
|
5
6
|
import type { ListElement } from '../../List';
|
|
6
|
-
import {
|
|
7
|
-
type PageHeaderActionItemProps,
|
|
8
|
-
PageHeaderActionType,
|
|
9
|
-
} from '../../PageHeader';
|
|
7
|
+
import type { PageHeaderJsActionProps } from '../../PageHeader/PageHeaderAction';
|
|
10
8
|
import type { QuickEditConfig, QuickEditRegistration } from '../Explorer.model';
|
|
11
9
|
import { QuickEditContext } from './QuickEditContext';
|
|
12
10
|
|
|
@@ -18,17 +16,27 @@ export interface useQuickEditProps<T extends Data> {
|
|
|
18
16
|
quickEditConfig?: QuickEditConfig;
|
|
19
17
|
collapseFilters: () => void;
|
|
20
18
|
generateItemLink?: (data: T) => LocationDescriptor<unknown>;
|
|
19
|
+
/**
|
|
20
|
+
* Called before quick edit opens, so that the consumer can put away whatever
|
|
21
|
+
* else is on display - only one set of actions can be shown at a time.
|
|
22
|
+
*/
|
|
23
|
+
onBeforeOpen?: () => void;
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
export interface useQuickEditReturnType<T extends Data> {
|
|
24
27
|
readonly isQuickEditMode: boolean;
|
|
25
|
-
|
|
28
|
+
/** Toggle of quick edit, to be rendered on the page header. */
|
|
29
|
+
readonly quickEditToggleAction?: PageHeaderJsActionProps;
|
|
30
|
+
/** The registrations to choose from, to be rendered on the action bar of the List. */
|
|
31
|
+
readonly quickEditActionBar?: ActionBarData;
|
|
26
32
|
readonly QuickEditContextProvider: React.FC;
|
|
27
33
|
readonly quickEditStation: JSX.Element | undefined;
|
|
28
34
|
readonly changeSelectedItem: (
|
|
29
35
|
item: T,
|
|
30
36
|
detailsLink?: LocationDescriptor<unknown>,
|
|
31
37
|
) => Promise<void>;
|
|
38
|
+
/** Closes quick edit, saving whatever is pending. Does nothing if it is not open. */
|
|
39
|
+
readonly closeQuickEdit: () => Promise<void>;
|
|
32
40
|
}
|
|
33
41
|
|
|
34
42
|
export const useQuickEdit = <T extends Data>({
|
|
@@ -39,6 +47,7 @@ export const useQuickEdit = <T extends Data>({
|
|
|
39
47
|
quickEditConfig,
|
|
40
48
|
collapseFilters,
|
|
41
49
|
generateItemLink,
|
|
50
|
+
onBeforeOpen,
|
|
42
51
|
}: useQuickEditProps<T>): useQuickEditReturnType<T> => {
|
|
43
52
|
const [isQuickEditMode, setIsQuickEditMode] = useState<boolean>(false);
|
|
44
53
|
const [currentRegistration, setCurrentRegistration] =
|
|
@@ -103,45 +112,98 @@ export const useQuickEdit = <T extends Data>({
|
|
|
103
112
|
[detailsLink, isQuickEditMode, registerSaveCallback, selectedItem],
|
|
104
113
|
);
|
|
105
114
|
|
|
106
|
-
const
|
|
115
|
+
const closeQuickEdit = useCallback(async (): Promise<void> => {
|
|
116
|
+
if (!isQuickEditMode) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (selectedItem) {
|
|
121
|
+
await saveCallbackRef.current?.();
|
|
122
|
+
setSelectedItem(defaultItem);
|
|
123
|
+
updateDetailsLink(defaultItem, registrations?.[0]);
|
|
124
|
+
setDetailsLink(undefined);
|
|
125
|
+
listRef.current?.resetSelection();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
setCurrentRegistration(undefined);
|
|
129
|
+
setIsQuickEditMode(false);
|
|
130
|
+
}, [
|
|
131
|
+
defaultItem,
|
|
132
|
+
isQuickEditMode,
|
|
133
|
+
listRef,
|
|
134
|
+
registrations,
|
|
135
|
+
selectedItem,
|
|
136
|
+
updateDetailsLink,
|
|
137
|
+
]);
|
|
138
|
+
|
|
139
|
+
const openQuickEdit = useCallback((): void => {
|
|
140
|
+
onBeforeOpen?.();
|
|
141
|
+
|
|
142
|
+
if (defaultItem) {
|
|
143
|
+
setSelectedItem(defaultItem);
|
|
144
|
+
updateDetailsLink(defaultItem, registrations?.[0]);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
setIsQuickEditMode(true);
|
|
148
|
+
setCurrentRegistration(registrations?.[0]);
|
|
149
|
+
collapseFilters();
|
|
150
|
+
}, [
|
|
151
|
+
collapseFilters,
|
|
152
|
+
defaultItem,
|
|
153
|
+
onBeforeOpen,
|
|
154
|
+
registrations,
|
|
155
|
+
updateDetailsLink,
|
|
156
|
+
]);
|
|
157
|
+
|
|
158
|
+
// Marks the item quick edit opens on in the list. The list drops its
|
|
159
|
+
// selection when it switches to single selection, so this runs as an effect,
|
|
160
|
+
// after the list has made the switch.
|
|
161
|
+
useEffect(() => {
|
|
162
|
+
if (isQuickEditMode) {
|
|
163
|
+
listRef.current?.selectIndex(0);
|
|
164
|
+
}
|
|
165
|
+
}, [isQuickEditMode, listRef]);
|
|
166
|
+
|
|
167
|
+
const hasRegistrations =
|
|
168
|
+
registrations !== undefined && registrations.length > 0;
|
|
169
|
+
|
|
170
|
+
const quickEditToggleAction: PageHeaderJsActionProps | undefined = useMemo(
|
|
107
171
|
() =>
|
|
108
|
-
|
|
172
|
+
hasRegistrations
|
|
109
173
|
? {
|
|
110
174
|
label: quickEditConfig?.label ?? 'Quick View',
|
|
111
|
-
kind: 'group',
|
|
112
175
|
icon: quickEditConfig?.icon ?? IconName.QuickEdit,
|
|
113
176
|
disabled: !hasData && !isQuickEditMode,
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if (
|
|
117
|
-
await
|
|
118
|
-
setCurrentRegistration(undefined);
|
|
119
|
-
setSelectedItem(defaultItem);
|
|
120
|
-
updateDetailsLink(defaultItem, registrations[0]);
|
|
121
|
-
setDetailsLink(undefined);
|
|
122
|
-
setIsQuickEditMode(false);
|
|
123
|
-
listRef.current?.resetSelection();
|
|
177
|
+
toggled: isQuickEditMode,
|
|
178
|
+
onClick: async () => {
|
|
179
|
+
if (isQuickEditMode) {
|
|
180
|
+
await closeQuickEdit();
|
|
124
181
|
} else {
|
|
125
|
-
|
|
126
|
-
setSelectedItem(defaultItem);
|
|
127
|
-
updateDetailsLink(defaultItem, registrations[0]);
|
|
128
|
-
}
|
|
129
|
-
setIsQuickEditMode(isOpen);
|
|
130
|
-
setCurrentRegistration(isOpen ? registrations[0] : undefined);
|
|
131
|
-
if (isOpen) {
|
|
132
|
-
collapseFilters();
|
|
133
|
-
listRef.current?.selectIndex(0);
|
|
134
|
-
}
|
|
182
|
+
openQuickEdit();
|
|
135
183
|
}
|
|
136
184
|
},
|
|
137
|
-
|
|
185
|
+
}
|
|
186
|
+
: undefined,
|
|
187
|
+
[
|
|
188
|
+
closeQuickEdit,
|
|
189
|
+
hasData,
|
|
190
|
+
hasRegistrations,
|
|
191
|
+
isQuickEditMode,
|
|
192
|
+
openQuickEdit,
|
|
193
|
+
quickEditConfig?.icon,
|
|
194
|
+
quickEditConfig?.label,
|
|
195
|
+
],
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
const quickEditActionBar: ActionBarData | undefined = useMemo(
|
|
199
|
+
() =>
|
|
200
|
+
hasRegistrations && isQuickEditMode
|
|
201
|
+
? {
|
|
202
|
+
actions: (registrations ?? []).map((registration) => ({
|
|
138
203
|
label: registration.label,
|
|
139
204
|
icon: registration.icon ?? IconName.QuickEditStation,
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
currentRegistration?.component === registration.component
|
|
143
|
-
? PageHeaderActionType.Hightlight
|
|
144
|
-
: PageHeaderActionType.Context,
|
|
205
|
+
toggled:
|
|
206
|
+
currentRegistration?.component === registration.component,
|
|
145
207
|
onClick: async () => {
|
|
146
208
|
await saveCallbackRef.current?.();
|
|
147
209
|
setSelectedItem({ ...selectedItem });
|
|
@@ -152,14 +214,9 @@ export const useQuickEdit = <T extends Data>({
|
|
|
152
214
|
}
|
|
153
215
|
: undefined,
|
|
154
216
|
[
|
|
155
|
-
collapseFilters,
|
|
156
217
|
currentRegistration?.component,
|
|
157
|
-
|
|
158
|
-
hasData,
|
|
218
|
+
hasRegistrations,
|
|
159
219
|
isQuickEditMode,
|
|
160
|
-
listRef,
|
|
161
|
-
quickEditConfig?.icon,
|
|
162
|
-
quickEditConfig?.label,
|
|
163
220
|
registrations,
|
|
164
221
|
selectedItem,
|
|
165
222
|
updateDetailsLink,
|
|
@@ -168,9 +225,11 @@ export const useQuickEdit = <T extends Data>({
|
|
|
168
225
|
|
|
169
226
|
return {
|
|
170
227
|
isQuickEditMode,
|
|
171
|
-
|
|
228
|
+
quickEditToggleAction,
|
|
229
|
+
quickEditActionBar,
|
|
172
230
|
QuickEditContextProvider,
|
|
173
231
|
quickEditStation: currentRegistration?.component,
|
|
174
232
|
changeSelectedItem,
|
|
233
|
+
closeQuickEdit,
|
|
175
234
|
};
|
|
176
235
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { render, waitFor } from '@testing-library/react';
|
|
1
|
+
import { fireEvent, render, waitFor } from '@testing-library/react';
|
|
2
2
|
import { noop } from 'lodash';
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { act } from 'react-dom/test-utils';
|
|
@@ -48,6 +48,17 @@ const getDataProvider = (): readonly [
|
|
|
48
48
|
] as const;
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
+
/** Finds the label element of the action with the given text. */
|
|
52
|
+
const findActionLabel = (
|
|
53
|
+
container: HTMLElement,
|
|
54
|
+
label: string,
|
|
55
|
+
): Element | undefined =>
|
|
56
|
+
Array.from(
|
|
57
|
+
container.querySelectorAll(
|
|
58
|
+
'[data-test-id="action"] [data-test-id="label"]',
|
|
59
|
+
),
|
|
60
|
+
).find((el) => el.textContent === label);
|
|
61
|
+
|
|
51
62
|
describe('SelectionExplorer', () => {
|
|
52
63
|
it('renders the component without crashing', () => {
|
|
53
64
|
const [provider] = getDataProvider();
|
|
@@ -71,19 +82,46 @@ describe('SelectionExplorer', () => {
|
|
|
71
82
|
dataProvider={provider}
|
|
72
83
|
stationKey="mock-key"
|
|
73
84
|
allowBulkSelect={true}
|
|
85
|
+
openBulkActionsOnStart={true}
|
|
74
86
|
/>,
|
|
75
87
|
);
|
|
76
88
|
|
|
77
89
|
await waitFor(() => {
|
|
78
|
-
const applySelectionButton =
|
|
79
|
-
container
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
).find((el) => el.textContent === 'Apply Selection');
|
|
90
|
+
const applySelectionButton = findActionLabel(
|
|
91
|
+
container,
|
|
92
|
+
'Apply Selection',
|
|
93
|
+
);
|
|
83
94
|
expect(applySelectionButton).toBeInTheDocument();
|
|
84
95
|
});
|
|
85
96
|
});
|
|
86
97
|
|
|
98
|
+
it(`shows the 'Apply Selection' bulk action once bulk actions are opened`, async () => {
|
|
99
|
+
const [provider] = getDataProvider();
|
|
100
|
+
|
|
101
|
+
const { container } = render(
|
|
102
|
+
<SelectionExplorer
|
|
103
|
+
columns={mockListColumns}
|
|
104
|
+
dataProvider={provider}
|
|
105
|
+
stationKey="mock-key"
|
|
106
|
+
allowBulkSelect={true}
|
|
107
|
+
/>,
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
expect(findActionLabel(container, 'Apply Selection')).toBeUndefined();
|
|
111
|
+
|
|
112
|
+
await act(async () => {
|
|
113
|
+
fireEvent.click(
|
|
114
|
+
findActionLabel(container, 'Bulk Actions')?.closest(
|
|
115
|
+
'button',
|
|
116
|
+
) as HTMLButtonElement,
|
|
117
|
+
);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
await waitFor(() => {
|
|
121
|
+
expect(findActionLabel(container, 'Apply Selection')).toBeInTheDocument();
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
87
125
|
it(`creates no bulk action if 'allowBulkSelect' is false`, async () => {
|
|
88
126
|
const [provider] = getDataProvider();
|
|
89
127
|
const spy = vi.fn();
|
|
@@ -94,17 +132,12 @@ describe('SelectionExplorer', () => {
|
|
|
94
132
|
dataProvider={provider}
|
|
95
133
|
stationKey="mock-key"
|
|
96
134
|
allowBulkSelect={false}
|
|
135
|
+
openBulkActionsOnStart={true}
|
|
97
136
|
onSelection={spy}
|
|
98
137
|
/>,
|
|
99
138
|
);
|
|
100
139
|
|
|
101
|
-
|
|
102
|
-
container.querySelectorAll(
|
|
103
|
-
'[data-test-id="action"] [data-test-id="label"]',
|
|
104
|
-
),
|
|
105
|
-
).find((el) => el.textContent === 'Apply Selection');
|
|
106
|
-
|
|
107
|
-
expect(applySelectionButton).toBeUndefined();
|
|
140
|
+
expect(findActionLabel(container, 'Apply Selection')).toBeUndefined();
|
|
108
141
|
});
|
|
109
142
|
|
|
110
143
|
it.todo('Does not call "showNotification" when "Apply Selection" is clicked');
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { useMemo } from 'react';
|
|
1
|
+
import { useCallback, useMemo } from 'react';
|
|
2
2
|
import { showNotification } from '../../../initialize';
|
|
3
3
|
import type { Data } from '../../../types';
|
|
4
4
|
import { ErrorTypeToStationError } from '../../../utils/ErrorTypeToStationError';
|
|
5
|
+
import type { ActionBarAction, ActionBarData } from '../../ActionBar';
|
|
5
6
|
import { IconName } from '../../Icons';
|
|
6
7
|
import type { ItemSelectEventArgs } from '../../List';
|
|
7
8
|
import type { PageHeaderActionItemProps } from '../../PageHeader';
|
|
@@ -9,6 +10,7 @@ import {
|
|
|
9
10
|
type PageHeaderJsActionProps,
|
|
10
11
|
isPageHeaderNavigationAction,
|
|
11
12
|
} from '../../PageHeader/PageHeaderAction';
|
|
13
|
+
import { toActionBarAction } from '../../PageHeader/helpers';
|
|
12
14
|
import type { ErrorType } from '../../models';
|
|
13
15
|
import type {
|
|
14
16
|
ExplorerAction,
|
|
@@ -21,11 +23,16 @@ import type { StationMessage } from './useStationMessage';
|
|
|
21
23
|
interface UseActionsProps<T extends Data> {
|
|
22
24
|
actions?: ExplorerAction[];
|
|
23
25
|
bulkActions?: ExplorerBulkAction<T>[];
|
|
24
|
-
quickEditAction?: PageHeaderActionItemProps;
|
|
25
26
|
bulkEditAction?: ExplorerBulkAction<T>;
|
|
26
|
-
|
|
27
|
+
/** Toggle of quick edit, rendered next to the toggle of the bulk actions */
|
|
28
|
+
quickEditToggleAction?: PageHeaderJsActionProps;
|
|
29
|
+
/** Actions of quick edit, shown on the action bar while quick edit is open */
|
|
30
|
+
quickEditActionBar?: ActionBarData;
|
|
31
|
+
/** Text the action bar shows next to the actions, e.g. the result counts */
|
|
32
|
+
actionBarLabel?: string;
|
|
33
|
+
/** Whether the bulk actions are currently on display */
|
|
34
|
+
isBulkOpen: boolean;
|
|
27
35
|
resultCount: ResultCounts;
|
|
28
|
-
activeFilterCount: number;
|
|
29
36
|
itemSelection: ItemSelectEventArgs<T>;
|
|
30
37
|
getBulkActionSelection: () => ItemSelection<T>;
|
|
31
38
|
onReloadData: () => void;
|
|
@@ -35,10 +42,14 @@ interface UseActionsProps<T extends Data> {
|
|
|
35
42
|
onBulkActionsToggled: (expanded: boolean) => void;
|
|
36
43
|
setIsBulkOpen: (value: React.SetStateAction<boolean>) => void;
|
|
37
44
|
closeBulkEdit: () => void;
|
|
45
|
+
closeQuickEdit: () => Promise<void>;
|
|
38
46
|
}
|
|
39
47
|
|
|
40
48
|
interface UseActionsReturnType {
|
|
49
|
+
/** Actions of the page header, which includes the toggles of the action sets */
|
|
41
50
|
readonly actions: PageHeaderActionItemProps[];
|
|
51
|
+
/** Content of the action bar of the List, for the context that is active */
|
|
52
|
+
readonly actionBar: ActionBarData;
|
|
42
53
|
}
|
|
43
54
|
|
|
44
55
|
export const useActions = <T extends Data>({
|
|
@@ -48,56 +59,60 @@ export const useActions = <T extends Data>({
|
|
|
48
59
|
actions,
|
|
49
60
|
itemSelection,
|
|
50
61
|
onBulkActionsToggled,
|
|
51
|
-
|
|
62
|
+
isBulkOpen,
|
|
52
63
|
resultCount,
|
|
53
64
|
setIsBulkOpen,
|
|
54
|
-
|
|
65
|
+
quickEditToggleAction,
|
|
66
|
+
quickEditActionBar,
|
|
67
|
+
actionBarLabel,
|
|
55
68
|
bulkActions,
|
|
56
69
|
closeBulkEdit,
|
|
70
|
+
closeQuickEdit,
|
|
57
71
|
bulkEditAction,
|
|
58
72
|
}: UseActionsProps<T>): UseActionsReturnType => {
|
|
59
|
-
const bulkActionItems:
|
|
60
|
-
() =>
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
...action
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
title: `Bulk Action '${action.label}' Started`,
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
try {
|
|
72
|
-
const result = await action.onClick(getBulkActionSelection());
|
|
73
|
-
if (result) {
|
|
74
|
-
const message = errMsg(result);
|
|
73
|
+
const bulkActionItems: ActionBarAction[] = useMemo(
|
|
74
|
+
() =>
|
|
75
|
+
[
|
|
76
|
+
...(bulkEditAction ? [bulkEditAction] : []),
|
|
77
|
+
...(bulkActions ?? []).map((action) => ({
|
|
78
|
+
...action,
|
|
79
|
+
onClick: async () => {
|
|
80
|
+
if (action.showStartedNotification !== false) {
|
|
75
81
|
showNotification({
|
|
76
|
-
title:
|
|
77
|
-
typeof message.title === 'string'
|
|
78
|
-
? message.title
|
|
79
|
-
: 'An error occurred',
|
|
80
|
-
body: message.body,
|
|
81
|
-
options: {
|
|
82
|
-
type: 'error',
|
|
83
|
-
},
|
|
82
|
+
title: `Bulk Action '${action.label}' Started`,
|
|
84
83
|
});
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const result = await action.onClick(getBulkActionSelection());
|
|
88
|
+
if (result) {
|
|
89
|
+
const message = errMsg(result);
|
|
90
|
+
showNotification({
|
|
91
|
+
title:
|
|
92
|
+
typeof message.title === 'string'
|
|
93
|
+
? message.title
|
|
94
|
+
: 'An error occurred',
|
|
95
|
+
body: message.body,
|
|
96
|
+
options: {
|
|
97
|
+
type: 'error',
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
} else {
|
|
101
|
+
if (action.reloadData) {
|
|
102
|
+
onReloadData();
|
|
103
|
+
}
|
|
88
104
|
}
|
|
105
|
+
} catch (error) {
|
|
106
|
+
setStationMessage(
|
|
107
|
+
errMsg(
|
|
108
|
+
error,
|
|
109
|
+
'An error occurred when trying to execute the bulk operation.',
|
|
110
|
+
),
|
|
111
|
+
);
|
|
89
112
|
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
error,
|
|
94
|
-
'An error occurred when trying to execute the bulk operation.',
|
|
95
|
-
),
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
},
|
|
99
|
-
})),
|
|
100
|
-
],
|
|
113
|
+
},
|
|
114
|
+
})),
|
|
115
|
+
].map(toActionBarAction),
|
|
101
116
|
[
|
|
102
117
|
bulkActions,
|
|
103
118
|
bulkEditAction,
|
|
@@ -107,40 +122,80 @@ export const useActions = <T extends Data>({
|
|
|
107
122
|
],
|
|
108
123
|
);
|
|
109
124
|
|
|
125
|
+
const toggleBulkActions = useCallback(async (): Promise<void> => {
|
|
126
|
+
const isOpening = !isBulkOpen;
|
|
127
|
+
|
|
128
|
+
if (isOpening) {
|
|
129
|
+
// Only one set of actions can be on display, so quick edit gives way.
|
|
130
|
+
await closeQuickEdit();
|
|
131
|
+
} else {
|
|
132
|
+
closeBulkEdit();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
setIsBulkOpen(isOpening);
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
await onBulkActionsToggled(isOpening);
|
|
139
|
+
} catch {
|
|
140
|
+
// The consumer is expected to surface a problem of its own handler.
|
|
141
|
+
}
|
|
142
|
+
}, [
|
|
143
|
+
closeBulkEdit,
|
|
144
|
+
closeQuickEdit,
|
|
145
|
+
isBulkOpen,
|
|
146
|
+
onBulkActionsToggled,
|
|
147
|
+
setIsBulkOpen,
|
|
148
|
+
]);
|
|
149
|
+
|
|
150
|
+
const actionBar: ActionBarData = useMemo(() => {
|
|
151
|
+
// The bar reports the results at all times, only the actions on it change
|
|
152
|
+
// with the context that is active.
|
|
153
|
+
if (isBulkOpen && bulkActionItems.length > 0) {
|
|
154
|
+
// Bulk actions apply to the selection, so they are unavailable while
|
|
155
|
+
// there is nothing to apply them to.
|
|
156
|
+
const noSelection =
|
|
157
|
+
itemSelection.items?.length === 0 || resultCount?.filtered === 0;
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
label: actionBarLabel,
|
|
161
|
+
actions: bulkActionItems.map((action) => ({
|
|
162
|
+
...action,
|
|
163
|
+
disabled: action.disabled || noSelection,
|
|
164
|
+
})),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
label: actionBarLabel,
|
|
170
|
+
actions: quickEditActionBar?.actions ?? [],
|
|
171
|
+
};
|
|
172
|
+
}, [
|
|
173
|
+
actionBarLabel,
|
|
174
|
+
bulkActionItems,
|
|
175
|
+
isBulkOpen,
|
|
176
|
+
itemSelection,
|
|
177
|
+
quickEditActionBar,
|
|
178
|
+
resultCount,
|
|
179
|
+
]);
|
|
180
|
+
|
|
110
181
|
const pageHeaderActions: PageHeaderActionItemProps[] = useMemo(() => {
|
|
111
182
|
const headerActions: PageHeaderActionItemProps[] = [];
|
|
112
183
|
|
|
113
184
|
if (bulkActionItems.length > 0) {
|
|
114
|
-
headerActions.push({ kind: 'spacer' });
|
|
115
|
-
|
|
116
185
|
headerActions.push({
|
|
186
|
+
kind: 'action',
|
|
117
187
|
label: 'Bulk Actions',
|
|
118
188
|
icon: IconName.Bulk,
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
openActionsGroupOnStart: openBulkActionsOnStart,
|
|
122
|
-
onActionsGroupToggled: async (isOpen) => {
|
|
123
|
-
setIsBulkOpen(isOpen);
|
|
124
|
-
onBulkActionsToggled(isOpen);
|
|
125
|
-
|
|
126
|
-
if (!isOpen) {
|
|
127
|
-
closeBulkEdit();
|
|
128
|
-
}
|
|
129
|
-
},
|
|
130
|
-
groupActionsDisabled:
|
|
131
|
-
itemSelection.items?.length === 0 || resultCount?.filtered === 0,
|
|
189
|
+
toggled: isBulkOpen,
|
|
190
|
+
onClick: toggleBulkActions,
|
|
132
191
|
});
|
|
133
192
|
}
|
|
134
193
|
|
|
135
|
-
if (
|
|
136
|
-
headerActions.push({ kind: '
|
|
137
|
-
|
|
138
|
-
headerActions.push(quickEditAction);
|
|
194
|
+
if (quickEditToggleAction) {
|
|
195
|
+
headerActions.push({ ...quickEditToggleAction, kind: 'action' });
|
|
139
196
|
}
|
|
140
197
|
|
|
141
198
|
if (actions && actions.length > 0) {
|
|
142
|
-
headerActions.push({ kind: 'spacer' });
|
|
143
|
-
|
|
144
199
|
actions?.forEach((action) => {
|
|
145
200
|
headerActions.push({
|
|
146
201
|
...(isPageHeaderNavigationAction(action)
|
|
@@ -173,20 +228,17 @@ export const useActions = <T extends Data>({
|
|
|
173
228
|
return headerActions;
|
|
174
229
|
}, [
|
|
175
230
|
actions,
|
|
176
|
-
bulkActionItems,
|
|
177
|
-
|
|
178
|
-
itemSelection.items?.length,
|
|
179
|
-
onBulkActionsToggled,
|
|
231
|
+
bulkActionItems.length,
|
|
232
|
+
isBulkOpen,
|
|
180
233
|
onReloadData,
|
|
181
|
-
|
|
182
|
-
quickEditAction,
|
|
183
|
-
resultCount?.filtered,
|
|
184
|
-
setIsBulkOpen,
|
|
234
|
+
quickEditToggleAction,
|
|
185
235
|
setStationMessage,
|
|
236
|
+
toggleBulkActions,
|
|
186
237
|
]);
|
|
187
238
|
|
|
188
239
|
return {
|
|
189
240
|
actions: pageHeaderActions,
|
|
241
|
+
actionBar,
|
|
190
242
|
};
|
|
191
243
|
};
|
|
192
244
|
|