box-ui-elements 23.5.0-beta.3 → 24.0.0-beta.1

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 (66) hide show
  1. package/dist/explorer.css +1 -1
  2. package/dist/explorer.js +1 -1
  3. package/dist/picker.js +1 -1
  4. package/dist/preview.css +1 -1
  5. package/dist/preview.js +1 -1
  6. package/dist/sidebar.css +1 -1
  7. package/dist/sidebar.js +1 -1
  8. package/es/constants.js +13 -0
  9. package/es/constants.js.flow +13 -0
  10. package/es/constants.js.map +1 -1
  11. package/es/elements/common/content-answers/ContentAnswersModal.js +1 -3
  12. package/es/elements/common/content-answers/ContentAnswersModal.js.map +1 -1
  13. package/es/elements/common/sub-header/SubHeader.js +3 -0
  14. package/es/elements/common/sub-header/SubHeader.js.map +1 -1
  15. package/es/elements/common/sub-header/SubHeaderLeftV2.js +3 -23
  16. package/es/elements/common/sub-header/SubHeaderLeftV2.js.map +1 -1
  17. package/es/elements/common/sub-header/SubHeaderRight.js +6 -2
  18. package/es/elements/common/sub-header/SubHeaderRight.js.map +1 -1
  19. package/es/elements/content-explorer/ContentExplorer.js +55 -10
  20. package/es/elements/content-explorer/ContentExplorer.js.map +1 -1
  21. package/es/elements/content-explorer/ContentExplorer.scss +12 -0
  22. package/es/elements/content-explorer/MetadataSidePanel.js +92 -0
  23. package/es/elements/content-explorer/MetadataSidePanel.js.map +1 -0
  24. package/es/elements/content-explorer/MetadataSidePanel.scss +12 -0
  25. package/es/elements/content-explorer/stories/tests/MetadataView-visual.stories.js +54 -3
  26. package/es/elements/content-explorer/stories/tests/MetadataView-visual.stories.js.map +1 -1
  27. package/es/elements/content-explorer/utils.js +67 -0
  28. package/es/elements/content-explorer/utils.js.map +1 -0
  29. package/es/elements/content-sidebar/BoxAISidebar.js.map +1 -1
  30. package/es/elements/content-sidebar/BoxAISidebarContent.js +2 -4
  31. package/es/elements/content-sidebar/BoxAISidebarContent.js.map +1 -1
  32. package/es/elements/content-sidebar/stories/BoxAISidebar.stories.js +0 -1
  33. package/es/elements/content-sidebar/stories/BoxAISidebar.stories.js.map +1 -1
  34. package/es/elements/content-sidebar/stories/tests/BoxAISidebar-visual.stories.js +0 -1
  35. package/es/elements/content-sidebar/stories/tests/BoxAISidebar-visual.stories.js.map +1 -1
  36. package/es/src/elements/common/content-answers/ContentAnswersModal.d.ts +0 -1
  37. package/es/src/elements/common/sub-header/SubHeader.d.ts +2 -1
  38. package/es/src/elements/common/sub-header/SubHeaderLeftV2.d.ts +1 -1
  39. package/es/src/elements/common/sub-header/SubHeaderRight.d.ts +4 -1
  40. package/es/src/elements/content-explorer/ContentExplorer.d.ts +15 -0
  41. package/es/src/elements/content-explorer/MetadataSidePanel.d.ts +13 -0
  42. package/es/src/elements/content-explorer/__tests__/MetadataSidePanel.test.d.ts +1 -0
  43. package/es/src/elements/content-explorer/stories/tests/MetadataView-visual.stories.d.ts +2 -0
  44. package/es/src/elements/content-explorer/utils.d.ts +22 -0
  45. package/es/src/elements/content-sidebar/BoxAISidebar.d.ts +0 -1
  46. package/es/src/elements/content-sidebar/stories/BoxAISidebar.stories.d.ts +0 -1
  47. package/package.json +2 -2
  48. package/src/constants.js +13 -0
  49. package/src/elements/common/content-answers/ContentAnswersModal.tsx +0 -3
  50. package/src/elements/common/content-answers/__tests__/ContentAnswersModal.test.tsx +7 -2
  51. package/src/elements/common/sub-header/SubHeader.tsx +4 -0
  52. package/src/elements/common/sub-header/SubHeaderLeftV2.tsx +3 -22
  53. package/src/elements/common/sub-header/SubHeaderRight.tsx +8 -2
  54. package/src/elements/content-explorer/ContentExplorer.scss +12 -0
  55. package/src/elements/content-explorer/ContentExplorer.tsx +135 -77
  56. package/src/elements/content-explorer/MetadataSidePanel.scss +12 -0
  57. package/src/elements/content-explorer/MetadataSidePanel.tsx +126 -0
  58. package/src/elements/content-explorer/__tests__/ContentExplorer.test.tsx +80 -16
  59. package/src/elements/content-explorer/__tests__/MetadataSidePanel.test.tsx +127 -0
  60. package/src/elements/content-explorer/stories/tests/MetadataView-visual.stories.tsx +43 -3
  61. package/src/elements/content-explorer/utils.ts +58 -0
  62. package/src/elements/content-sidebar/BoxAISidebar.tsx +0 -1
  63. package/src/elements/content-sidebar/BoxAISidebarContent.tsx +1 -3
  64. package/src/elements/content-sidebar/__tests__/BoxAISidebar.test.tsx +0 -8
  65. package/src/elements/content-sidebar/stories/BoxAISidebar.stories.tsx +0 -1
  66. package/src/elements/content-sidebar/stories/tests/BoxAISidebar-visual.stories.tsx +0 -1
@@ -24,6 +24,7 @@ import ThemingStyles from '../common/theming';
24
24
  import API from '../../api';
25
25
  import MetadataQueryAPIHelperV2 from './MetadataQueryAPIHelper';
26
26
  import MetadataQueryAPIHelper from '../../features/metadata-based-view/MetadataQueryAPIHelper';
27
+ import MetadataSidePanel from './MetadataSidePanel';
27
28
  import Footer from './Footer';
28
29
  import PreviewDialog from '../common/preview-dialog/PreviewDialog';
29
30
  import ShareDialog from './ShareDialog';
@@ -48,6 +49,7 @@ import {
48
49
  DEFAULT_HOSTNAME_STATIC,
49
50
  DEFAULT_SEARCH_DEBOUNCE,
50
51
  SORT_ASC,
52
+ FIELD_ITEM_NAME,
51
53
  FIELD_NAME,
52
54
  FIELD_PERMISSIONS_CAN_SHARE,
53
55
  FIELD_SHARED_LINK,
@@ -169,6 +171,7 @@ type State = {
169
171
  isCreateFolderModalOpen: boolean;
170
172
  isDeleteModalOpen: boolean;
171
173
  isLoading: boolean;
174
+ isMetadataSidePanelOpen: boolean;
172
175
  isPreviewModalOpen: boolean;
173
176
  isRenameModalOpen: boolean;
174
177
  isShareModalOpen: boolean;
@@ -294,6 +297,7 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
294
297
  isCreateFolderModalOpen: false,
295
298
  isDeleteModalOpen: false,
296
299
  isLoading: false,
300
+ isMetadataSidePanelOpen: false,
297
301
  isPreviewModalOpen: false,
298
302
  isRenameModalOpen: false,
299
303
  isShareModalOpen: false,
@@ -451,12 +455,6 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
451
455
  metadataQueryClone.limit = DEFAULT_PAGE_SIZE;
452
456
  }
453
457
 
454
- metadataQueryClone.order_by = [
455
- {
456
- field_key: sortBy,
457
- direction: sortDirection,
458
- },
459
- ];
460
458
  // Reset search state, the view and show busy indicator
461
459
  this.setState({
462
460
  searchQuery: '',
@@ -465,8 +463,22 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
465
463
  });
466
464
 
467
465
  if (isFeatureEnabled(features, 'contentExplorer.metadataViewV2')) {
466
+ metadataQueryClone.order_by = [
467
+ {
468
+ // Default to the prefixed name field for metadata view v2 only, while not touching the default sortBy for other views.
469
+ field_key: sortBy === FIELD_NAME ? FIELD_ITEM_NAME : sortBy,
470
+ direction: sortDirection,
471
+ },
472
+ ];
473
+
468
474
  this.metadataQueryAPIHelper = new MetadataQueryAPIHelperV2(this.api);
469
475
  } else {
476
+ metadataQueryClone.order_by = [
477
+ {
478
+ field_key: sortBy,
479
+ direction: sortDirection,
480
+ },
481
+ ];
470
482
  this.metadataQueryAPIHelper = new MetadataQueryAPIHelper(this.api);
471
483
  }
472
484
 
@@ -1562,7 +1574,11 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
1562
1574
  selectedKeys: selectedItemIds,
1563
1575
  onSelectionChange: (ids: Selection) => {
1564
1576
  onSelectionChange?.(ids);
1565
- this.setState({ selectedItemIds: ids });
1577
+ const isSelectionEmpty = ids !== 'all' && ids.size === 0;
1578
+ this.setState({
1579
+ selectedItemIds: ids,
1580
+ ...(isSelectionEmpty && { isMetadataSidePanelOpen: false }),
1581
+ });
1566
1582
  },
1567
1583
  },
1568
1584
  };
@@ -1644,7 +1660,32 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
1644
1660
  };
1645
1661
 
1646
1662
  clearSelectedItemIds = () => {
1647
- this.setState({ selectedItemIds: new Set() });
1663
+ this.setState({
1664
+ selectedItemIds: new Set(),
1665
+ isMetadataSidePanelOpen: false,
1666
+ });
1667
+ };
1668
+
1669
+ /**
1670
+ * Toggle metadata side panel visibility
1671
+ *
1672
+ * @private
1673
+ * @return {void}
1674
+ */
1675
+ onMetadataSidePanelToggle = () => {
1676
+ this.setState(prevState => ({
1677
+ isMetadataSidePanelOpen: !prevState.isMetadataSidePanelOpen,
1678
+ }));
1679
+ };
1680
+
1681
+ /**
1682
+ * Close metadata side panel
1683
+ *
1684
+ * @private
1685
+ * @return {void}
1686
+ */
1687
+ closeMetadataSidePanel = () => {
1688
+ this.setState({ isMetadataSidePanelOpen: false });
1648
1689
  };
1649
1690
 
1650
1691
  /**
@@ -1706,6 +1747,7 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
1706
1747
  isCreateFolderModalOpen,
1707
1748
  isDeleteModalOpen,
1708
1749
  isLoading,
1750
+ isMetadataSidePanelOpen,
1709
1751
  isPreviewModalOpen,
1710
1752
  isRenameModalOpen,
1711
1753
  isShareModalOpen,
@@ -1714,6 +1756,7 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
1714
1756
  metadataTemplate,
1715
1757
  rootName,
1716
1758
  selected,
1759
+ selectedItemIds,
1717
1760
  view,
1718
1761
  }: State = this.state;
1719
1762
 
@@ -1723,6 +1766,7 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
1723
1766
  const allowUpload: boolean = canUpload && !!can_upload;
1724
1767
  const allowCreate: boolean = canCreateNewFolder && !!can_upload;
1725
1768
  const isDefaultViewMetadata: boolean = defaultView === DEFAULT_VIEW_METADATA;
1769
+ const isMetadataViewV2Feature = isFeatureEnabled(features, 'contentExplorer.metadataViewV2');
1726
1770
  const isErrorView: boolean = view === VIEW_ERROR;
1727
1771
 
1728
1772
  const viewMode = this.getViewMode();
@@ -1741,75 +1785,89 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
1741
1785
  <div id={this.id} className={styleClassName} ref={measureRef} data-testid="content-explorer">
1742
1786
  <ThemingStyles selector={`#${this.id}`} theme={theme} />
1743
1787
  <div className="be-app-element" onKeyDown={this.onKeyDown} tabIndex={0}>
1744
- {!isDefaultViewMetadata && <Header view={view} logoUrl={logoUrl} onSearch={this.search} />}
1745
-
1746
- <SubHeader
1747
- view={view}
1748
- viewMode={viewMode}
1749
- rootId={rootFolderId}
1750
- isSmall={isSmall}
1751
- rootName={rootName}
1752
- currentCollection={currentCollection}
1753
- canUpload={allowUpload}
1754
- canCreateNewFolder={allowCreate}
1755
- gridColumnCount={gridColumnCount}
1756
- gridMaxColumns={GRID_VIEW_MAX_COLUMNS}
1757
- gridMinColumns={GRID_VIEW_MIN_COLUMNS}
1758
- maxGridColumnCountForWidth={maxGridColumnCount}
1759
- onUpload={this.upload}
1760
- onClearSelectedItemIds={this.clearSelectedItemIds}
1761
- onCreate={this.createFolder}
1762
- onGridViewSliderChange={this.onGridViewSliderChange}
1763
- onItemClick={this.fetchFolder}
1764
- onSortChange={this.sort}
1765
- onViewModeChange={this.changeViewMode}
1766
- portalElement={this.rootElement}
1767
- selectedItemIds={this.state.selectedItemIds}
1768
- title={title}
1769
- />
1770
-
1771
- <Content
1772
- canDelete={canDelete}
1773
- canDownload={canDownload}
1774
- canPreview={canPreview}
1775
- canRename={canRename}
1776
- canShare={canShare}
1777
- currentCollection={currentCollection}
1778
- features={features}
1779
- gridColumnCount={Math.min(gridColumnCount, maxGridColumnCount)}
1780
- isMedium={isMedium}
1781
- isSmall={isSmall}
1782
- isTouch={isTouch}
1783
- itemActions={itemActions}
1784
- fieldsToShow={fieldsToShow}
1785
- metadataTemplate={metadataTemplate}
1786
- metadataViewProps={metadataViewProps}
1787
- onItemClick={this.onItemClick}
1788
- onItemDelete={this.delete}
1789
- onItemDownload={this.download}
1790
- onItemPreview={this.preview}
1791
- onItemRename={this.rename}
1792
- onItemSelect={this.select}
1793
- onItemShare={this.share}
1794
- onMetadataUpdate={this.updateMetadata}
1795
- onSortChange={this.sort}
1796
- portalElement={this.rootElement}
1797
- view={view}
1798
- viewMode={viewMode}
1799
- />
1800
- {!isErrorView && (
1801
- <Footer>
1802
- <Pagination
1803
- hasNextMarker={hasNextMarker}
1804
- hasPrevMarker={hasPreviousMarker}
1805
- isSmall={isSmall}
1806
- offset={offset}
1807
- onOffsetChange={this.paginate}
1808
- pageSize={currentPageSize}
1809
- totalCount={totalCount}
1810
- onMarkerBasedPageChange={this.markerBasedPaginate}
1811
- />
1812
- </Footer>
1788
+ <div className="bce-ContentExplorer-main">
1789
+ {!isDefaultViewMetadata && (
1790
+ <Header view={view} logoUrl={logoUrl} onSearch={this.search} />
1791
+ )}
1792
+
1793
+ <SubHeader
1794
+ view={view}
1795
+ viewMode={viewMode}
1796
+ rootId={rootFolderId}
1797
+ isSmall={isSmall}
1798
+ rootName={rootName}
1799
+ currentCollection={currentCollection}
1800
+ canUpload={allowUpload}
1801
+ canCreateNewFolder={allowCreate}
1802
+ gridColumnCount={gridColumnCount}
1803
+ gridMaxColumns={GRID_VIEW_MAX_COLUMNS}
1804
+ gridMinColumns={GRID_VIEW_MIN_COLUMNS}
1805
+ maxGridColumnCountForWidth={maxGridColumnCount}
1806
+ onUpload={this.upload}
1807
+ onClearSelectedItemIds={this.clearSelectedItemIds}
1808
+ onCreate={this.createFolder}
1809
+ onGridViewSliderChange={this.onGridViewSliderChange}
1810
+ onItemClick={this.fetchFolder}
1811
+ onSortChange={this.sort}
1812
+ onMetadataSidePanelToggle={this.onMetadataSidePanelToggle}
1813
+ onViewModeChange={this.changeViewMode}
1814
+ portalElement={this.rootElement}
1815
+ selectedItemIds={selectedItemIds}
1816
+ title={title}
1817
+ />
1818
+
1819
+ <Content
1820
+ canDelete={canDelete}
1821
+ canDownload={canDownload}
1822
+ canPreview={canPreview}
1823
+ canRename={canRename}
1824
+ canShare={canShare}
1825
+ currentCollection={currentCollection}
1826
+ features={features}
1827
+ gridColumnCount={Math.min(gridColumnCount, maxGridColumnCount)}
1828
+ isMedium={isMedium}
1829
+ isSmall={isSmall}
1830
+ isTouch={isTouch}
1831
+ itemActions={itemActions}
1832
+ fieldsToShow={fieldsToShow}
1833
+ metadataTemplate={metadataTemplate}
1834
+ metadataViewProps={metadataViewProps}
1835
+ onItemClick={this.onItemClick}
1836
+ onItemDelete={this.delete}
1837
+ onItemDownload={this.download}
1838
+ onItemPreview={this.preview}
1839
+ onItemRename={this.rename}
1840
+ onItemSelect={this.select}
1841
+ onItemShare={this.share}
1842
+ onMetadataUpdate={this.updateMetadata}
1843
+ onSortChange={this.sort}
1844
+ portalElement={this.rootElement}
1845
+ view={view}
1846
+ viewMode={viewMode}
1847
+ />
1848
+
1849
+ {!isErrorView && (
1850
+ <Footer>
1851
+ <Pagination
1852
+ hasNextMarker={hasNextMarker}
1853
+ hasPrevMarker={hasPreviousMarker}
1854
+ isSmall={isSmall}
1855
+ offset={offset}
1856
+ onOffsetChange={this.paginate}
1857
+ pageSize={currentPageSize}
1858
+ totalCount={totalCount}
1859
+ onMarkerBasedPageChange={this.markerBasedPaginate}
1860
+ />
1861
+ </Footer>
1862
+ )}
1863
+ </div>
1864
+ {isDefaultViewMetadata && isMetadataViewV2Feature && isMetadataSidePanelOpen && (
1865
+ <MetadataSidePanel
1866
+ currentCollection={currentCollection}
1867
+ onClose={this.closeMetadataSidePanel}
1868
+ metadataTemplate={metadataTemplate}
1869
+ selectedItemIds={selectedItemIds}
1870
+ />
1813
1871
  )}
1814
1872
  </div>
1815
1873
  {allowUpload && !!this.appElement ? (
@@ -0,0 +1,12 @@
1
+ .bce-MetadataSidePanel-subtitle {
2
+ display: flex;
3
+ align-items: center;
4
+ }
5
+
6
+ .bce-MetadataSidePanel-content {
7
+ padding: var(--space-4);
8
+
9
+ [data-target-id='TextButton-deleteButton'] {
10
+ visibility: hidden;
11
+ }
12
+ }
@@ -0,0 +1,126 @@
1
+ import React, { useState } from 'react';
2
+ import { useIntl } from 'react-intl';
3
+
4
+ import { IconButton, SidePanel, Text } from '@box/blueprint-web';
5
+ import { XMark } from '@box/blueprint-web-assets/icons/Fill/index';
6
+ import { FileDefault } from '@box/blueprint-web-assets/icons/Line/index';
7
+ import {
8
+ AutofillContextProvider,
9
+ FormValues,
10
+ JSONPatchOperations,
11
+ MetadataInstance,
12
+ MetadataInstanceForm,
13
+ } from '@box/metadata-editor';
14
+
15
+ import type { Selection } from 'react-aria-components';
16
+ import type { Collection } from '../../common/types/core';
17
+ import type { MetadataTemplate } from '../../common/types/metadata';
18
+ import { getTemplateInstance, useSelectedItemText } from './utils';
19
+
20
+ import messages from '../common/messages';
21
+
22
+ import './MetadataSidePanel.scss';
23
+
24
+ export interface MetadataSidePanelProps {
25
+ currentCollection: Collection;
26
+ onClose: () => void;
27
+ metadataTemplate: MetadataTemplate;
28
+ selectedItemIds: Selection;
29
+ }
30
+
31
+ const MetadataSidePanel = ({
32
+ currentCollection,
33
+ onClose,
34
+ selectedItemIds,
35
+ metadataTemplate,
36
+ }: MetadataSidePanelProps) => {
37
+ const { formatMessage } = useIntl();
38
+ const [isEditing, setIsEditing] = useState<boolean>(false);
39
+ const [isUnsavedChangesModalOpen, setIsUnsavedChangesModalOpen] = useState<boolean>(false);
40
+
41
+ const selectedItemText = useSelectedItemText(currentCollection, selectedItemIds);
42
+ const selectedItems =
43
+ selectedItemIds === 'all'
44
+ ? currentCollection.items
45
+ : currentCollection.items.filter(item => selectedItemIds.has(item.id));
46
+ const templateInstance = getTemplateInstance(metadataTemplate, selectedItems);
47
+
48
+ const handleMetadataInstanceEdit = () => {
49
+ setIsEditing(true);
50
+ };
51
+
52
+ const handleMetadataInstanceFormCancel = () => {
53
+ setIsEditing(false);
54
+ };
55
+
56
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
57
+ const handleMetadataInstanceFormChange = (values: FormValues) => {
58
+ // TODO: Implement on form change
59
+ };
60
+
61
+ const handleMetadataInstanceFormDiscardUnsavedChanges = () => {
62
+ setIsUnsavedChangesModalOpen(false);
63
+ setIsEditing(false);
64
+ };
65
+
66
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
67
+ const handleMetadataInstanceFormSubmit = async (values: FormValues, operations: JSONPatchOperations) => {
68
+ // TODO: Implement onSave callback
69
+ };
70
+
71
+ return (
72
+ <SidePanel variant="persistent">
73
+ <SidePanel.Header>
74
+ <div>
75
+ <Text as="span" variant="titleLarge">
76
+ {formatMessage(messages.sidebarMetadataTitle)}
77
+ </Text>
78
+ <div className="bce-MetadataSidePanel-subtitle">
79
+ <FileDefault />
80
+ <Text as="span" color="textOnLightSecondary" variant="subtitle">
81
+ {selectedItemText}
82
+ </Text>
83
+ </div>
84
+ </div>
85
+ <IconButton aria-label={formatMessage(messages.close)} icon={XMark} onClick={onClose} size="large" />
86
+ </SidePanel.Header>
87
+ <SidePanel.ScrollableContainer>
88
+ <div className="bce-MetadataSidePanel-content">
89
+ <AutofillContextProvider fetchSuggestions={null} isAiSuggestionsFeatureEnabled={false}>
90
+ {isEditing ? (
91
+ <MetadataInstanceForm
92
+ areAiSuggestionsAvailable={false}
93
+ isAiSuggestionsFeatureEnabled={false}
94
+ isBetaLanguageEnabled={false}
95
+ isDeleteButtonDisabled={true}
96
+ isDeleteConfirmationModalCheckboxEnabled={false}
97
+ isLargeFile={false}
98
+ isMultilevelTaxonomyFieldEnabled={false}
99
+ isUnsavedChangesModalOpen={isUnsavedChangesModalOpen}
100
+ selectedTemplateInstance={templateInstance}
101
+ onCancel={handleMetadataInstanceFormCancel}
102
+ onChange={handleMetadataInstanceFormChange}
103
+ onDelete={null}
104
+ onDiscardUnsavedChanges={handleMetadataInstanceFormDiscardUnsavedChanges}
105
+ onSubmit={handleMetadataInstanceFormSubmit}
106
+ setIsUnsavedChangesModalOpen={setIsUnsavedChangesModalOpen}
107
+ taxonomyOptionsFetcher={null}
108
+ />
109
+ ) : (
110
+ <MetadataInstance
111
+ areAiSuggestionsAvailable={false}
112
+ isAiSuggestionsFeatureEnabled={false}
113
+ isBetaLanguageEnabled={false}
114
+ onEdit={handleMetadataInstanceEdit}
115
+ templateInstance={templateInstance}
116
+ taxonomyNodeFetcher={null}
117
+ />
118
+ )}
119
+ </AutofillContextProvider>
120
+ </div>
121
+ </SidePanel.ScrollableContainer>
122
+ </SidePanel>
123
+ );
124
+ };
125
+
126
+ export default MetadataSidePanel;
@@ -1,5 +1,7 @@
1
1
  import React from 'react';
2
2
  import userEvent from '@testing-library/user-event';
3
+ import type { MetadataFieldType } from '@box/metadata-view';
4
+
3
5
  import { render, screen, waitFor, within } from '../../../test-utils/testing-library';
4
6
  import { ContentExplorerComponent as ContentExplorer, ContentExplorerProps } from '../ContentExplorer';
5
7
  import { mockRecentItems, mockRootFolder, mockRootFolderSharedLink } from '../../common/__mocks__/mockRootFolder';
@@ -77,7 +79,13 @@ describe('elements/content-explorer/ContentExplorer', () => {
77
79
  const renderComponent = ({ features, ...props }: Partial<ContentExplorerProps> = {}) => {
78
80
  return render(
79
81
  <FeatureProvider features={features}>
80
- <ContentExplorer defaultView="list" rootFolderId="69083462919" token="token" {...props} />
82
+ <ContentExplorer
83
+ defaultView="list"
84
+ features={features}
85
+ rootFolderId="69083462919"
86
+ token="token"
87
+ {...props}
88
+ />
81
89
  </FeatureProvider>,
82
90
  );
83
91
  };
@@ -414,31 +422,87 @@ describe('elements/content-explorer/ContentExplorer', () => {
414
422
  expect(screen.getByText('Technology')).toBeInTheDocument();
415
423
  expect(screen.getByText('November 16, 2023')).toBeInTheDocument();
416
424
  });
425
+
417
426
  describe('Metadata View V2', () => {
418
- test('should render metadata view button', async () => {
419
- renderComponent({
420
- defaultView: 'metadata',
421
- features: {
422
- contentExplorer: {
423
- metadataViewV2: true,
424
- },
427
+ const { scope: templateScope, templateKey } = mockSchema;
428
+ const metadataScopeAndKey = `${templateScope}.${templateKey}`;
429
+ const metadataFieldNamePrefix = `metadata.${metadataScopeAndKey}`;
430
+ const metadataQuery = {
431
+ from: metadataScopeAndKey,
432
+ ancestor_folder_id: '69083462919',
433
+ sort_by: [
434
+ {
435
+ field_key: `${metadataFieldNamePrefix}.${mockSchema.fields[0].key}`, // Default to sorting by the first field in the schema
436
+ direction: 'asc',
437
+ },
438
+ ],
439
+ fields: [
440
+ // Default to returning all fields in the metadata template schema, and name as a standalone (non-metadata) field
441
+ ...mockSchema.fields.map(field => `${metadataFieldNamePrefix}.${field.key}`),
442
+ 'name',
443
+ ],
444
+ };
445
+ const fieldsToShow = [
446
+ { key: `${metadataFieldNamePrefix}.name`, canEdit: false, displayName: 'Alias' },
447
+ { key: `${metadataFieldNamePrefix}.industry`, canEdit: true },
448
+ { key: `${metadataFieldNamePrefix}.last_contacted_at`, canEdit: true },
449
+ { key: `${metadataFieldNamePrefix}.role`, canEdit: true },
450
+ ];
451
+ const columns = [
452
+ {
453
+ // Always include the name column
454
+ textValue: 'Name',
455
+ id: 'name',
456
+ type: 'string' as const,
457
+ allowSorting: true,
458
+ minWidth: 150,
459
+ maxWidth: 150,
460
+ },
461
+ ...mockSchema.fields.map(field => ({
462
+ textValue: field.displayName,
463
+ id: `${metadataFieldNamePrefix}.${field.key}`,
464
+ type: field.type as MetadataFieldType,
465
+ allowSorting: true,
466
+ minWidth: 150,
467
+ maxWidth: 150,
468
+ })),
469
+ ];
470
+ const defaultView = 'metadata';
471
+ const metadataViewV2ElementProps = {
472
+ metadataViewProps: {
473
+ columns,
474
+ metadataTemplate: mockSchema,
475
+ tableProps: {
476
+ isSelectAllEnabled: true,
425
477
  },
478
+ },
479
+ metadataQuery,
480
+ fieldsToShow,
481
+ defaultView,
482
+ features: {
483
+ contentExplorer: {
484
+ metadataViewV2: true,
485
+ },
486
+ },
487
+ };
488
+
489
+ test('should render metadata view button', async () => {
490
+ renderComponent(metadataViewV2ElementProps);
491
+ await waitFor(() => {
492
+ expect(screen.getByTestId('content-explorer')).toBeInTheDocument();
426
493
  });
427
494
 
428
- // two separate promises need to be resolved before the component is ready
429
495
  await waitFor(() => {
430
- expect(screen.getByText('Please wait while the items load...')).toBeInTheDocument();
496
+ expect(screen.queryByRole('button', { name: 'Switch to Grid View' })).toBeInTheDocument();
431
497
  });
432
498
 
433
499
  await waitFor(() => {
434
- expect(screen.getByTestId('content-explorer')).toBeInTheDocument();
500
+ expect(screen.getByRole('row', { name: /Child 2/i })).toBeInTheDocument();
435
501
  });
436
502
 
437
- expect(screen.queryByRole('searchbox', { name: 'Search files and folders' })).not.toBeInTheDocument();
438
- expect(screen.queryByRole('button', { name: 'Preview Test Folder' })).not.toBeInTheDocument();
439
- expect(screen.queryByRole('button', { name: 'Switch to Grid View' })).not.toBeInTheDocument();
440
- expect(screen.queryByRole('button', { name: 'Sort' })).not.toBeInTheDocument();
441
- expect(screen.queryByRole('button', { name: 'Add' })).not.toBeInTheDocument();
503
+ const selectAllCheckbox = screen.getByLabelText('Select all');
504
+ await userEvent.click(selectAllCheckbox);
505
+
442
506
  expect(screen.getByRole('button', { name: 'Metadata' })).toBeInTheDocument();
443
507
  });
444
508
  });