Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/elements/common/sub-header/SubHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface SubHeaderProps {
onGridViewSliderChange?: (newSliderValue: number) => void;
onItemClick: (id: string | null, triggerNavigationEvent: boolean | null) => void;
onSortChange: (sortBy: string, sortDirection: string) => void;
onToggleMetadataSidePanel?: () => void;
onUpload: () => void;
onViewModeChange?: (viewMode: ViewMode) => void;
portalElement?: HTMLElement;
Expand All @@ -53,6 +54,7 @@ const SubHeader = ({
onCreate,
onItemClick,
onSortChange,
onToggleMetadataSidePanel,
onUpload,
onViewModeChange,
portalElement,
Expand Down Expand Up @@ -109,9 +111,11 @@ const SubHeader = ({
onCreate={onCreate}
onGridViewSliderChange={onGridViewSliderChange}
onSortChange={onSortChange}
onToggleMetadataSidePanel={onToggleMetadataSidePanel}
onUpload={onUpload}
onViewModeChange={onViewModeChange}
portalElement={portalElement}
selectedItemIds={selectedItemIds}
view={view}
viewMode={viewMode}
/>
Expand Down
25 changes: 3 additions & 22 deletions src/elements/common/sub-header/SubHeaderLeftV2.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React, { useMemo } from 'react';
import * as React from 'react';
import { useIntl } from 'react-intl';
import { XMark } from '@box/blueprint-web-assets/icons/Fill/index';
import { IconButton, PageHeader, Text } from '@box/blueprint-web';
import type { Selection } from 'react-aria-components';
import { useSelectedItemText } from '../../content-explorer/utils';
import type { Collection } from '../../../common/types/core';
import messages from '../messages';

Expand All @@ -20,27 +21,7 @@ const SubHeaderLeftV2 = (props: SubHeaderLeftV2Props) => {
const { currentCollection, onClearSelectedItemIds, rootName, selectedItemIds, title } = props;
const { formatMessage } = useIntl();

// Generate selected item text based on selected keys
const selectedItemText: string = useMemo(() => {
const selectedCount = selectedItemIds === 'all' ? currentCollection.items.length : selectedItemIds.size;

if (selectedCount === 0) {
return '';
}

// Case 1: Single selected item - show item name
if (selectedCount === 1) {
const selectedKey =
selectedItemIds === 'all' ? currentCollection.items[0].id : selectedItemIds.values().next().value;
const selectedItem = currentCollection.items.find(item => item.id === selectedKey);
return selectedItem?.name ?? '';
}
// Case 2: Multiple selected items - show count
if (selectedCount > 1) {
return formatMessage(messages.numFilesSelected, { numSelected: selectedCount });
}
return '';
}, [currentCollection.items, formatMessage, selectedItemIds]);
const selectedItemText = useSelectedItemText(currentCollection, selectedItemIds);

// Case 1 and 2: selected item text with X button
if (selectedItemText) {
Expand Down
13 changes: 11 additions & 2 deletions src/elements/common/sub-header/SubHeaderRight.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as React from 'react';
import { Button } from '@box/blueprint-web';
import { Pencil } from '@box/blueprint-web-assets/icons/Fill';
import { useIntl } from 'react-intl';
import type { Selection } from 'react-aria-components';
import Sort from './Sort';
import Add from './Add';
import GridViewSlider from '../../../components/grid-view/GridViewSlider';
Expand All @@ -27,9 +28,11 @@ export interface SubHeaderRightProps {
onCreate: () => void;
onGridViewSliderChange: (newSliderValue: number) => void;
onSortChange: (sortBy: SortBy, sortDirection: SortDirection) => void;
onToggleMetadataSidePanel?: () => void;
onUpload: () => void;
onViewModeChange?: (viewMode: ViewMode) => void;
portalElement?: HTMLElement;
selectedItemIds?: Selection;
view: View;
viewMode: ViewMode;
}
Expand All @@ -45,9 +48,11 @@ const SubHeaderRight = ({
onCreate,
onGridViewSliderChange,
onSortChange,
onToggleMetadataSidePanel,
onUpload,
onViewModeChange,
portalElement,
selectedItemIds,
view,
viewMode,
}: SubHeaderRightProps) => {
Expand All @@ -60,6 +65,10 @@ const SubHeaderRight = ({
const showSort: boolean = isFolder && hasItems;
const showAdd: boolean = (!!canUpload || !!canCreateNewFolder) && isFolder;
const isMetadataView: boolean = view === VIEW_METADATA;
const isMetadataViewV2ItemSelected: boolean = !!(
selectedItemIds &&
(selectedItemIds === 'all' || selectedItemIds.size > 0)
);
return (
<div className="be-sub-header-right">
{!isMetadataView && (
Expand Down Expand Up @@ -90,8 +99,8 @@ const SubHeaderRight = ({
</>
)}

{isMetadataView && isMetadataViewV2Feature && (
<Button icon={Pencil} size="large" variant="primary">
{isMetadataView && isMetadataViewV2Feature && isMetadataViewV2ItemSelected && (
<Button icon={Pencil} size="large" variant="primary" onClick={onToggleMetadataSidePanel}>
{formatMessage(messages.metadata)}
</Button>
)}
Expand Down
12 changes: 12 additions & 0 deletions src/elements/content-explorer/ContentExplorer.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,17 @@
.bcpr {
z-index: 1; // Prevents overlay issues with list-item when a file is previewed
}

.be-app-element {
flex-direction: row;
gap: var(--space-4);
}

.bce-ContentExplorer-main {
display: flex;
flex: 1;
flex-direction: column;
min-width: 0;
}
}
}
191 changes: 120 additions & 71 deletions src/elements/content-explorer/ContentExplorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import ThemingStyles from '../common/theming';
import API from '../../api';
import MetadataQueryAPIHelperV2 from './MetadataQueryAPIHelper';
import MetadataQueryAPIHelper from '../../features/metadata-based-view/MetadataQueryAPIHelper';
import MetadataSidePanel from './MetadataSidePanel';
import Footer from './Footer';
import PreviewDialog from '../common/preview-dialog/PreviewDialog';
import ShareDialog from './ShareDialog';
Expand Down Expand Up @@ -169,6 +170,7 @@ type State = {
isCreateFolderModalOpen: boolean;
isDeleteModalOpen: boolean;
isLoading: boolean;
isMetadataSidePanelOpen: boolean;
isPreviewModalOpen: boolean;
isRenameModalOpen: boolean;
isShareModalOpen: boolean;
Expand Down Expand Up @@ -294,6 +296,7 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
isCreateFolderModalOpen: false,
isDeleteModalOpen: false,
isLoading: false,
isMetadataSidePanelOpen: false,
isPreviewModalOpen: false,
isRenameModalOpen: false,
isShareModalOpen: false,
Expand Down Expand Up @@ -1562,7 +1565,11 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
selectedKeys: selectedItemIds,
onSelectionChange: (ids: Selection) => {
onSelectionChange?.(ids);
this.setState({ selectedItemIds: ids });
const isSelectionEmpty = ids !== 'all' && ids.size === 0;
this.setState({
selectedItemIds: ids,
...(isSelectionEmpty && { isMetadataSidePanelOpen: false }),
});
},
},
};
Expand Down Expand Up @@ -1644,7 +1651,32 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
};

clearSelectedItemIds = () => {
this.setState({ selectedItemIds: new Set() });
this.setState({
selectedItemIds: new Set(),
isMetadataSidePanelOpen: false,
});
};

/**
* Toggle metadata side panel visibility
*
* @private
* @return {void}
*/
toggleMetadataSidePanel = () => {
this.setState(prevState => ({
isMetadataSidePanelOpen: !prevState.isMetadataSidePanelOpen,
}));
};

/**
* Close metadata side panel
*
* @private
* @return {void}
*/
closeMetadataSidePanel = () => {
this.setState({ isMetadataSidePanelOpen: false });
};

/**
Expand Down Expand Up @@ -1706,6 +1738,7 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
isCreateFolderModalOpen,
isDeleteModalOpen,
isLoading,
isMetadataSidePanelOpen,
isPreviewModalOpen,
isRenameModalOpen,
isShareModalOpen,
Expand All @@ -1714,6 +1747,7 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
metadataTemplate,
rootName,
selected,
selectedItemIds,
view,
}: State = this.state;

Expand All @@ -1723,6 +1757,7 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
const allowUpload: boolean = canUpload && !!can_upload;
const allowCreate: boolean = canCreateNewFolder && !!can_upload;
const isDefaultViewMetadata: boolean = defaultView === DEFAULT_VIEW_METADATA;
const isMetadataViewV2Feature = isFeatureEnabled(features, 'contentExplorer.metadataViewV2');
const isErrorView: boolean = view === VIEW_ERROR;

const viewMode = this.getViewMode();
Expand All @@ -1741,75 +1776,89 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
<div id={this.id} className={styleClassName} ref={measureRef} data-testid="content-explorer">
<ThemingStyles selector={`#${this.id}`} theme={theme} />
<div className="be-app-element" onKeyDown={this.onKeyDown} tabIndex={0}>
{!isDefaultViewMetadata && <Header view={view} logoUrl={logoUrl} onSearch={this.search} />}

<SubHeader
view={view}
viewMode={viewMode}
rootId={rootFolderId}
isSmall={isSmall}
rootName={rootName}
currentCollection={currentCollection}
canUpload={allowUpload}
canCreateNewFolder={allowCreate}
gridColumnCount={gridColumnCount}
gridMaxColumns={GRID_VIEW_MAX_COLUMNS}
gridMinColumns={GRID_VIEW_MIN_COLUMNS}
maxGridColumnCountForWidth={maxGridColumnCount}
onUpload={this.upload}
onClearSelectedItemIds={this.clearSelectedItemIds}
onCreate={this.createFolder}
onGridViewSliderChange={this.onGridViewSliderChange}
onItemClick={this.fetchFolder}
onSortChange={this.sort}
onViewModeChange={this.changeViewMode}
portalElement={this.rootElement}
selectedItemIds={this.state.selectedItemIds}
title={title}
/>

<Content
canDelete={canDelete}
canDownload={canDownload}
canPreview={canPreview}
canRename={canRename}
canShare={canShare}
currentCollection={currentCollection}
features={features}
gridColumnCount={Math.min(gridColumnCount, maxGridColumnCount)}
isMedium={isMedium}
isSmall={isSmall}
isTouch={isTouch}
itemActions={itemActions}
fieldsToShow={fieldsToShow}
metadataTemplate={metadataTemplate}
metadataViewProps={metadataViewProps}
onItemClick={this.onItemClick}
onItemDelete={this.delete}
onItemDownload={this.download}
onItemPreview={this.preview}
onItemRename={this.rename}
onItemSelect={this.select}
onItemShare={this.share}
onMetadataUpdate={this.updateMetadata}
onSortChange={this.sort}
portalElement={this.rootElement}
view={view}
viewMode={viewMode}
/>
{!isErrorView && (
<Footer>
<Pagination
hasNextMarker={hasNextMarker}
hasPrevMarker={hasPreviousMarker}
isSmall={isSmall}
offset={offset}
onOffsetChange={this.paginate}
pageSize={currentPageSize}
totalCount={totalCount}
onMarkerBasedPageChange={this.markerBasedPaginate}
/>
</Footer>
<div className="bce-ContentExplorer-main">
{!isDefaultViewMetadata && (
<Header view={view} logoUrl={logoUrl} onSearch={this.search} />
)}

<SubHeader
view={view}
viewMode={viewMode}
rootId={rootFolderId}
isSmall={isSmall}
rootName={rootName}
currentCollection={currentCollection}
canUpload={allowUpload}
canCreateNewFolder={allowCreate}
gridColumnCount={gridColumnCount}
gridMaxColumns={GRID_VIEW_MAX_COLUMNS}
gridMinColumns={GRID_VIEW_MIN_COLUMNS}
maxGridColumnCountForWidth={maxGridColumnCount}
onUpload={this.upload}
onClearSelectedItemIds={this.clearSelectedItemIds}
onCreate={this.createFolder}
onGridViewSliderChange={this.onGridViewSliderChange}
onItemClick={this.fetchFolder}
onSortChange={this.sort}
onToggleMetadataSidePanel={this.toggleMetadataSidePanel}
onViewModeChange={this.changeViewMode}
portalElement={this.rootElement}
selectedItemIds={selectedItemIds}
title={title}
/>

<Content
canDelete={canDelete}
canDownload={canDownload}
canPreview={canPreview}
canRename={canRename}
canShare={canShare}
currentCollection={currentCollection}
features={features}
gridColumnCount={Math.min(gridColumnCount, maxGridColumnCount)}
isMedium={isMedium}
isSmall={isSmall}
isTouch={isTouch}
itemActions={itemActions}
fieldsToShow={fieldsToShow}
metadataTemplate={metadataTemplate}
metadataViewProps={metadataViewProps}
onItemClick={this.onItemClick}
onItemDelete={this.delete}
onItemDownload={this.download}
onItemPreview={this.preview}
onItemRename={this.rename}
onItemSelect={this.select}
onItemShare={this.share}
onMetadataUpdate={this.updateMetadata}
onSortChange={this.sort}
portalElement={this.rootElement}
view={view}
viewMode={viewMode}
/>

{!isErrorView && (
<Footer>
<Pagination
hasNextMarker={hasNextMarker}
hasPrevMarker={hasPreviousMarker}
isSmall={isSmall}
offset={offset}
onOffsetChange={this.paginate}
pageSize={currentPageSize}
totalCount={totalCount}
onMarkerBasedPageChange={this.markerBasedPaginate}
/>
</Footer>
)}
</div>
{isDefaultViewMetadata && isMetadataViewV2Feature && isMetadataSidePanelOpen && (
<MetadataSidePanel
currentCollection={currentCollection}
onClose={this.closeMetadataSidePanel}
metadataTemplate={metadataTemplate}
selectedItemIds={selectedItemIds}
/>
)}
</div>
{allowUpload && !!this.appElement ? (
Expand Down
Loading