@axinom/mosaic-ui 0.51.0-rc.9 → 0.52.0-rc.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 (100) hide show
  1. package/dist/components/Explorer/ConditionalSplit/ConditionalSplit.d.ts +8 -0
  2. package/dist/components/Explorer/ConditionalSplit/ConditionalSplit.d.ts.map +1 -0
  3. package/dist/components/Explorer/Explorer.d.ts +3 -1
  4. package/dist/components/Explorer/Explorer.d.ts.map +1 -1
  5. package/dist/components/Explorer/Explorer.model.d.ts +18 -1
  6. package/dist/components/Explorer/Explorer.model.d.ts.map +1 -1
  7. package/dist/components/Explorer/QuickEdit/QuickEditContext.d.ts +11 -0
  8. package/dist/components/Explorer/QuickEdit/QuickEditContext.d.ts.map +1 -0
  9. package/dist/components/Explorer/QuickEdit/useQuickEdit.d.ts +22 -0
  10. package/dist/components/Explorer/QuickEdit/useQuickEdit.d.ts.map +1 -0
  11. package/dist/components/Explorer/{InMemoryDataProvider.d.ts → helpers/InMemoryDataProvider.d.ts} +3 -3
  12. package/dist/components/Explorer/helpers/InMemoryDataProvider.d.ts.map +1 -0
  13. package/dist/components/Explorer/helpers/useActions.d.ts +31 -0
  14. package/dist/components/Explorer/helpers/useActions.d.ts.map +1 -0
  15. package/dist/components/Explorer/{useDataProvider.d.ts → helpers/useDataProvider.d.ts} +6 -6
  16. package/dist/components/Explorer/helpers/useDataProvider.d.ts.map +1 -0
  17. package/dist/components/Explorer/helpers/useFilters.d.ts +21 -0
  18. package/dist/components/Explorer/helpers/useFilters.d.ts.map +1 -0
  19. package/dist/components/Explorer/helpers/useStationMessage.d.ts +17 -0
  20. package/dist/components/Explorer/helpers/useStationMessage.d.ts.map +1 -0
  21. package/dist/components/Explorer/index.d.ts +2 -1
  22. package/dist/components/Explorer/index.d.ts.map +1 -1
  23. package/dist/components/FormStation/Create/Create.d.ts.map +1 -1
  24. package/dist/components/FormStation/FormStation.d.ts +4 -1
  25. package/dist/components/FormStation/FormStation.d.ts.map +1 -1
  26. package/dist/components/FormStation/FormStationHeader/FormStationHeader.d.ts +1 -0
  27. package/dist/components/FormStation/FormStationHeader/FormStationHeader.d.ts.map +1 -1
  28. package/dist/components/FormStation/SaveOnDemand/SaveOnDemand.d.ts +11 -0
  29. package/dist/components/FormStation/SaveOnDemand/SaveOnDemand.d.ts.map +1 -0
  30. package/dist/components/FormStation/helpers/useDataProvider.d.ts.map +1 -1
  31. package/dist/components/Icons/Icons.d.ts.map +1 -1
  32. package/dist/components/Icons/Icons.models.d.ts +28 -24
  33. package/dist/components/Icons/Icons.models.d.ts.map +1 -1
  34. package/dist/components/List/List.d.ts +1 -1
  35. package/dist/components/List/List.d.ts.map +1 -1
  36. package/dist/components/List/List.model.d.ts +4 -0
  37. package/dist/components/List/List.model.d.ts.map +1 -1
  38. package/dist/components/PageHeader/PageHeader.d.ts.map +1 -1
  39. package/dist/components/PageHeader/PageHeaderAction/PageHeaderAction.d.ts.map +1 -1
  40. package/dist/components/PageHeader/PageHeaderAction/PageHeaderAction.model.d.ts +2 -1
  41. package/dist/components/PageHeader/PageHeaderAction/PageHeaderAction.model.d.ts.map +1 -1
  42. package/dist/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.d.ts +1 -1
  43. package/dist/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.d.ts.map +1 -1
  44. package/dist/components/PageHeader/helpers/useElementWidthObserver.d.ts +6 -0
  45. package/dist/components/PageHeader/helpers/useElementWidthObserver.d.ts.map +1 -0
  46. package/dist/index.es.js +4 -4
  47. package/dist/index.es.js.map +1 -1
  48. package/dist/index.js +4 -4
  49. package/dist/index.js.map +1 -1
  50. package/dist/initialize.d.ts +1 -1
  51. package/dist/initialize.d.ts.map +1 -1
  52. package/package.json +4 -3
  53. package/src/components/EmptyStation/EmptyStation.spec.tsx +24 -0
  54. package/src/components/Explorer/ConditionalSplit/ConditionalSplit.tsx +23 -0
  55. package/src/components/Explorer/Explorer.model.ts +19 -1
  56. package/src/components/Explorer/Explorer.scss +4 -0
  57. package/src/components/Explorer/Explorer.spec.tsx +28 -3
  58. package/src/components/Explorer/Explorer.stories.tsx +90 -5
  59. package/src/components/Explorer/Explorer.tsx +149 -185
  60. package/src/components/Explorer/NavigationExplorer/NavigationExplorer.spec.tsx +26 -0
  61. package/src/components/Explorer/NavigationExplorer/NavigationExplorer.stories.tsx +2 -2
  62. package/src/components/Explorer/QuickEdit/QuickEditContext.tsx +16 -0
  63. package/src/components/Explorer/QuickEdit/useQuickEdit.spec.tsx +461 -0
  64. package/src/components/Explorer/QuickEdit/useQuickEdit.tsx +169 -0
  65. package/src/components/Explorer/SelectionExplorer/SelectionExplorer.spec.tsx +6 -0
  66. package/src/components/Explorer/SelectionExplorer/SelectionExplorer.stories.tsx +2 -2
  67. package/src/components/Explorer/{InMemoryDataProvider.ts → helpers/InMemoryDataProvider.ts} +4 -4
  68. package/src/components/Explorer/helpers/useActions.ts +203 -0
  69. package/src/components/Explorer/{useDataProvider.tsx → helpers/useDataProvider.tsx} +11 -11
  70. package/src/components/Explorer/helpers/useFilters.tsx +77 -0
  71. package/src/components/Explorer/{useStationMessage.tsx → helpers/useStationMessage.tsx} +8 -6
  72. package/src/components/Explorer/index.ts +10 -6
  73. package/src/components/FormStation/Create/Create.tsx +1 -0
  74. package/src/components/FormStation/FormStation.spec.tsx +62 -73
  75. package/src/components/FormStation/FormStation.tsx +31 -15
  76. package/src/components/FormStation/FormStationHeader/FormStationHeader.tsx +38 -18
  77. package/src/components/FormStation/SaveOnDemand/SaveOnDemand.tsx +55 -0
  78. package/src/components/FormStation/helpers/useDataProvider.ts +1 -8
  79. package/src/components/Icons/Icons.models.ts +4 -0
  80. package/src/components/Icons/Icons.tsx +78 -0
  81. package/src/components/InlineMenu/InlineMenu.spec.tsx +18 -0
  82. package/src/components/List/List.model.ts +5 -0
  83. package/src/components/List/List.tsx +29 -5
  84. package/src/components/List/ListRow/ListRow.spec.tsx +0 -10
  85. package/src/components/List/ListRow/ListRow.tsx +1 -1
  86. package/src/components/PageHeader/PageHeader.scss +1 -2
  87. package/src/components/PageHeader/PageHeader.stories.tsx +6 -2
  88. package/src/components/PageHeader/PageHeader.tsx +10 -16
  89. package/src/components/PageHeader/PageHeaderAction/PageHeaderAction.model.ts +1 -0
  90. package/src/components/PageHeader/PageHeaderAction/PageHeaderAction.scss +7 -0
  91. package/src/components/PageHeader/PageHeaderAction/PageHeaderAction.tsx +1 -0
  92. package/src/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.spec.tsx +19 -7
  93. package/src/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.tsx +19 -12
  94. package/src/components/PageHeader/helpers/useElementWidthObserver.tsx +30 -0
  95. package/src/initialize.ts +2 -2
  96. package/dist/components/Explorer/InMemoryDataProvider.d.ts.map +0 -1
  97. package/dist/components/Explorer/useDataProvider.d.ts.map +0 -1
  98. package/dist/components/Explorer/useStationMessage.d.ts +0 -15
  99. package/dist/components/Explorer/useStationMessage.d.ts.map +0 -1
  100. /package/src/components/Explorer/{InMemoryDataProvider.spec.ts → helpers/InMemoryDataProvider.spec.ts} +0 -0
@@ -8,14 +8,11 @@ import {
8
8
  useState,
9
9
  } from 'react';
10
10
  import { noop } from '../../helpers/utils';
11
- import { showNotification } from '../../initialize';
12
11
  import { Data } from '../../types/data';
13
12
  import { ErrorTypeToStationError } from '../../utils/ErrorTypeToStationError';
14
13
  import { isContextAction } from '../Actions/Action/Action';
15
14
  import { ActionData } from '../Actions/Actions.models';
16
- import { Filters } from '../Filters/Filters';
17
15
  import { FilterType, FilterValues } from '../Filters/Filters.model';
18
- import { IconName } from '../Icons/Icons.models';
19
16
  import {
20
17
  Column,
21
18
  ItemSelectEventArgs,
@@ -24,25 +21,24 @@ import {
24
21
  ListSelectMode,
25
22
  SortData,
26
23
  } from '../List';
27
- import {
28
- PageHeader,
29
- PageHeaderActionItemProps,
30
- PageHeaderActionProps,
31
- } from '../PageHeader';
32
- import { isPageHeaderNavigationAction } from '../PageHeader/PageHeaderAction/PageHeaderAction';
33
- import { PageHeaderJsActionProps } from '../PageHeader/PageHeaderAction/PageHeaderAction.model';
24
+ import { PageHeader, PageHeaderActionProps } from '../PageHeader';
34
25
  import { getState, storeState } from '../Utils/State/GlobalState';
35
26
  import { ErrorType } from '../models';
27
+ import { ConditionalSplit } from './ConditionalSplit/ConditionalSplit';
36
28
  import {
37
29
  ExplorerBulkAction,
38
30
  ExplorerDataProvider,
39
31
  ExplorerDataProviderConnection,
40
32
  ExplorerStateOptions,
41
33
  ItemSelection,
34
+ QuickEditRegistration,
42
35
  } from './Explorer.model';
43
36
  import classes from './Explorer.scss';
44
- import { ResultCounts, useDataProvider } from './useDataProvider';
45
- import { StationMessage, useStationMessage } from './useStationMessage';
37
+ import { useQuickEdit } from './QuickEdit/useQuickEdit';
38
+ import { useActions } from './helpers/useActions';
39
+ import { ResultCounts, useDataProvider } from './helpers/useDataProvider';
40
+ import { useFilters } from './helpers/useFilters';
41
+ import { StationMessage, useStationMessage } from './helpers/useStationMessage';
46
42
 
47
43
  export interface ExplorerProps<T extends Data> {
48
44
  /** Title shown in page header */
@@ -136,6 +132,9 @@ export interface ExplorerProps<T extends Data> {
136
132
  /** Update the tab title using the 'title' field. (default: true) */
137
133
  setTabTitle?: boolean;
138
134
 
135
+ /** Quick Edit Registrations */
136
+ quickEditRegistrations?: QuickEditRegistration<T>[];
137
+
139
138
  /**
140
139
  * When set, this function is used to generate the link that the user should be navigated to for each item.
141
140
  *
@@ -211,6 +210,8 @@ export const Explorer = React.forwardRef(function Explorer<T extends Data>(
211
210
  defaultSortOrder,
212
211
  setTabTitle = true,
213
212
 
213
+ quickEditRegistrations,
214
+
214
215
  onItemClicked,
215
216
  onBulkActionsToggled = noop,
216
217
  generateItemLink,
@@ -227,30 +228,12 @@ export const Explorer = React.forwardRef(function Explorer<T extends Data>(
227
228
  ...persistExplorerStates,
228
229
  };
229
230
 
230
- const [activeFilters, setActiveFilters] = useState<FilterValues<T>>(
231
- getState<FilterValues<T>>(stationKey, 'filters') ??
232
- defaultFilterValues ??
233
- {},
234
- );
235
-
236
231
  const [sortOrder, setSortOrder] = useState<SortData<T>>(
237
232
  getState<SortData<T>>(stationKey, 'sort') ?? defaultSortOrder,
238
233
  );
239
234
 
240
235
  const listRef = React.useRef<ListElement>(null);
241
236
 
242
- useEffect(() => {
243
- if (
244
- globalStateOptions.filters &&
245
- activeFilters !== defaultFilterValues &&
246
- Object.keys(activeFilters).length > 0
247
- ) {
248
- storeState(stationKey, 'filters', activeFilters);
249
- } else {
250
- storeState(stationKey, 'filters', undefined);
251
- }
252
- }, [activeFilters, defaultFilterValues, globalStateOptions.filters, stationKey]);
253
-
254
237
  useEffect(() => {
255
238
  if (globalStateOptions.sort && sortOrder !== defaultSortOrder) {
256
239
  storeState(stationKey, 'sort', sortOrder);
@@ -259,6 +242,25 @@ export const Explorer = React.forwardRef(function Explorer<T extends Data>(
259
242
  }
260
243
  }, [defaultSortOrder, globalStateOptions.sort, sortOrder, stationKey]);
261
244
 
245
+ const onFilterChangedHandler = (filters: FilterValues<T>): void => {
246
+ onFiltersChange(filters);
247
+ listRef.current?.resetSelection();
248
+ };
249
+
250
+ const {
251
+ activeFilters,
252
+ Filters,
253
+ filtersVisible,
254
+ toggleFiltersVisible,
255
+ collapseFilters,
256
+ } = useFilters<T>({
257
+ stationKey,
258
+ globalStateOptions,
259
+ filterOptions,
260
+ defaultFilterValues,
261
+ onFiltersChange: onFilterChangedHandler,
262
+ });
263
+
262
264
  const {
263
265
  data,
264
266
  isLoading,
@@ -277,9 +279,24 @@ export const Explorer = React.forwardRef(function Explorer<T extends Data>(
277
279
  keyProperty,
278
280
  });
279
281
 
282
+ const {
283
+ isQuickEditMode,
284
+ quickEditAction,
285
+ QuickEditContextProvider,
286
+ quickEditStation,
287
+ changeSelectedItem,
288
+ } = useQuickEdit({
289
+ listRef,
290
+ registrations: quickEditRegistrations,
291
+ hasData: data.length > 0,
292
+ collapseFilters,
293
+ generateItemLink,
294
+ });
295
+
280
296
  const { mode, setIsBulkOpen } = useListSelectionMode(
281
297
  selectionMode,
282
298
  openBulkActionsOnStart,
299
+ isQuickEditMode,
283
300
  );
284
301
 
285
302
  // TODO: Put into hook?------------------
@@ -323,23 +340,23 @@ export const Explorer = React.forwardRef(function Explorer<T extends Data>(
323
340
 
324
341
  // Emits selected row data and current ListSelectMode state
325
342
  const onItemClickedHandler = useCallback(
326
- (item: T): void => {
327
- if (onItemClicked !== undefined) {
343
+ async (item: T) => {
344
+ if (isQuickEditMode) {
345
+ await changeSelectedItem(item);
346
+ } else if (onItemClicked !== undefined) {
328
347
  onItemClicked(item, mode);
329
348
  }
330
349
  },
331
- [mode, onItemClicked],
350
+ [isQuickEditMode, onItemClicked, changeSelectedItem, mode],
332
351
  );
333
352
 
334
353
  const { resultsTitle } = useSubtitle<T>(mode, itemSelection, resultCount);
335
354
 
336
355
  const errAction = 'An error occurred when trying to execute the operation.';
337
- const errBulk =
338
- 'An error occurred when trying to execute the bulk operation.';
339
356
 
340
- const inlineMenuActionsHandler = (data: T): ActionData[] => {
341
- return (inlineMenuActions?.(data) ?? []).map((action) => {
342
- return isContextAction(action)
357
+ const inlineMenuActionsHandler = (data: T): ActionData[] =>
358
+ (inlineMenuActions?.(data) ?? []).map((action) =>
359
+ isContextAction(action)
343
360
  ? {
344
361
  ...action,
345
362
  onActionSelected: async () => {
@@ -353,157 +370,95 @@ export const Explorer = React.forwardRef(function Explorer<T extends Data>(
353
370
  }
354
371
  },
355
372
  }
356
- : action;
357
- });
358
- };
373
+ : action,
374
+ );
359
375
 
360
- const pageHeaderActionsHandler = (): PageHeaderActionItemProps[] => {
361
- const headerActions: PageHeaderActionItemProps[] = [];
362
-
363
- if (bulkActions && bulkActions.length > 0) {
364
- headerActions.push({
365
- label: 'Bulk Actions',
366
- icon: IconName.Bulk,
367
- kind: 'group',
368
- actions: bulkActionsHandler(),
369
- openActionsGroupOnStart: openBulkActionsOnStart,
370
- onActionsGroupToggled: (isOpen) => {
371
- setIsBulkOpen(isOpen);
372
- onBulkActionsToggled(isOpen);
373
- },
374
- groupActionsDisabled:
375
- itemSelection.items?.length === 0 || resultCount?.filtered === 0,
376
- });
377
- headerActions.push({ kind: 'spacer' });
378
- }
379
-
380
- actions?.forEach((action) => {
381
- headerActions.push({
382
- ...(isPageHeaderNavigationAction(action)
383
- ? action
384
- : {
385
- ...action,
386
- onClick: async () => {
387
- try {
388
- const result = await action.onClick();
389
- if (result) {
390
- setStationMessage(errMsg(result));
391
- }
392
- } catch (error) {
393
- setStationMessage(errMsg(error, errAction));
394
- }
395
- },
396
- }),
397
- kind: 'action',
398
- });
399
- });
400
-
401
- return headerActions;
402
- };
403
-
404
- const bulkActionsHandler = (): PageHeaderJsActionProps[] => {
405
- return (bulkActions ?? []).map((action) => {
406
- return {
407
- ...action,
408
- onClick: async () => {
409
- if (action.showStartedNotification !== false) {
410
- showNotification({
411
- title: `Bulk Action '${action.label}' Started`,
412
- });
413
- }
414
-
415
- try {
416
- const result = await action.onClick(getBulkActionSelection());
417
- if (result) {
418
- const message = errMsg(result);
419
- showNotification({
420
- title:
421
- typeof message.title === 'string'
422
- ? message.title
423
- : 'An error occurred',
424
- body: message.body,
425
- options: {
426
- type: 'error',
427
- },
428
- });
429
- } else {
430
- if (action.reloadData) {
431
- onReloadData();
432
- }
433
- }
434
- } catch (error) {
435
- setStationMessage(errMsg(error, errBulk));
436
- }
437
- },
438
- };
439
- });
440
- };
376
+ const { actions: pageHeaderActions } = useActions<T>({
377
+ actions,
378
+ bulkActions,
379
+ quickEditAction,
380
+ openBulkActionsOnStart,
381
+ filtersVisible,
382
+ hasFilters: filterOptions !== undefined,
383
+ resultCount,
384
+ activeFilterCount: Object.keys(activeFilters).length,
385
+ itemSelection,
386
+ getBulkActionSelection,
387
+ onReloadData,
388
+ setStationMessage,
389
+ onBulkActionsToggled,
390
+ setIsBulkOpen,
391
+ toggleFiltersVisible,
392
+ });
441
393
 
442
394
  return (
443
- <div
444
- className={clsx(
445
- classes.container,
446
- {
447
- [classes.hasStationError]: stationMessage,
448
- [classes.modalMode]: modalMode,
449
- },
450
- 'explorer-container',
451
- className,
452
- )}
453
- >
454
- <PageHeader
455
- title={title}
456
- subtitle={resultsTitle}
457
- actions={pageHeaderActionsHandler()}
458
- setTabTitle={setTabTitle}
459
- />
460
- {StationMessage}
461
- <Filters<T>
462
- options={filterOptions}
463
- defaultValues={activeFilters}
464
- onFiltersChange={(args) => {
465
- onFiltersChange(args);
466
- setActiveFilters(args);
467
- listRef.current?.resetSelection();
468
- }}
469
- />
470
- <div>
471
- <List<T>
472
- ref={listRef}
473
- columns={columns}
474
- data={data}
475
- isLoading={isLoading}
476
- isError={Boolean(stationMessage?.type === 'error')}
477
- handleRetry={false}
478
- minimumWidth={minimumWidth}
479
- columnGap={columnGap}
480
- rowGap={rowGap}
481
- headerRowHeight={headerRowHeight}
482
- listRowHeight={listRowHeight}
483
- listRowActionSize={listRowActionSize}
484
- headerRowActionSize={headerRowActionSize}
485
- horizontalTextAlign={horizontalTextAlign}
486
- verticalTextAlign={verticalTextAlign}
487
- textWrap={textWrap}
488
- keyProperty={keyProperty}
489
- showActionButton={Boolean(generateItemLink) || Boolean(onItemClicked)} // or hard code to `true`?
490
- selectionMode={mode}
491
- enableSelectAll={enableSelectAll}
492
- enableSelectAllDeselect={enableSelectAll && !hasMoreData}
493
- loadingTriggerOffset={loadingTriggerOffset}
494
- defaultSortOrder={sortOrder}
495
- generateItemLink={generateItemLink}
496
- onItemClicked={onItemClickedHandler}
497
- onItemSelected={itemSelectedHandler}
498
- onRequestMoreData={onRequestMoreData}
499
- onSortChanged={(sortData: SortData<T>) => {
500
- onSortChanged(sortData);
501
- setSortOrder(sortData);
502
- }}
503
- inlineMenuActions={inlineMenuActions && inlineMenuActionsHandler}
395
+ <ConditionalSplit shouldSplit={isQuickEditMode} minSecondarySize="500px">
396
+ <div
397
+ className={clsx(
398
+ classes.container,
399
+ {
400
+ [classes.hasStationError]: stationMessage,
401
+ [classes.modalMode]: modalMode,
402
+ },
403
+ 'explorer-container',
404
+ className,
405
+ )}
406
+ >
407
+ <PageHeader
408
+ title={title}
409
+ subtitle={resultsTitle}
410
+ actions={pageHeaderActions}
411
+ setTabTitle={setTabTitle}
504
412
  />
413
+ {StationMessage}
414
+ {Filters}
415
+ <div
416
+ className={clsx({
417
+ [classes.filtersHidden]: !filtersVisible,
418
+ })}
419
+ >
420
+ <List<T>
421
+ ref={listRef}
422
+ columns={columns}
423
+ data={data}
424
+ isLoading={isLoading}
425
+ isError={Boolean(stationMessage?.type === 'error')}
426
+ handleRetry={false}
427
+ minimumWidth={minimumWidth}
428
+ columnGap={columnGap}
429
+ rowGap={rowGap}
430
+ headerRowHeight={headerRowHeight}
431
+ listRowHeight={listRowHeight}
432
+ listRowActionSize={listRowActionSize}
433
+ headerRowActionSize={headerRowActionSize}
434
+ horizontalTextAlign={horizontalTextAlign}
435
+ verticalTextAlign={verticalTextAlign}
436
+ textWrap={textWrap}
437
+ keyProperty={keyProperty}
438
+ showActionButton={
439
+ Boolean(generateItemLink) || Boolean(onItemClicked)
440
+ } // or hard code to `true`?
441
+ selectionMode={mode}
442
+ enableSelectAll={enableSelectAll}
443
+ enableSelectAllDeselect={enableSelectAll && !hasMoreData}
444
+ loadingTriggerOffset={loadingTriggerOffset}
445
+ defaultSortOrder={sortOrder}
446
+ generateItemLink={!isQuickEditMode ? generateItemLink : undefined}
447
+ onItemClicked={onItemClickedHandler}
448
+ onItemSelected={itemSelectedHandler}
449
+ onRequestMoreData={onRequestMoreData}
450
+ onSortChanged={(sortData: SortData<T>) => {
451
+ onSortChanged(sortData);
452
+ setSortOrder(sortData);
453
+ }}
454
+ inlineMenuActions={inlineMenuActions && inlineMenuActionsHandler}
455
+ />
456
+ </div>
505
457
  </div>
506
- </div>
458
+ {isQuickEditMode && (
459
+ <QuickEditContextProvider>{quickEditStation}</QuickEditContextProvider>
460
+ )}
461
+ </ConditionalSplit>
507
462
  );
508
463
  });
509
464
 
@@ -515,6 +470,7 @@ export const Explorer = React.forwardRef(function Explorer<T extends Data>(
515
470
  const useListSelectionMode = (
516
471
  selectionMode: ListSelectMode,
517
472
  openBulkActionsOnStart?: boolean,
473
+ isQuickEditMode?: boolean,
518
474
  ): {
519
475
  readonly mode: ListSelectMode;
520
476
  readonly setIsBulkOpen: React.Dispatch<React.SetStateAction<boolean>>;
@@ -523,8 +479,16 @@ const useListSelectionMode = (
523
479
  openBulkActionsOnStart ?? false,
524
480
  );
525
481
 
482
+ let mode = selectionMode;
483
+
484
+ if (isQuickEditMode) {
485
+ mode = ListSelectMode.Single;
486
+ } else if (isBulkOpen) {
487
+ mode = ListSelectMode.Multi;
488
+ }
489
+
526
490
  // If bulk actions is open, set ListSelectMode to Multi
527
- const mode = isBulkOpen ? ListSelectMode.Multi : selectionMode;
491
+ // const mode = isBulkOpen ? ListSelectMode.Multi : selectionMode;
528
492
 
529
493
  return { mode, setIsBulkOpen } as const;
530
494
  };
@@ -1,6 +1,8 @@
1
1
  import { mount, shallow } from 'enzyme';
2
2
  import React from 'react';
3
3
  import { actWithReturn } from '../../../helpers/testing';
4
+ import { noop } from '../../../helpers/utils';
5
+ import { initializeUi } from '../../../initialize';
4
6
  import { IconName } from '../../Icons';
5
7
  import { Column, ListSelectMode } from '../../List';
6
8
  import {
@@ -50,6 +52,28 @@ const getDataProvider = (): readonly [
50
52
  };
51
53
 
52
54
  describe('NavigationExplorer', () => {
55
+ global.ResizeObserver = jest.fn().mockImplementation(() => ({
56
+ observe: jest.fn(),
57
+ unobserve: jest.fn(),
58
+ disconnect: jest.fn(),
59
+ }));
60
+
61
+ beforeEach(() => {
62
+ initializeUi({
63
+ showNotification: () => {
64
+ // not implemented
65
+ return -1;
66
+ },
67
+ addIndicator: () => {
68
+ return -1;
69
+ },
70
+ removeIndicator: noop,
71
+ on: noop,
72
+ setTitle: noop,
73
+ setSaveIndicator: noop,
74
+ });
75
+ });
76
+
53
77
  it('renders the component without crashing', () => {
54
78
  const [provider] = getDataProvider();
55
79
  const wrapper = shallow(
@@ -161,6 +185,7 @@ describe('NavigationExplorer', () => {
161
185
  const pageHeader = wrapper.find(PageHeader);
162
186
 
163
187
  expect(pageHeader.prop('actions')).toMatchObject([
188
+ { kind: 'spacer' },
164
189
  {
165
190
  label: 'New',
166
191
  icon: IconName.Plus,
@@ -193,6 +218,7 @@ describe('NavigationExplorer', () => {
193
218
  const pageHeader = wrapper.find(PageHeader);
194
219
 
195
220
  expect(pageHeader.prop('actions')).toMatchObject([
221
+ { kind: 'spacer' },
196
222
  { label: 'test' },
197
223
  {
198
224
  label: 'New',
@@ -12,11 +12,11 @@ import { Data } from '../../../types/data';
12
12
  import { FilterType, FilterTypes } from '../../Filters/Filters.model';
13
13
  import { IconName } from '../../Icons';
14
14
  import { ExplorerBulkAction, ExplorerDataProvider } from '../Explorer.model';
15
+ import { NavigationExplorer } from '../NavigationExplorer/NavigationExplorer';
15
16
  import {
16
17
  createInMemoryDataProvider,
17
18
  findAnywhereInStringCaseInsensitive,
18
- } from '../InMemoryDataProvider';
19
- import { NavigationExplorer } from '../NavigationExplorer/NavigationExplorer';
19
+ } from '../helpers/InMemoryDataProvider';
20
20
 
21
21
  interface NavExplorerStoryData {
22
22
  id: number;
@@ -0,0 +1,16 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { LocationDescriptor } from 'history';
3
+ import React from 'react';
4
+
5
+ export interface QuickEditContextType<T> {
6
+ selectedItem?: T;
7
+ detailsLink?: LocationDescriptor<unknown>;
8
+ isQuickEditMode?: boolean;
9
+ registerSaveCallback?: (callback: () => Promise<void>) => void;
10
+ refresh: () => Promise<void>;
11
+ }
12
+
13
+ // TODO: Find an elegant way to type this context
14
+ export const QuickEditContext = React.createContext<QuickEditContextType<any>>(
15
+ undefined as any,
16
+ );