box-ui-elements 23.5.0-beta.2 → 23.5.0-beta.4
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/explorer.css +1 -1
- package/dist/explorer.js +1 -1
- package/dist/picker.js +1 -1
- package/dist/preview.css +1 -1
- package/dist/preview.js +1 -1
- package/dist/sidebar.css +1 -1
- package/dist/sidebar.js +1 -1
- package/es/elements/common/sub-header/SubHeader.js +3 -0
- package/es/elements/common/sub-header/SubHeader.js.map +1 -1
- package/es/elements/common/sub-header/SubHeaderLeftV2.js +3 -23
- package/es/elements/common/sub-header/SubHeaderLeftV2.js.map +1 -1
- package/es/elements/common/sub-header/SubHeaderRight.js +6 -2
- package/es/elements/common/sub-header/SubHeaderRight.js.map +1 -1
- package/es/elements/content-explorer/ContentExplorer.js +44 -5
- package/es/elements/content-explorer/ContentExplorer.js.map +1 -1
- package/es/elements/content-explorer/ContentExplorer.scss +12 -0
- package/es/elements/content-explorer/MetadataSidePanel.js +92 -0
- package/es/elements/content-explorer/MetadataSidePanel.js.map +1 -0
- package/es/elements/content-explorer/MetadataSidePanel.scss +12 -0
- package/es/elements/content-explorer/stories/tests/MetadataView-visual.stories.js +30 -0
- package/es/elements/content-explorer/stories/tests/MetadataView-visual.stories.js.map +1 -1
- package/es/elements/content-explorer/utils.js +67 -0
- package/es/elements/content-explorer/utils.js.map +1 -0
- package/es/features/metadata-instance-editor/CascadePolicy.js +3 -3
- package/es/features/metadata-instance-editor/CascadePolicy.js.flow +2 -3
- package/es/features/metadata-instance-editor/CascadePolicy.js.map +1 -1
- package/es/features/metadata-instance-editor/Instance.js +0 -2
- package/es/features/metadata-instance-editor/Instance.js.flow +0 -5
- package/es/features/metadata-instance-editor/Instance.js.map +1 -1
- package/es/features/metadata-instance-editor/Instances.js +0 -2
- package/es/features/metadata-instance-editor/Instances.js.flow +0 -3
- package/es/features/metadata-instance-editor/Instances.js.map +1 -1
- package/es/features/metadata-instance-editor/MetadataInstanceEditor.js +0 -2
- package/es/features/metadata-instance-editor/MetadataInstanceEditor.js.flow +0 -3
- package/es/features/metadata-instance-editor/MetadataInstanceEditor.js.map +1 -1
- package/es/features/metadata-instance-editor/stories/tests/CascadePolicy-visual.stories.js +0 -1
- package/es/features/metadata-instance-editor/stories/tests/CascadePolicy-visual.stories.js.flow +0 -1
- package/es/features/metadata-instance-editor/stories/tests/CascadePolicy-visual.stories.js.map +1 -1
- package/es/src/elements/common/sub-header/SubHeader.d.ts +2 -1
- package/es/src/elements/common/sub-header/SubHeaderLeftV2.d.ts +1 -1
- package/es/src/elements/common/sub-header/SubHeaderRight.d.ts +4 -1
- package/es/src/elements/content-explorer/ContentExplorer.d.ts +15 -0
- package/es/src/elements/content-explorer/MetadataSidePanel.d.ts +13 -0
- package/es/src/elements/content-explorer/__tests__/MetadataSidePanel.test.d.ts +1 -0
- package/es/src/elements/content-explorer/stories/tests/MetadataView-visual.stories.d.ts +1 -0
- package/es/src/elements/content-explorer/utils.d.ts +22 -0
- package/package.json +3 -3
- package/src/elements/common/sub-header/SubHeader.tsx +4 -0
- package/src/elements/common/sub-header/SubHeaderLeftV2.tsx +3 -22
- package/src/elements/common/sub-header/SubHeaderRight.tsx +8 -2
- package/src/elements/content-explorer/ContentExplorer.scss +12 -0
- package/src/elements/content-explorer/ContentExplorer.tsx +120 -71
- package/src/elements/content-explorer/MetadataSidePanel.scss +12 -0
- package/src/elements/content-explorer/MetadataSidePanel.tsx +126 -0
- package/src/elements/content-explorer/__tests__/ContentExplorer.test.tsx +80 -16
- package/src/elements/content-explorer/__tests__/MetadataSidePanel.test.tsx +127 -0
- package/src/elements/content-explorer/stories/tests/MetadataView-visual.stories.tsx +26 -0
- package/src/elements/content-explorer/utils.ts +58 -0
- package/src/features/metadata-instance-editor/CascadePolicy.js +2 -3
- package/src/features/metadata-instance-editor/Instance.js +0 -5
- package/src/features/metadata-instance-editor/Instances.js +0 -3
- package/src/features/metadata-instance-editor/MetadataInstanceEditor.js +0 -3
- package/src/features/metadata-instance-editor/__tests__/CascadePolicy.test.js +0 -9
- package/src/features/metadata-instance-editor/__tests__/Instance.test.js +0 -28
- package/src/features/metadata-instance-editor/__tests__/Instances.test.js +7 -9
- package/src/features/metadata-instance-editor/__tests__/MetadataInstanceEditor.test.js +1 -48
- package/src/features/metadata-instance-editor/__tests__/__snapshots__/Instance.test.js.snap +0 -1
- package/src/features/metadata-instance-editor/__tests__/__snapshots__/Instances.test.js.snap +0 -2
- package/src/features/metadata-instance-editor/__tests__/__snapshots__/MetadataInstanceEditor.test.js.snap +0 -1
- package/src/features/metadata-instance-editor/stories/tests/CascadePolicy-visual.stories.js +0 -1
|
@@ -2,6 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
import { Button } from '@box/blueprint-web';
|
|
3
3
|
import { Pencil } from '@box/blueprint-web-assets/icons/Fill';
|
|
4
4
|
import { useIntl } from 'react-intl';
|
|
5
|
+
import type { Selection } from 'react-aria-components';
|
|
5
6
|
import Sort from './Sort';
|
|
6
7
|
import Add from './Add';
|
|
7
8
|
import GridViewSlider from '../../../components/grid-view/GridViewSlider';
|
|
@@ -27,9 +28,11 @@ export interface SubHeaderRightProps {
|
|
|
27
28
|
onCreate: () => void;
|
|
28
29
|
onGridViewSliderChange: (newSliderValue: number) => void;
|
|
29
30
|
onSortChange: (sortBy: SortBy, sortDirection: SortDirection) => void;
|
|
31
|
+
onMetadataSidePanelToggle?: () => void;
|
|
30
32
|
onUpload: () => void;
|
|
31
33
|
onViewModeChange?: (viewMode: ViewMode) => void;
|
|
32
34
|
portalElement?: HTMLElement;
|
|
35
|
+
selectedItemIds?: Selection;
|
|
33
36
|
view: View;
|
|
34
37
|
viewMode: ViewMode;
|
|
35
38
|
}
|
|
@@ -45,9 +48,11 @@ const SubHeaderRight = ({
|
|
|
45
48
|
onCreate,
|
|
46
49
|
onGridViewSliderChange,
|
|
47
50
|
onSortChange,
|
|
51
|
+
onMetadataSidePanelToggle,
|
|
48
52
|
onUpload,
|
|
49
53
|
onViewModeChange,
|
|
50
54
|
portalElement,
|
|
55
|
+
selectedItemIds,
|
|
51
56
|
view,
|
|
52
57
|
viewMode,
|
|
53
58
|
}: SubHeaderRightProps) => {
|
|
@@ -60,6 +65,7 @@ const SubHeaderRight = ({
|
|
|
60
65
|
const showSort: boolean = isFolder && hasItems;
|
|
61
66
|
const showAdd: boolean = (!!canUpload || !!canCreateNewFolder) && isFolder;
|
|
62
67
|
const isMetadataView: boolean = view === VIEW_METADATA;
|
|
68
|
+
const hasSelectedItems: boolean = !!(selectedItemIds && (selectedItemIds === 'all' || selectedItemIds.size > 0));
|
|
63
69
|
return (
|
|
64
70
|
<div className="be-sub-header-right">
|
|
65
71
|
{!isMetadataView && (
|
|
@@ -90,8 +96,8 @@ const SubHeaderRight = ({
|
|
|
90
96
|
</>
|
|
91
97
|
)}
|
|
92
98
|
|
|
93
|
-
{isMetadataView && isMetadataViewV2Feature && (
|
|
94
|
-
<Button icon={Pencil} size="large" variant="primary">
|
|
99
|
+
{isMetadataView && isMetadataViewV2Feature && hasSelectedItems && (
|
|
100
|
+
<Button icon={Pencil} size="large" variant="primary" onClick={onMetadataSidePanelToggle}>
|
|
95
101
|
{formatMessage(messages.metadata)}
|
|
96
102
|
</Button>
|
|
97
103
|
)}
|
|
@@ -7,5 +7,17 @@
|
|
|
7
7
|
.bcpr {
|
|
8
8
|
z-index: 1; // Prevents overlay issues with list-item when a file is previewed
|
|
9
9
|
}
|
|
10
|
+
|
|
11
|
+
.be-app-element {
|
|
12
|
+
flex-direction: row;
|
|
13
|
+
gap: var(--space-4);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.bce-ContentExplorer-main {
|
|
17
|
+
display: flex;
|
|
18
|
+
flex: 1;
|
|
19
|
+
flex-direction: column;
|
|
20
|
+
min-width: 0;
|
|
21
|
+
}
|
|
10
22
|
}
|
|
11
23
|
}
|
|
@@ -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';
|
|
@@ -169,6 +170,7 @@ type State = {
|
|
|
169
170
|
isCreateFolderModalOpen: boolean;
|
|
170
171
|
isDeleteModalOpen: boolean;
|
|
171
172
|
isLoading: boolean;
|
|
173
|
+
isMetadataSidePanelOpen: boolean;
|
|
172
174
|
isPreviewModalOpen: boolean;
|
|
173
175
|
isRenameModalOpen: boolean;
|
|
174
176
|
isShareModalOpen: boolean;
|
|
@@ -294,6 +296,7 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
|
|
|
294
296
|
isCreateFolderModalOpen: false,
|
|
295
297
|
isDeleteModalOpen: false,
|
|
296
298
|
isLoading: false,
|
|
299
|
+
isMetadataSidePanelOpen: false,
|
|
297
300
|
isPreviewModalOpen: false,
|
|
298
301
|
isRenameModalOpen: false,
|
|
299
302
|
isShareModalOpen: false,
|
|
@@ -1562,7 +1565,11 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
|
|
|
1562
1565
|
selectedKeys: selectedItemIds,
|
|
1563
1566
|
onSelectionChange: (ids: Selection) => {
|
|
1564
1567
|
onSelectionChange?.(ids);
|
|
1565
|
-
|
|
1568
|
+
const isSelectionEmpty = ids !== 'all' && ids.size === 0;
|
|
1569
|
+
this.setState({
|
|
1570
|
+
selectedItemIds: ids,
|
|
1571
|
+
...(isSelectionEmpty && { isMetadataSidePanelOpen: false }),
|
|
1572
|
+
});
|
|
1566
1573
|
},
|
|
1567
1574
|
},
|
|
1568
1575
|
};
|
|
@@ -1644,7 +1651,32 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
|
|
|
1644
1651
|
};
|
|
1645
1652
|
|
|
1646
1653
|
clearSelectedItemIds = () => {
|
|
1647
|
-
this.setState({
|
|
1654
|
+
this.setState({
|
|
1655
|
+
selectedItemIds: new Set(),
|
|
1656
|
+
isMetadataSidePanelOpen: false,
|
|
1657
|
+
});
|
|
1658
|
+
};
|
|
1659
|
+
|
|
1660
|
+
/**
|
|
1661
|
+
* Toggle metadata side panel visibility
|
|
1662
|
+
*
|
|
1663
|
+
* @private
|
|
1664
|
+
* @return {void}
|
|
1665
|
+
*/
|
|
1666
|
+
onMetadataSidePanelToggle = () => {
|
|
1667
|
+
this.setState(prevState => ({
|
|
1668
|
+
isMetadataSidePanelOpen: !prevState.isMetadataSidePanelOpen,
|
|
1669
|
+
}));
|
|
1670
|
+
};
|
|
1671
|
+
|
|
1672
|
+
/**
|
|
1673
|
+
* Close metadata side panel
|
|
1674
|
+
*
|
|
1675
|
+
* @private
|
|
1676
|
+
* @return {void}
|
|
1677
|
+
*/
|
|
1678
|
+
closeMetadataSidePanel = () => {
|
|
1679
|
+
this.setState({ isMetadataSidePanelOpen: false });
|
|
1648
1680
|
};
|
|
1649
1681
|
|
|
1650
1682
|
/**
|
|
@@ -1706,6 +1738,7 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
|
|
|
1706
1738
|
isCreateFolderModalOpen,
|
|
1707
1739
|
isDeleteModalOpen,
|
|
1708
1740
|
isLoading,
|
|
1741
|
+
isMetadataSidePanelOpen,
|
|
1709
1742
|
isPreviewModalOpen,
|
|
1710
1743
|
isRenameModalOpen,
|
|
1711
1744
|
isShareModalOpen,
|
|
@@ -1714,6 +1747,7 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
|
|
|
1714
1747
|
metadataTemplate,
|
|
1715
1748
|
rootName,
|
|
1716
1749
|
selected,
|
|
1750
|
+
selectedItemIds,
|
|
1717
1751
|
view,
|
|
1718
1752
|
}: State = this.state;
|
|
1719
1753
|
|
|
@@ -1723,6 +1757,7 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
|
|
|
1723
1757
|
const allowUpload: boolean = canUpload && !!can_upload;
|
|
1724
1758
|
const allowCreate: boolean = canCreateNewFolder && !!can_upload;
|
|
1725
1759
|
const isDefaultViewMetadata: boolean = defaultView === DEFAULT_VIEW_METADATA;
|
|
1760
|
+
const isMetadataViewV2Feature = isFeatureEnabled(features, 'contentExplorer.metadataViewV2');
|
|
1726
1761
|
const isErrorView: boolean = view === VIEW_ERROR;
|
|
1727
1762
|
|
|
1728
1763
|
const viewMode = this.getViewMode();
|
|
@@ -1741,75 +1776,89 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
|
|
|
1741
1776
|
<div id={this.id} className={styleClassName} ref={measureRef} data-testid="content-explorer">
|
|
1742
1777
|
<ThemingStyles selector={`#${this.id}`} theme={theme} />
|
|
1743
1778
|
<div className="be-app-element" onKeyDown={this.onKeyDown} tabIndex={0}>
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1779
|
+
<div className="bce-ContentExplorer-main">
|
|
1780
|
+
{!isDefaultViewMetadata && (
|
|
1781
|
+
<Header view={view} logoUrl={logoUrl} onSearch={this.search} />
|
|
1782
|
+
)}
|
|
1783
|
+
|
|
1784
|
+
<SubHeader
|
|
1785
|
+
view={view}
|
|
1786
|
+
viewMode={viewMode}
|
|
1787
|
+
rootId={rootFolderId}
|
|
1788
|
+
isSmall={isSmall}
|
|
1789
|
+
rootName={rootName}
|
|
1790
|
+
currentCollection={currentCollection}
|
|
1791
|
+
canUpload={allowUpload}
|
|
1792
|
+
canCreateNewFolder={allowCreate}
|
|
1793
|
+
gridColumnCount={gridColumnCount}
|
|
1794
|
+
gridMaxColumns={GRID_VIEW_MAX_COLUMNS}
|
|
1795
|
+
gridMinColumns={GRID_VIEW_MIN_COLUMNS}
|
|
1796
|
+
maxGridColumnCountForWidth={maxGridColumnCount}
|
|
1797
|
+
onUpload={this.upload}
|
|
1798
|
+
onClearSelectedItemIds={this.clearSelectedItemIds}
|
|
1799
|
+
onCreate={this.createFolder}
|
|
1800
|
+
onGridViewSliderChange={this.onGridViewSliderChange}
|
|
1801
|
+
onItemClick={this.fetchFolder}
|
|
1802
|
+
onSortChange={this.sort}
|
|
1803
|
+
onMetadataSidePanelToggle={this.onMetadataSidePanelToggle}
|
|
1804
|
+
onViewModeChange={this.changeViewMode}
|
|
1805
|
+
portalElement={this.rootElement}
|
|
1806
|
+
selectedItemIds={selectedItemIds}
|
|
1807
|
+
title={title}
|
|
1808
|
+
/>
|
|
1809
|
+
|
|
1810
|
+
<Content
|
|
1811
|
+
canDelete={canDelete}
|
|
1812
|
+
canDownload={canDownload}
|
|
1813
|
+
canPreview={canPreview}
|
|
1814
|
+
canRename={canRename}
|
|
1815
|
+
canShare={canShare}
|
|
1816
|
+
currentCollection={currentCollection}
|
|
1817
|
+
features={features}
|
|
1818
|
+
gridColumnCount={Math.min(gridColumnCount, maxGridColumnCount)}
|
|
1819
|
+
isMedium={isMedium}
|
|
1820
|
+
isSmall={isSmall}
|
|
1821
|
+
isTouch={isTouch}
|
|
1822
|
+
itemActions={itemActions}
|
|
1823
|
+
fieldsToShow={fieldsToShow}
|
|
1824
|
+
metadataTemplate={metadataTemplate}
|
|
1825
|
+
metadataViewProps={metadataViewProps}
|
|
1826
|
+
onItemClick={this.onItemClick}
|
|
1827
|
+
onItemDelete={this.delete}
|
|
1828
|
+
onItemDownload={this.download}
|
|
1829
|
+
onItemPreview={this.preview}
|
|
1830
|
+
onItemRename={this.rename}
|
|
1831
|
+
onItemSelect={this.select}
|
|
1832
|
+
onItemShare={this.share}
|
|
1833
|
+
onMetadataUpdate={this.updateMetadata}
|
|
1834
|
+
onSortChange={this.sort}
|
|
1835
|
+
portalElement={this.rootElement}
|
|
1836
|
+
view={view}
|
|
1837
|
+
viewMode={viewMode}
|
|
1838
|
+
/>
|
|
1839
|
+
|
|
1840
|
+
{!isErrorView && (
|
|
1841
|
+
<Footer>
|
|
1842
|
+
<Pagination
|
|
1843
|
+
hasNextMarker={hasNextMarker}
|
|
1844
|
+
hasPrevMarker={hasPreviousMarker}
|
|
1845
|
+
isSmall={isSmall}
|
|
1846
|
+
offset={offset}
|
|
1847
|
+
onOffsetChange={this.paginate}
|
|
1848
|
+
pageSize={currentPageSize}
|
|
1849
|
+
totalCount={totalCount}
|
|
1850
|
+
onMarkerBasedPageChange={this.markerBasedPaginate}
|
|
1851
|
+
/>
|
|
1852
|
+
</Footer>
|
|
1853
|
+
)}
|
|
1854
|
+
</div>
|
|
1855
|
+
{isDefaultViewMetadata && isMetadataViewV2Feature && isMetadataSidePanelOpen && (
|
|
1856
|
+
<MetadataSidePanel
|
|
1857
|
+
currentCollection={currentCollection}
|
|
1858
|
+
onClose={this.closeMetadataSidePanel}
|
|
1859
|
+
metadataTemplate={metadataTemplate}
|
|
1860
|
+
selectedItemIds={selectedItemIds}
|
|
1861
|
+
/>
|
|
1813
1862
|
)}
|
|
1814
1863
|
</div>
|
|
1815
1864
|
{allowUpload && !!this.appElement ? (
|
|
@@ -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
|
|
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
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
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.
|
|
496
|
+
expect(screen.queryByRole('button', { name: 'Switch to Grid View' })).toBeInTheDocument();
|
|
431
497
|
});
|
|
432
498
|
|
|
433
499
|
await waitFor(() => {
|
|
434
|
-
expect(screen.
|
|
500
|
+
expect(screen.getByRole('row', { name: /Child 2/i })).toBeInTheDocument();
|
|
435
501
|
});
|
|
436
502
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
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
|
});
|