Skip to content

Commit c006cf8

Browse files
authored
Merge of #4174
2 parents 035cffb + d1d126e commit c006cf8

File tree

7 files changed

+164
-90
lines changed

7 files changed

+164
-90
lines changed

i18n/en-US.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1812,6 +1812,8 @@ boxui.shareMenu.shortcutOnly = Shortcut Only
18121812
boxui.shareMenu.viewAndDownload = View and Download
18131813
# Description of permissions granted to users who have access to the shared link
18141814
boxui.shareMenu.viewOnly = View Only
1815+
# Text for metadata button that will open the metadata side panel
1816+
boxui.subHeader.metadata = Metadata
18151817
# Error message for empty time formats. "HH:MM A" should be localized.
18161818
boxui.timeInput.emptyTimeError = Required field. Enter a time in the format HH:MM A.
18171819
# Error message for invalid time formats. "HH:MM A" should be localized.

src/elements/common/sub-header/SubHeader.tsx

Lines changed: 46 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import SubHeaderLeft from './SubHeaderLeft';
55
import SubHeaderRight from './SubHeaderRight';
66
import type { ViewMode } from '../flowTypes';
77
import type { View, Collection } from '../../../common/types/core';
8-
import { VIEW_MODE_LIST } from '../../../constants';
8+
import { VIEW_MODE_LIST, VIEW_METADATA } from '../../../constants';
9+
import { useFeatureEnabled } from '../feature-checking';
910

1011
import './SubHeader.scss';
1112

@@ -51,39 +52,49 @@ const SubHeader = ({
5152
rootName,
5253
view,
5354
viewMode = VIEW_MODE_LIST,
54-
}: SubHeaderProps) => (
55-
<PageHeader.Root className="be-sub-header" data-testid="be-sub-header" variant="inline">
56-
<PageHeader.StartElements>
57-
<SubHeaderLeft
58-
currentCollection={currentCollection}
59-
isSmall={isSmall}
60-
onItemClick={onItemClick}
61-
portalElement={portalElement}
62-
rootId={rootId}
63-
rootName={rootName}
64-
view={view}
65-
/>
66-
</PageHeader.StartElements>
67-
<PageHeader.EndElements>
68-
<SubHeaderRight
69-
canCreateNewFolder={canCreateNewFolder}
70-
canUpload={canUpload}
71-
currentCollection={currentCollection}
72-
gridColumnCount={gridColumnCount}
73-
gridMaxColumns={gridMaxColumns}
74-
gridMinColumns={gridMinColumns}
75-
maxGridColumnCountForWidth={maxGridColumnCountForWidth}
76-
onCreate={onCreate}
77-
onGridViewSliderChange={onGridViewSliderChange}
78-
onSortChange={onSortChange}
79-
onUpload={onUpload}
80-
onViewModeChange={onViewModeChange}
81-
portalElement={portalElement}
82-
view={view}
83-
viewMode={viewMode}
84-
/>
85-
</PageHeader.EndElements>
86-
</PageHeader.Root>
87-
);
55+
}: SubHeaderProps) => {
56+
const isMetadataViewV2Feature = useFeatureEnabled('contentExplorer.metadataViewV2');
57+
58+
if (view === VIEW_METADATA && !isMetadataViewV2Feature) {
59+
return null;
60+
}
61+
62+
return (
63+
<PageHeader.Root className="be-sub-header" data-testid="be-sub-header" variant="inline">
64+
<PageHeader.StartElements>
65+
{view !== VIEW_METADATA && !isMetadataViewV2Feature && (
66+
<SubHeaderLeft
67+
currentCollection={currentCollection}
68+
isSmall={isSmall}
69+
onItemClick={onItemClick}
70+
portalElement={portalElement}
71+
rootId={rootId}
72+
rootName={rootName}
73+
view={view}
74+
/>
75+
)}
76+
</PageHeader.StartElements>
77+
<PageHeader.EndElements>
78+
<SubHeaderRight
79+
canCreateNewFolder={canCreateNewFolder}
80+
canUpload={canUpload}
81+
currentCollection={currentCollection}
82+
gridColumnCount={gridColumnCount}
83+
gridMaxColumns={gridMaxColumns}
84+
gridMinColumns={gridMinColumns}
85+
maxGridColumnCountForWidth={maxGridColumnCountForWidth}
86+
onCreate={onCreate}
87+
onGridViewSliderChange={onGridViewSliderChange}
88+
onSortChange={onSortChange}
89+
onUpload={onUpload}
90+
onViewModeChange={onViewModeChange}
91+
portalElement={portalElement}
92+
view={view}
93+
viewMode={viewMode}
94+
/>
95+
</PageHeader.EndElements>
96+
</PageHeader.Root>
97+
);
98+
};
8899

89100
export default SubHeader;

src/elements/common/sub-header/SubHeaderRight.tsx

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
import * as React from 'react';
2+
import { Button } from '@box/blueprint-web';
3+
import { Pencil } from '@box/blueprint-web-assets/icons/Fill';
4+
import { useIntl } from 'react-intl';
25
import Sort from './Sort';
36
import Add from './Add';
47
import GridViewSlider from '../../../components/grid-view/GridViewSlider';
58
import ViewModeChangeButton from './ViewModeChangeButton';
6-
import { VIEW_FOLDER, VIEW_MODE_GRID } from '../../../constants';
9+
import { VIEW_FOLDER, VIEW_MODE_GRID, VIEW_METADATA } from '../../../constants';
10+
import { useFeatureEnabled } from '../feature-checking';
11+
712
import type { ViewMode } from '../flowTypes';
813
import type { SortBy, SortDirection, View, Collection } from '../../../common/types/core';
14+
15+
import messages from './messages';
16+
917
import './SubHeaderRight.scss';
1018

1119
export interface SubHeaderRightProps {
@@ -43,36 +51,49 @@ const SubHeaderRight = ({
4351
view,
4452
viewMode,
4553
}: SubHeaderRightProps) => {
54+
const { formatMessage } = useIntl();
55+
const isMetadataViewV2Feature = useFeatureEnabled('contentExplorer.metadataViewV2');
4656
const { items = [] }: Collection = currentCollection;
4757
const hasGridView: boolean = !!gridColumnCount;
4858
const hasItems: boolean = items.length > 0;
4959
const isFolder: boolean = view === VIEW_FOLDER;
5060
const showSort: boolean = isFolder && hasItems;
5161
const showAdd: boolean = (!!canUpload || !!canCreateNewFolder) && isFolder;
62+
const isMetadataView: boolean = view === VIEW_METADATA;
5263
return (
5364
<div className="be-sub-header-right">
54-
{hasItems && viewMode === VIEW_MODE_GRID && (
55-
<GridViewSlider
56-
columnCount={gridColumnCount}
57-
gridMaxColumns={gridMaxColumns}
58-
gridMinColumns={gridMinColumns}
59-
maxColumnCount={maxGridColumnCountForWidth}
60-
onChange={onGridViewSliderChange}
61-
/>
65+
{!isMetadataView && (
66+
<>
67+
{hasItems && viewMode === VIEW_MODE_GRID && (
68+
<GridViewSlider
69+
columnCount={gridColumnCount}
70+
gridMaxColumns={gridMaxColumns}
71+
gridMinColumns={gridMinColumns}
72+
maxColumnCount={maxGridColumnCountForWidth}
73+
onChange={onGridViewSliderChange}
74+
/>
75+
)}
76+
{hasItems && hasGridView && (
77+
<ViewModeChangeButton viewMode={viewMode} onViewModeChange={onViewModeChange} />
78+
)}
79+
{showSort && <Sort onSortChange={onSortChange} portalElement={portalElement} />}
80+
{showAdd && (
81+
<Add
82+
isDisabled={!isFolder}
83+
onCreate={onCreate}
84+
onUpload={onUpload}
85+
portalElement={portalElement}
86+
showCreate={canCreateNewFolder}
87+
showUpload={canUpload}
88+
/>
89+
)}
90+
</>
6291
)}
63-
{hasItems && hasGridView && (
64-
<ViewModeChangeButton viewMode={viewMode} onViewModeChange={onViewModeChange} />
65-
)}
66-
{showSort && <Sort onSortChange={onSortChange} portalElement={portalElement} />}
67-
{showAdd && (
68-
<Add
69-
isDisabled={!isFolder}
70-
onCreate={onCreate}
71-
onUpload={onUpload}
72-
portalElement={portalElement}
73-
showCreate={canCreateNewFolder}
74-
showUpload={canUpload}
75-
/>
92+
93+
{isMetadataView && isMetadataViewV2Feature && (
94+
<Button icon={Pencil} size="large" variant="primary">
95+
{formatMessage(messages.metadata)}
96+
</Button>
7697
)}
7798
</div>
7899
);
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { defineMessages } from 'react-intl';
2+
3+
const messages = defineMessages({
4+
metadata: {
5+
defaultMessage: 'Metadata',
6+
description: 'Text for metadata button that will open the metadata side panel',
7+
id: 'boxui.subHeader.metadata',
8+
},
9+
});
10+
11+
export default messages;

src/elements/content-explorer/Content.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,23 +65,21 @@ const Content = ({
6565
const isMetadataBasedView = view === VIEW_METADATA;
6666
const isListView = !isMetadataBasedView && viewMode === VIEW_MODE_LIST; // Folder view or Recents view
6767
const isGridView = !isMetadataBasedView && viewMode === VIEW_MODE_GRID; // Folder view or Recents view
68-
68+
const isMetadataViewV2Feature = isFeatureEnabled(features, 'contentExplorer.metadataViewV2');
6969
return (
7070
<div className="bce-content">
7171
{view === VIEW_ERROR || view === VIEW_SELECTED ? null : <ProgressBar percent={percentLoaded} />}
7272

7373
{isViewEmpty && <EmptyView view={view} isLoading={percentLoaded !== 100} />}
74-
{!isFeatureEnabled(features, 'contentExplorer.metadataViewV2') && !isViewEmpty && isMetadataBasedView && (
74+
{!isMetadataViewV2Feature && !isViewEmpty && isMetadataBasedView && (
7575
<MetadataBasedItemList
7676
currentCollection={currentCollection}
7777
fieldsToShow={fieldsToShow}
7878
onMetadataUpdate={onMetadataUpdate}
7979
{...rest}
8080
/>
8181
)}
82-
{isFeatureEnabled(features, 'contentExplorer.metadataViewV2') && !isViewEmpty && isMetadataBasedView && (
83-
<MetadataView />
84-
)}
82+
{isMetadataViewV2Feature && !isViewEmpty && isMetadataBasedView && <MetadataView />}
8583
{!isViewEmpty && isListView && (
8684
<ItemList
8785
items={items}

src/elements/content-explorer/ContentExplorer.tsx

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1649,32 +1649,30 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
16491649
<div id={this.id} className={styleClassName} ref={measureRef} data-testid="content-explorer">
16501650
<ThemingStyles selector={`#${this.id}`} theme={theme} />
16511651
<div className="be-app-element" onKeyDown={this.onKeyDown} tabIndex={0}>
1652-
{!isDefaultViewMetadata && (
1653-
<>
1654-
<Header view={view} logoUrl={logoUrl} onSearch={this.search} />
1655-
<SubHeader
1656-
view={view}
1657-
viewMode={viewMode}
1658-
rootId={rootFolderId}
1659-
isSmall={isSmall}
1660-
rootName={rootName}
1661-
currentCollection={currentCollection}
1662-
canUpload={allowUpload}
1663-
canCreateNewFolder={allowCreate}
1664-
gridColumnCount={gridColumnCount}
1665-
gridMaxColumns={GRID_VIEW_MAX_COLUMNS}
1666-
gridMinColumns={GRID_VIEW_MIN_COLUMNS}
1667-
maxGridColumnCountForWidth={maxGridColumnCount}
1668-
onUpload={this.upload}
1669-
onCreate={this.createFolder}
1670-
onGridViewSliderChange={this.onGridViewSliderChange}
1671-
onItemClick={this.fetchFolder}
1672-
onSortChange={this.sort}
1673-
onViewModeChange={this.changeViewMode}
1674-
portalElement={this.rootElement}
1675-
/>
1676-
</>
1677-
)}
1652+
{!isDefaultViewMetadata && <Header view={view} logoUrl={logoUrl} onSearch={this.search} />}
1653+
1654+
<SubHeader
1655+
view={view}
1656+
viewMode={viewMode}
1657+
rootId={rootFolderId}
1658+
isSmall={isSmall}
1659+
rootName={rootName}
1660+
currentCollection={currentCollection}
1661+
canUpload={allowUpload}
1662+
canCreateNewFolder={allowCreate}
1663+
gridColumnCount={gridColumnCount}
1664+
gridMaxColumns={GRID_VIEW_MAX_COLUMNS}
1665+
gridMinColumns={GRID_VIEW_MIN_COLUMNS}
1666+
maxGridColumnCountForWidth={maxGridColumnCount}
1667+
onUpload={this.upload}
1668+
onCreate={this.createFolder}
1669+
onGridViewSliderChange={this.onGridViewSliderChange}
1670+
onItemClick={this.fetchFolder}
1671+
onSortChange={this.sort}
1672+
onViewModeChange={this.changeViewMode}
1673+
portalElement={this.rootElement}
1674+
/>
1675+
16781676
<Content
16791677
canDelete={canDelete}
16801678
canDownload={canDownload}

src/elements/content-explorer/__tests__/ContentExplorer.test.tsx

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { ContentExplorerComponent as ContentExplorer, ContentExplorerProps } fro
55
import { mockRecentItems, mockRootFolder, mockRootFolderSharedLink } from '../../common/__mocks__/mockRootFolder';
66
import { mockMetadata, mockSchema } from '../../common/__mocks__/mockMetadata';
77
import mockSubFolder from '../../common/__mocks__/mockSubfolder';
8+
import { FeatureProvider } from '../../common/feature-checking';
89

910
jest.mock('../../../utils/Xhr', () => {
1011
return jest.fn().mockImplementation(() => {
@@ -71,8 +72,12 @@ jest.mock('../../common/preview-dialog/PreviewDialog', () => props => {
7172
describe('elements/content-explorer/ContentExplorer', () => {
7273
let rootElement: HTMLDivElement;
7374

74-
const renderComponent = (props: Partial<ContentExplorerProps> = {}) => {
75-
return render(<ContentExplorer defaultView="list" rootFolderId="69083462919" token="token" {...props} />);
75+
const renderComponent = ({ features, ...props }: Partial<ContentExplorerProps> = {}) => {
76+
return render(
77+
<FeatureProvider features={features}>
78+
<ContentExplorer defaultView="list" rootFolderId="69083462919" token="token" {...props} />
79+
</FeatureProvider>,
80+
);
7681
};
7782

7883
beforeEach(() => {
@@ -410,6 +415,34 @@ describe('elements/content-explorer/ContentExplorer', () => {
410415
expect(screen.getByText('Healthcare')).toBeInTheDocument();
411416
expect(screen.getByText('November 1, 2023')).toBeInTheDocument();
412417
});
418+
describe('Metadata View V2', () => {
419+
test('should render metadata view button', async () => {
420+
renderComponent({
421+
defaultView: 'metadata',
422+
features: {
423+
contentExplorer: {
424+
metadataViewV2: true,
425+
},
426+
},
427+
});
428+
429+
// two separate promises need to be resolved before the component is ready
430+
await waitFor(() => {
431+
expect(screen.getByText('Please wait while the items load...')).toBeInTheDocument();
432+
});
433+
434+
await waitFor(() => {
435+
expect(screen.getByTestId('content-explorer')).toBeInTheDocument();
436+
});
437+
438+
expect(screen.queryByRole('searchbox', { name: 'Search files and folders' })).not.toBeInTheDocument();
439+
expect(screen.queryByRole('button', { name: 'Preview Test Folder' })).not.toBeInTheDocument();
440+
expect(screen.queryByRole('button', { name: 'Switch to Grid View' })).not.toBeInTheDocument();
441+
expect(screen.queryByRole('button', { name: 'Sort' })).not.toBeInTheDocument();
442+
expect(screen.queryByRole('button', { name: 'Add' })).not.toBeInTheDocument();
443+
expect(screen.getByRole('button', { name: 'Metadata' })).toBeInTheDocument();
444+
});
445+
});
413446
});
414447

415448
describe('Preview', () => {

0 commit comments

Comments
 (0)