@axinom/mosaic-ui 0.49.0-rc.5 → 0.49.0-rc.6
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/components/DynamicDataList/DynamicDataList.d.ts.map +1 -1
- package/dist/components/Explorer/Explorer.d.ts.map +1 -1
- package/dist/components/FormStation/FormStationHeader/FormStationHeader.d.ts.map +1 -1
- package/dist/components/PageHeader/PageHeader.d.ts +9 -2
- package/dist/components/PageHeader/PageHeader.d.ts.map +1 -1
- package/dist/components/PageHeader/PageHeader.model.d.ts +11 -12
- package/dist/components/PageHeader/PageHeader.model.d.ts.map +1 -1
- package/dist/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.d.ts +35 -0
- package/dist/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.d.ts.map +1 -0
- package/dist/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContext.d.ts +7 -0
- package/dist/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContext.d.ts.map +1 -0
- package/dist/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContextProvider.d.ts +3 -0
- package/dist/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContextProvider.d.ts.map +1 -0
- package/dist/components/PageHeader/index.d.ts +1 -1
- package/dist/components/PageHeader/index.d.ts.map +1 -1
- package/dist/index.es.js +4 -4
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/{components/DynamicDataList/helpers/generateId.d.ts → utils/GenerateId.d.ts} +1 -1
- package/dist/utils/GenerateId.d.ts.map +1 -0
- package/package.json +3 -3
- package/src/components/DynamicDataList/DynamicDataList.spec.tsx +2 -1
- package/src/components/DynamicDataList/DynamicDataList.tsx +1 -1
- package/src/components/Explorer/Explorer.spec.tsx +26 -16
- package/src/components/Explorer/Explorer.tsx +47 -28
- package/src/components/Explorer/NavigationExplorer/NavigationExplorer.spec.tsx +2 -2
- package/src/components/Explorer/SelectionExplorer/SelectionExplorer.spec.tsx +8 -32
- package/src/components/FormStation/FormStationHeader/FormStationHeader.tsx +34 -30
- package/src/components/PageHeader/PageHeader.model.ts +10 -12
- package/src/components/PageHeader/PageHeader.scss +7 -3
- package/src/components/PageHeader/PageHeader.spec.tsx +28 -86
- package/src/components/PageHeader/PageHeader.stories.tsx +32 -7
- package/src/components/PageHeader/PageHeader.tsx +50 -77
- package/src/components/PageHeader/{PageHeaderBulkActions/PageHeaderBulkActions.scss → PageHeaderActionsGroup/PageHeaderActionsGroup.scss} +21 -21
- package/src/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.spec.tsx +105 -0
- package/src/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.tsx +224 -0
- package/src/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContext.ts +13 -0
- package/src/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContextProvider.tsx +30 -0
- package/src/components/PageHeader/index.ts +1 -1
- package/dist/components/DynamicDataList/helpers/generateId.d.ts.map +0 -1
- package/dist/components/PageHeader/PageHeaderBulkActions/PageHeaderBulkActions.d.ts +0 -22
- package/dist/components/PageHeader/PageHeaderBulkActions/PageHeaderBulkActions.d.ts.map +0 -1
- package/src/components/PageHeader/PageHeaderBulkActions/PageHeaderBulkActions.spec.tsx +0 -369
- package/src/components/PageHeader/PageHeaderBulkActions/PageHeaderBulkActions.tsx +0 -188
- /package/src/{components/DynamicDataList/helpers/generateId.ts → utils/GenerateId.ts} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GenerateId.d.ts","sourceRoot":"","sources":["../../src/utils/GenerateId.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,IAAI,QAAO,MAKvB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axinom/mosaic-ui",
|
|
3
|
-
"version": "0.49.0-rc.
|
|
3
|
+
"version": "0.49.0-rc.6",
|
|
4
4
|
"description": "UI components for building Axinom Mosaic applications",
|
|
5
5
|
"author": "Axinom",
|
|
6
6
|
"license": "PROPRIETARY",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"build-storybook": "storybook build"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@axinom/mosaic-core": "^0.4.22-rc.
|
|
35
|
+
"@axinom/mosaic-core": "^0.4.22-rc.6",
|
|
36
36
|
"@faker-js/faker": "^7.4.0",
|
|
37
37
|
"@popperjs/core": "^2.11.8",
|
|
38
38
|
"clsx": "^1.1.0",
|
|
@@ -105,5 +105,5 @@
|
|
|
105
105
|
"publishConfig": {
|
|
106
106
|
"access": "public"
|
|
107
107
|
},
|
|
108
|
-
"gitHead": "
|
|
108
|
+
"gitHead": "00356987b703a8eab052ca7efa3ec609338e5cf7"
|
|
109
109
|
}
|
|
@@ -9,7 +9,8 @@ import { DynamicListRow } from './DynamicListRow/DynamicListRow';
|
|
|
9
9
|
import { useDataHandler } from './helpers/useDataHandler';
|
|
10
10
|
|
|
11
11
|
jest.mock('./helpers/useDataHandler');
|
|
12
|
-
|
|
12
|
+
|
|
13
|
+
jest.mock('../../utils/GenerateId', () => ({
|
|
13
14
|
uuid: jest.fn().mockReturnValue('test-uuid'),
|
|
14
15
|
}));
|
|
15
16
|
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import { OptionalObjectSchema } from 'yup/lib/object';
|
|
11
11
|
import { noop } from '../../helpers/utils';
|
|
12
12
|
import { Data } from '../../types/data';
|
|
13
|
+
import { uuid } from '../../utils/GenerateId';
|
|
13
14
|
import { ActionData } from '../Actions';
|
|
14
15
|
import { ObjectSchemaDefinition } from '../FormStation';
|
|
15
16
|
import { DynamicListColumn } from './DynamicDataList.model';
|
|
@@ -21,7 +22,6 @@ import {
|
|
|
21
22
|
} from './DynamicListDataEntry/DynamicListDataEntry';
|
|
22
23
|
import { DynamicListHeader } from './DynamicListHeader/DynamicListHeader';
|
|
23
24
|
import { DynamicListRow } from './DynamicListRow/DynamicListRow';
|
|
24
|
-
import { uuid } from './helpers/generateId';
|
|
25
25
|
import { useColumnDefs } from './helpers/useColumnDefs';
|
|
26
26
|
import { useDataHandler } from './helpers/useDataHandler';
|
|
27
27
|
import { useRowAnimation } from './helpers/useRowAnimation';
|
|
@@ -24,7 +24,7 @@ import { MessageBar } from '../MessageBar';
|
|
|
24
24
|
import { StationError } from '../models';
|
|
25
25
|
import { PageHeaderAction } from '../PageHeader';
|
|
26
26
|
import { PageHeader } from '../PageHeader/PageHeader';
|
|
27
|
-
import {
|
|
27
|
+
import { PageHeaderActionsGroup } from '../PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup';
|
|
28
28
|
import * as GS from '../Utils/State/GlobalState';
|
|
29
29
|
import { Explorer, ExplorerProps } from './Explorer';
|
|
30
30
|
import {
|
|
@@ -34,6 +34,10 @@ import {
|
|
|
34
34
|
} from './Explorer.model';
|
|
35
35
|
import { StationMessage } from './useStationMessage';
|
|
36
36
|
|
|
37
|
+
jest.mock('../../utils/GenerateId', () => ({
|
|
38
|
+
uuid: jest.fn().mockReturnValue('test-uuid'),
|
|
39
|
+
}));
|
|
40
|
+
|
|
37
41
|
interface ExplorerTestData {
|
|
38
42
|
id: number;
|
|
39
43
|
title: string;
|
|
@@ -152,7 +156,6 @@ describe('Explorer', () => {
|
|
|
152
156
|
columns={[{ propertyName: 'id' }]}
|
|
153
157
|
dataProvider={provider}
|
|
154
158
|
stationKey="mock-key"
|
|
155
|
-
openBulkActionsOnStart={true}
|
|
156
159
|
bulkActions={[{ label: 'Something', onClick: jest.fn() }]}
|
|
157
160
|
/>,
|
|
158
161
|
);
|
|
@@ -166,8 +169,9 @@ describe('Explorer', () => {
|
|
|
166
169
|
await wrapper.update();
|
|
167
170
|
});
|
|
168
171
|
|
|
169
|
-
|
|
170
|
-
|
|
172
|
+
expect(
|
|
173
|
+
wrapper.find(PageHeaderActionsGroup).prop('groupActionsDisabled'),
|
|
174
|
+
).toBe(true);
|
|
171
175
|
});
|
|
172
176
|
|
|
173
177
|
it('enables bulk actions if filtered results are returned', async () => {
|
|
@@ -203,7 +207,10 @@ describe('Explorer', () => {
|
|
|
203
207
|
});
|
|
204
208
|
|
|
205
209
|
wrapper.update();
|
|
206
|
-
|
|
210
|
+
|
|
211
|
+
expect(
|
|
212
|
+
wrapper.find(PageHeaderActionsGroup).prop('groupActionsDisabled'),
|
|
213
|
+
).toBe(false);
|
|
207
214
|
});
|
|
208
215
|
|
|
209
216
|
it('disables bulk actions if no filtered results are returned', async () => {
|
|
@@ -239,7 +246,9 @@ describe('Explorer', () => {
|
|
|
239
246
|
});
|
|
240
247
|
|
|
241
248
|
wrapper.update();
|
|
242
|
-
expect(
|
|
249
|
+
expect(
|
|
250
|
+
wrapper.find(PageHeaderActionsGroup).prop('groupActionsDisabled'),
|
|
251
|
+
).toBe(true);
|
|
243
252
|
});
|
|
244
253
|
|
|
245
254
|
it('Reloads data when a bulk action with reloadData is triggered', async () => {
|
|
@@ -267,10 +276,10 @@ describe('Explorer', () => {
|
|
|
267
276
|
// Initial Data Loading
|
|
268
277
|
expect(spy).toHaveBeenCalledTimes(1);
|
|
269
278
|
|
|
270
|
-
const
|
|
279
|
+
const bulkActions = wrapper.find(PageHeaderActionsGroup);
|
|
271
280
|
|
|
272
281
|
await act(async () => {
|
|
273
|
-
|
|
282
|
+
bulkActions.prop('actions')?.[0].onClick?.();
|
|
274
283
|
|
|
275
284
|
await wrapper.update();
|
|
276
285
|
});
|
|
@@ -301,9 +310,9 @@ describe('Explorer', () => {
|
|
|
301
310
|
return wrapper;
|
|
302
311
|
});
|
|
303
312
|
|
|
304
|
-
const
|
|
313
|
+
const bulkActions = wrapper.find(PageHeaderActionsGroup);
|
|
305
314
|
await act(async () => {
|
|
306
|
-
|
|
315
|
+
bulkActions.prop('actions')?.[0].onClick?.();
|
|
307
316
|
await wrapper.update();
|
|
308
317
|
});
|
|
309
318
|
|
|
@@ -336,9 +345,9 @@ describe('Explorer', () => {
|
|
|
336
345
|
return wrapper;
|
|
337
346
|
});
|
|
338
347
|
|
|
339
|
-
const
|
|
348
|
+
const bulkActions = wrapper.find(PageHeaderActionsGroup);
|
|
340
349
|
await act(async () => {
|
|
341
|
-
|
|
350
|
+
bulkActions.prop('actions')?.[0].onClick?.();
|
|
342
351
|
await wrapper.update();
|
|
343
352
|
});
|
|
344
353
|
|
|
@@ -401,7 +410,7 @@ describe('Explorer', () => {
|
|
|
401
410
|
expectComponentReceivesValue(header, 'title');
|
|
402
411
|
// expectComponentReceivesValue(header, 'actions');
|
|
403
412
|
// expectComponentReceivesValue(header, 'bulkActions');
|
|
404
|
-
expectComponentReceivesValue(header, 'openBulkActionsOnStart');
|
|
413
|
+
// expectComponentReceivesValue(header, 'openBulkActionsOnStart');
|
|
405
414
|
|
|
406
415
|
const filters = wrapper.find(Filters);
|
|
407
416
|
expectComponentReceivesValue(filters, 'filters');
|
|
@@ -2025,9 +2034,10 @@ describe('Explorer', () => {
|
|
|
2025
2034
|
});
|
|
2026
2035
|
|
|
2027
2036
|
await act(async () => {
|
|
2028
|
-
wrapper.find(
|
|
2029
|
-
|
|
2030
|
-
|
|
2037
|
+
wrapper.find(PageHeaderActionsGroup).prop('onActionsGroupToggled')!(true);
|
|
2038
|
+
wrapper.find(PageHeaderActionsGroup).prop('onActionsGroupToggled')!(
|
|
2039
|
+
false,
|
|
2040
|
+
);
|
|
2031
2041
|
});
|
|
2032
2042
|
|
|
2033
2043
|
expect(spy).toHaveBeenCalledTimes(2);
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
useEffect,
|
|
8
8
|
useState,
|
|
9
9
|
} from 'react';
|
|
10
|
-
import { ActionData } from '..';
|
|
10
|
+
import { ActionData, IconName } from '..';
|
|
11
11
|
import { noop } from '../../helpers/utils';
|
|
12
12
|
import { showNotification } from '../../initialize';
|
|
13
13
|
import { Data } from '../../types/data';
|
|
@@ -23,7 +23,11 @@ import {
|
|
|
23
23
|
ListSelectMode,
|
|
24
24
|
SortData,
|
|
25
25
|
} from '../List';
|
|
26
|
-
import {
|
|
26
|
+
import {
|
|
27
|
+
PageHeader,
|
|
28
|
+
PageHeaderActionItemProps,
|
|
29
|
+
PageHeaderActionProps,
|
|
30
|
+
} from '../PageHeader';
|
|
27
31
|
import { isPageHeaderNavigationAction } from '../PageHeader/PageHeaderAction/PageHeaderAction';
|
|
28
32
|
import { PageHeaderJsActionProps } from '../PageHeader/PageHeaderAction/PageHeaderAction.model';
|
|
29
33
|
import { getState, storeState } from '../Utils/State/GlobalState';
|
|
@@ -348,24 +352,48 @@ export const Explorer = React.forwardRef(function Explorer<T extends Data>(
|
|
|
348
352
|
});
|
|
349
353
|
};
|
|
350
354
|
|
|
351
|
-
const pageHeaderActionsHandler = ():
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
355
|
+
const pageHeaderActionsHandler = (): PageHeaderActionItemProps[] => {
|
|
356
|
+
const headerActions: PageHeaderActionItemProps[] = [];
|
|
357
|
+
|
|
358
|
+
if (bulkActions && bulkActions.length > 0) {
|
|
359
|
+
headerActions.push({
|
|
360
|
+
label: 'Bulk Actions',
|
|
361
|
+
icon: IconName.Bulk,
|
|
362
|
+
kind: 'group',
|
|
363
|
+
actions: bulkActionsHandler(),
|
|
364
|
+
openActionsGroupOnStart: openBulkActionsOnStart,
|
|
365
|
+
onActionsGroupToggled: (isOpen) => {
|
|
366
|
+
setIsBulkOpen(isOpen);
|
|
367
|
+
onBulkActionsToggled(isOpen);
|
|
368
|
+
},
|
|
369
|
+
groupActionsDisabled:
|
|
370
|
+
itemSelection.items?.length === 0 || resultCount?.filtered === 0,
|
|
371
|
+
});
|
|
372
|
+
headerActions.push({ kind: 'spacer' });
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
actions?.forEach((action) => {
|
|
376
|
+
headerActions.push({
|
|
377
|
+
...(isPageHeaderNavigationAction(action)
|
|
378
|
+
? action
|
|
379
|
+
: {
|
|
380
|
+
...action,
|
|
381
|
+
onClick: async () => {
|
|
382
|
+
try {
|
|
383
|
+
const result = await action.onClick();
|
|
384
|
+
if (result) {
|
|
385
|
+
setStationMessage(errMsg(result));
|
|
386
|
+
}
|
|
387
|
+
} catch (error) {
|
|
388
|
+
setStationMessage(errMsg(error, errAction));
|
|
362
389
|
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
};
|
|
390
|
+
},
|
|
391
|
+
}),
|
|
392
|
+
kind: 'action',
|
|
393
|
+
});
|
|
368
394
|
});
|
|
395
|
+
|
|
396
|
+
return headerActions;
|
|
369
397
|
};
|
|
370
398
|
|
|
371
399
|
const bulkActionsHandler = (): PageHeaderJsActionProps[] => {
|
|
@@ -421,16 +449,7 @@ export const Explorer = React.forwardRef(function Explorer<T extends Data>(
|
|
|
421
449
|
<PageHeader
|
|
422
450
|
title={title}
|
|
423
451
|
subtitle={resultsTitle}
|
|
424
|
-
actions={
|
|
425
|
-
bulkActions={bulkActions && bulkActionsHandler()}
|
|
426
|
-
openBulkActionsOnStart={openBulkActionsOnStart}
|
|
427
|
-
bulkActionsDisabled={
|
|
428
|
-
itemSelection.items?.length === 0 || resultCount?.filtered === 0
|
|
429
|
-
}
|
|
430
|
-
onBulkActionsToggled={(isOpen) => {
|
|
431
|
-
setIsBulkOpen(isOpen);
|
|
432
|
-
onBulkActionsToggled(isOpen);
|
|
433
|
-
}}
|
|
452
|
+
actions={pageHeaderActionsHandler()}
|
|
434
453
|
setTabTitle={setTabTitle}
|
|
435
454
|
/>
|
|
436
455
|
{StationMessage}
|
|
@@ -117,7 +117,7 @@ describe('NavigationExplorer', () => {
|
|
|
117
117
|
return wrapper;
|
|
118
118
|
});
|
|
119
119
|
|
|
120
|
-
const action = wrapper.find(PageHeaderAction);
|
|
120
|
+
const action = wrapper.find(PageHeaderAction).last();
|
|
121
121
|
expect(action.props().label).toBe('test');
|
|
122
122
|
});
|
|
123
123
|
|
|
@@ -219,7 +219,7 @@ describe('NavigationExplorer', () => {
|
|
|
219
219
|
return wrapper;
|
|
220
220
|
});
|
|
221
221
|
|
|
222
|
-
const createAction = wrapper.find(PageHeaderAction);
|
|
222
|
+
const createAction = wrapper.find(PageHeaderAction).last();
|
|
223
223
|
|
|
224
224
|
createAction.simulate('click');
|
|
225
225
|
|
|
@@ -3,14 +3,16 @@ import { noop } from 'lodash';
|
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { act } from 'react-dom/test-utils';
|
|
5
5
|
import { actWithReturn } from '../../../helpers/testing';
|
|
6
|
-
import * as app from '../../../initialize';
|
|
7
6
|
import { Column } from '../../List';
|
|
8
|
-
import {
|
|
9
|
-
import { PageHeaderBulkActions } from '../../PageHeader/PageHeaderBulkActions/PageHeaderBulkActions';
|
|
7
|
+
import { PageHeaderActionsGroup } from '../../PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup';
|
|
10
8
|
import { Explorer } from '../Explorer';
|
|
11
9
|
import { ExplorerDataProvider } from '../Explorer.model';
|
|
12
10
|
import { SelectionExplorer } from './SelectionExplorer';
|
|
13
11
|
|
|
12
|
+
jest.mock('../../../utils/GenerateId', () => ({
|
|
13
|
+
uuid: jest.fn().mockReturnValue('test-uuid'),
|
|
14
|
+
}));
|
|
15
|
+
|
|
14
16
|
interface SelectExplorerTestData {
|
|
15
17
|
id: string;
|
|
16
18
|
desc: string;
|
|
@@ -78,7 +80,7 @@ describe('SelectionExplorer', () => {
|
|
|
78
80
|
return wrapper;
|
|
79
81
|
});
|
|
80
82
|
|
|
81
|
-
const bulkActions = wrapper.find(
|
|
83
|
+
const bulkActions = wrapper.find(PageHeaderActionsGroup);
|
|
82
84
|
|
|
83
85
|
expect(bulkActions.exists()).toBe(true);
|
|
84
86
|
});
|
|
@@ -101,38 +103,12 @@ describe('SelectionExplorer', () => {
|
|
|
101
103
|
return wrapper;
|
|
102
104
|
});
|
|
103
105
|
|
|
104
|
-
const bulkActions = wrapper.find(
|
|
106
|
+
const bulkActions = wrapper.find(PageHeaderActionsGroup);
|
|
105
107
|
|
|
106
108
|
expect(bulkActions.exists()).toBe(false);
|
|
107
109
|
});
|
|
108
110
|
|
|
109
|
-
it('Does not call "showNotification" when "Apply Selection" is clicked'
|
|
110
|
-
const [provider] = getDataProvider();
|
|
111
|
-
const showNotificationSpy: jest.SpyInstance = jest.spyOn(
|
|
112
|
-
app,
|
|
113
|
-
'showNotification',
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
const wrapper = await actWithReturn(async () => {
|
|
117
|
-
const wrapper = mount(
|
|
118
|
-
<SelectionExplorer
|
|
119
|
-
columns={mockListColumns}
|
|
120
|
-
dataProvider={provider}
|
|
121
|
-
stationKey="mock-key"
|
|
122
|
-
allowBulkSelect={true}
|
|
123
|
-
/>,
|
|
124
|
-
);
|
|
125
|
-
return wrapper;
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
const header = wrapper.find(PageHeader);
|
|
129
|
-
await act(async () => {
|
|
130
|
-
header.prop('bulkActions')?.[0].onClick?.();
|
|
131
|
-
await wrapper.update();
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
expect(showNotificationSpy).toHaveBeenCalledTimes(0);
|
|
135
|
-
});
|
|
111
|
+
it.todo('Does not call "showNotification" when "Apply Selection" is clicked');
|
|
136
112
|
|
|
137
113
|
it('sends onSelection callback when the selection of a single item is triggered', async () => {
|
|
138
114
|
const [provider] = getDataProvider();
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { FormikValues, useFormikContext } from 'formik';
|
|
2
|
-
import React, { useEffect } from 'react';
|
|
2
|
+
import React, { useEffect, useMemo } from 'react';
|
|
3
3
|
import { useHistory } from 'react-router-dom';
|
|
4
4
|
import { SaveIndicatorType, setSaveIndicator } from '../../../initialize';
|
|
5
5
|
import { IconName } from '../../Icons';
|
|
6
6
|
import {
|
|
7
7
|
PageHeader,
|
|
8
|
+
PageHeaderActionItemProps,
|
|
8
9
|
PageHeaderActionType,
|
|
9
10
|
PageHeaderProps,
|
|
10
11
|
} from '../../PageHeader';
|
|
@@ -49,41 +50,44 @@ export const FormStationHeader: React.FC<
|
|
|
49
50
|
|
|
50
51
|
const title = useTitle(titleProperty, defaultTitle);
|
|
51
52
|
|
|
53
|
+
const actions: PageHeaderActionItemProps[] = useMemo(() => {
|
|
54
|
+
const actionItems: PageHeaderActionItemProps[] = [];
|
|
55
|
+
|
|
56
|
+
if (dirty) {
|
|
57
|
+
actionItems.push({
|
|
58
|
+
label: 'Undo Changes',
|
|
59
|
+
icon: IconName.Undo,
|
|
60
|
+
kind: 'action',
|
|
61
|
+
actionType: PageHeaderActionType.Context,
|
|
62
|
+
onClick: () => {
|
|
63
|
+
resetForm();
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (cancelNavigationUrl) {
|
|
69
|
+
actionItems.push({
|
|
70
|
+
label: 'Cancel',
|
|
71
|
+
icon: IconName.X,
|
|
72
|
+
kind: 'action',
|
|
73
|
+
onClick: () => {
|
|
74
|
+
resetForm();
|
|
75
|
+
// If the form has errors, Navigation needs to be wrapped in a promise or timeout.
|
|
76
|
+
Promise.resolve().then(() => history.push(cancelNavigationUrl));
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return actionItems;
|
|
82
|
+
}, [cancelNavigationUrl, dirty, history, resetForm]);
|
|
83
|
+
|
|
52
84
|
return (
|
|
53
85
|
<PageHeader
|
|
54
86
|
title={title}
|
|
55
87
|
subtitle={subtitle}
|
|
56
88
|
className={className}
|
|
57
89
|
setTabTitle={setTabTitle}
|
|
58
|
-
actions={
|
|
59
|
-
...(dirty === true // add undo action if form as been altered
|
|
60
|
-
? [
|
|
61
|
-
{
|
|
62
|
-
label: 'Undo Changes',
|
|
63
|
-
icon: IconName.Undo,
|
|
64
|
-
actionType: PageHeaderActionType.Context,
|
|
65
|
-
onClick: () => {
|
|
66
|
-
resetForm();
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
]
|
|
70
|
-
: []),
|
|
71
|
-
...(cancelNavigationUrl // add cancel action if applicable
|
|
72
|
-
? [
|
|
73
|
-
{
|
|
74
|
-
label: 'Cancel',
|
|
75
|
-
icon: IconName.X,
|
|
76
|
-
onClick: () => {
|
|
77
|
-
resetForm();
|
|
78
|
-
// If the form has errors, Navigation needs to be wrapped in a promise or timeout.
|
|
79
|
-
Promise.resolve().then(() =>
|
|
80
|
-
history.push(cancelNavigationUrl),
|
|
81
|
-
);
|
|
82
|
-
},
|
|
83
|
-
},
|
|
84
|
-
]
|
|
85
|
-
: []),
|
|
86
|
-
]}
|
|
90
|
+
actions={actions}
|
|
87
91
|
/>
|
|
88
92
|
);
|
|
89
93
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PageHeaderActionProps } from './PageHeaderAction/PageHeaderAction.model';
|
|
2
|
+
import { PageHeaderActionsGroupProps } from './PageHeaderActionsGroup/PageHeaderActionsGroup';
|
|
2
3
|
|
|
3
4
|
export interface PageHeaderProps {
|
|
4
5
|
/** Title shown in page header */
|
|
@@ -6,20 +7,17 @@ export interface PageHeaderProps {
|
|
|
6
7
|
/** Subtitle shown in page header */
|
|
7
8
|
subtitle?: string;
|
|
8
9
|
/** Array of actions to be rendered. (default: []) */
|
|
9
|
-
actions?:
|
|
10
|
-
/** Array of Bulk Actions to be rendered. If populated, Bulk Actions will become available. (default: []) */
|
|
11
|
-
bulkActions?: PageHeaderActionProps[];
|
|
12
|
-
/** Whether or bulk actions are shown by default. (default: false) */
|
|
13
|
-
openBulkActionsOnStart?: boolean;
|
|
14
|
-
/** Whether or not bulk actions are disabled (default: false)*/
|
|
15
|
-
bulkActionsDisabled?: boolean;
|
|
16
|
-
/**
|
|
17
|
-
* Callback to emit when Bulk Actions is toggled
|
|
18
|
-
* The expanded state is supplied as an argument
|
|
19
|
-
*/
|
|
20
|
-
onBulkActionsToggled?: (expanded: boolean) => void;
|
|
10
|
+
actions?: PageHeaderActionItemProps[];
|
|
21
11
|
/** CSS Class name for additional styles */
|
|
22
12
|
className?: string;
|
|
23
13
|
/** Update the tab title using the 'title' field. (default: true) */
|
|
24
14
|
setTabTitle?: boolean;
|
|
25
15
|
}
|
|
16
|
+
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
18
|
+
export interface PageHeaderSpacerProps {}
|
|
19
|
+
|
|
20
|
+
export type PageHeaderActionItemProps =
|
|
21
|
+
| (PageHeaderSpacerProps & { kind: 'spacer' })
|
|
22
|
+
| (PageHeaderActionProps & { kind: 'action' })
|
|
23
|
+
| (PageHeaderActionsGroupProps & { kind: 'group' });
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
height: $page-header-height;
|
|
7
7
|
display: grid;
|
|
8
|
-
grid-template-columns: minmax(
|
|
8
|
+
grid-template-columns: minmax(30%, 1fr) auto;
|
|
9
9
|
grid-template-rows: 1fr;
|
|
10
10
|
|
|
11
11
|
@media only screen and (min-width: $XL-min-size) {
|
|
@@ -52,9 +52,13 @@
|
|
|
52
52
|
|
|
53
53
|
.actions {
|
|
54
54
|
display: grid;
|
|
55
|
-
grid-template-rows: 1fr;
|
|
56
55
|
grid-auto-flow: column;
|
|
56
|
+
grid-auto-columns: minmax(0, min-content);
|
|
57
57
|
grid-gap: 1px;
|
|
58
|
-
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.spacer {
|
|
61
|
+
display: grid;
|
|
62
|
+
width: 8px;
|
|
59
63
|
}
|
|
60
64
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { shallow } from 'enzyme';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { noop } from '../../helpers/utils';
|
|
4
4
|
import { PageHeader } from './PageHeader';
|
|
5
|
+
import { PageHeaderActionItemProps } from './PageHeader.model';
|
|
6
|
+
import { PageHeaderActionProps } from './PageHeaderAction';
|
|
5
7
|
import { PageHeaderAction } from './PageHeaderAction/PageHeaderAction';
|
|
6
|
-
import {
|
|
7
|
-
import { PageHeaderBulkActions } from './PageHeaderBulkActions/PageHeaderBulkActions';
|
|
8
|
+
import { PageHeaderActionsGroup } from './PageHeaderActionsGroup/PageHeaderActionsGroup';
|
|
8
9
|
|
|
9
10
|
jest.mock('../../hooks/useTabTitle/useTabTitle');
|
|
10
11
|
|
|
@@ -40,96 +41,37 @@ describe('PageHeader', () => {
|
|
|
40
41
|
});
|
|
41
42
|
|
|
42
43
|
it(`renders actions`, () => {
|
|
43
|
-
const wrapper = shallow(
|
|
44
|
+
const wrapper = shallow(
|
|
45
|
+
<PageHeader actions={[{ ...defaultbulkActions[0], kind: 'action' }]} />,
|
|
46
|
+
);
|
|
44
47
|
|
|
45
48
|
const action = wrapper.find(PageHeaderAction);
|
|
46
49
|
expect(action.exists()).toBe(true);
|
|
47
50
|
});
|
|
48
51
|
|
|
49
|
-
it(`
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const actionsContainer = wrapper
|
|
63
|
-
.find('.actions')
|
|
64
|
-
.prop('style') as React.CSSProperties;
|
|
65
|
-
|
|
66
|
-
expect(actionsContainer.marginLeft).toBeUndefined();
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it(`does not render 'PageHeaderBulkActions' if bulkActions prop is empty`, () => {
|
|
70
|
-
const wrapper = mount(<PageHeader />);
|
|
71
|
-
|
|
72
|
-
const bulkActions = wrapper.find(PageHeaderBulkActions);
|
|
73
|
-
|
|
74
|
-
expect(bulkActions.exists()).toBe(false);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it(`renders 'PageHeaderBulkActions' if bulkActions prop is populated`, () => {
|
|
78
|
-
const wrapper = mount(<PageHeader bulkActions={defaultbulkActions} />);
|
|
79
|
-
|
|
80
|
-
const bulkActions = wrapper.find(PageHeaderBulkActions);
|
|
81
|
-
|
|
82
|
-
expect(bulkActions.exists()).toBe(true);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it('raises onBulkActionsToggled', () => {
|
|
86
|
-
const spy = jest.fn();
|
|
87
|
-
|
|
88
|
-
const wrapper = mount(
|
|
89
|
-
<PageHeader
|
|
90
|
-
bulkActions={defaultbulkActions}
|
|
91
|
-
onBulkActionsToggled={spy}
|
|
92
|
-
/>,
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
const bulkActionsToggle = wrapper.find(PageHeaderAction).first();
|
|
96
|
-
bulkActionsToggle.simulate('click');
|
|
97
|
-
expect(spy).toHaveBeenCalledTimes(1);
|
|
98
|
-
expect(spy).toHaveBeenCalledWith(true);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it(`bulk actions should not be disabled by default`, () => {
|
|
102
|
-
const spy = jest.fn();
|
|
103
|
-
|
|
104
|
-
const wrapper = shallow(
|
|
105
|
-
<PageHeader
|
|
106
|
-
bulkActions={defaultbulkActions}
|
|
107
|
-
onBulkActionsToggled={spy}
|
|
108
|
-
/>,
|
|
109
|
-
);
|
|
110
|
-
|
|
111
|
-
const bulkActions = wrapper.find(PageHeaderBulkActions);
|
|
112
|
-
|
|
113
|
-
expect(bulkActions.prop('bulkActionsDisabled')).toBe(false);
|
|
52
|
+
it(`renders actions groups`, () => {
|
|
53
|
+
const actions: PageHeaderActionItemProps[] = [
|
|
54
|
+
{
|
|
55
|
+
label: 'Bulk Actions',
|
|
56
|
+
kind: 'group',
|
|
57
|
+
actions: defaultbulkActions,
|
|
58
|
+
},
|
|
59
|
+
];
|
|
60
|
+
const wrapper = shallow(<PageHeader actions={actions} />);
|
|
61
|
+
|
|
62
|
+
const action = wrapper.find(PageHeaderActionsGroup);
|
|
63
|
+
expect(action.exists()).toBe(true);
|
|
114
64
|
});
|
|
115
65
|
|
|
116
|
-
it(
|
|
117
|
-
const
|
|
66
|
+
it('renders spacers', () => {
|
|
67
|
+
const actions: PageHeaderActionItemProps[] = [
|
|
68
|
+
{
|
|
69
|
+
kind: 'spacer',
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
const wrapper = shallow(<PageHeader actions={actions} />);
|
|
118
73
|
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
bulkActions={defaultbulkActions}
|
|
122
|
-
onBulkActionsToggled={spy}
|
|
123
|
-
bulkActionsDisabled={true}
|
|
124
|
-
/>,
|
|
125
|
-
);
|
|
126
|
-
|
|
127
|
-
const bulkActions = wrapper.find(PageHeaderBulkActions);
|
|
128
|
-
|
|
129
|
-
expect(bulkActions.prop('bulkActionsDisabled')).toBe(true);
|
|
74
|
+
const spacer = wrapper.find('.spacer');
|
|
75
|
+
expect(spacer.exists()).toBe(true);
|
|
130
76
|
});
|
|
131
|
-
|
|
132
|
-
it.todo('calculates the available space needed for bulk actions');
|
|
133
|
-
|
|
134
|
-
it.todo('should not calcuate if there are no bulk actions');
|
|
135
77
|
});
|