Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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;
onMetadataSidePanelToggle?: () => void;
onUpload: () => void;
onViewModeChange?: (viewMode: ViewMode) => void;
portalElement?: HTMLElement;
Expand All @@ -53,6 +54,7 @@ const SubHeader = ({
onCreate,
onItemClick,
onSortChange,
onMetadataSidePanelToggle,
onUpload,
onViewModeChange,
portalElement,
Expand Down Expand Up @@ -109,9 +111,11 @@ const SubHeader = ({
onCreate={onCreate}
onGridViewSliderChange={onGridViewSliderChange}
onSortChange={onSortChange}
onMetadataSidePanelToggle={onMetadataSidePanelToggle}
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
10 changes: 8 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;
onMetadataSidePanelToggle?: () => 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,
onMetadataSidePanelToggle,
onUpload,
onViewModeChange,
portalElement,
selectedItemIds,
view,
viewMode,
}: SubHeaderRightProps) => {
Expand All @@ -60,6 +65,7 @@ const SubHeaderRight = ({
const showSort: boolean = isFolder && hasItems;
const showAdd: boolean = (!!canUpload || !!canCreateNewFolder) && isFolder;
const isMetadataView: boolean = view === VIEW_METADATA;
const hasSelectedItems: boolean = !!(selectedItemIds && (selectedItemIds === 'all' || selectedItemIds.size > 0));
return (
<div className="be-sub-header-right">
{!isMetadataView && (
Expand Down Expand Up @@ -90,8 +96,8 @@ const SubHeaderRight = ({
</>
)}

{isMetadataView && isMetadataViewV2Feature && (
<Button icon={Pencil} size="large" variant="primary">
{isMetadataView && isMetadataViewV2Feature && hasSelectedItems && (
<Button icon={Pencil} size="large" variant="primary" onClick={onMetadataSidePanelToggle}>
{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}
*/
onMetadataSidePanelToggle = () => {
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}
onMetadataSidePanelToggle={this.onMetadataSidePanelToggle}
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