diff --git a/packages/e2e/features/ui/components/storage/storage-browser/download.feature b/packages/e2e/features/ui/components/storage/storage-browser/download.feature index 74d7c34673e..ee11594c058 100644 --- a/packages/e2e/features/ui/components/storage/storage-browser/download.feature +++ b/packages/e2e/features/ui/components/storage/storage-browser/download.feature @@ -18,4 +18,4 @@ Feature: Download on Storage Browser Then I type my password Then I click the "Sign in" button When I click the first button containing "public" - Then I see no download for folder "DO_NOT_DELETE/" + Then I see no download for folder "DO_NOT_DELETE" diff --git a/packages/e2e/features/ui/components/storage/storage-browser/navigate-locations.feature b/packages/e2e/features/ui/components/storage/storage-browser/navigate-locations.feature index 03f0566cfe7..31811d1f769 100644 --- a/packages/e2e/features/ui/components/storage/storage-browser/navigate-locations.feature +++ b/packages/e2e/features/ui/components/storage/storage-browser/navigate-locations.feature @@ -20,10 +20,10 @@ Feature: Storage Browser navigate breadcrumbs Then I type my password Then I click the "Sign in" button When I click the first button containing "public" - Then I see the "DO_NOT_DELETE/" button - When I click the "DO_NOT_DELETE/" button - Then I see "DONT_DELETE_SUB/" - When I click the "DONT_DELETE_SUB/" button + Then I see the "DO_NOT_DELETE" button + When I click the "DO_NOT_DELETE" button + Then I see "DONT_DELETE_SUB" + When I click the "DONT_DELETE_SUB" button Then I see "DO_NOT_DELETE" Then I see "DONT_DELETE_SUB" @@ -33,10 +33,10 @@ Feature: Storage Browser navigate breadcrumbs Then I type my password Then I click the "Sign in" button When I click the first button containing "public" - Then I see the "DO_NOT_DELETE/" button - When I click the "DO_NOT_DELETE/" button - Then I see the "DONT_DELETE_SUB/" button - When I click the "DONT_DELETE_SUB/" button + Then I see the "DO_NOT_DELETE" button + When I click the "DO_NOT_DELETE" button + Then I see the "DONT_DELETE_SUB" button + When I click the "DONT_DELETE_SUB" button Then I see "DO_NOT_DELETE" When I click the "DO_NOT_DELETE" button - Then I see "DONT_DELETE_SUB/" + Then I see "DONT_DELETE_SUB" diff --git a/packages/e2e/features/ui/components/storage/storage-browser/search-locations.feature b/packages/e2e/features/ui/components/storage/storage-browser/search-locations.feature index 00b1de0fa87..e59d2fb123a 100644 --- a/packages/e2e/features/ui/components/storage/storage-browser/search-locations.feature +++ b/packages/e2e/features/ui/components/storage/storage-browser/search-locations.feature @@ -26,12 +26,12 @@ Feature: Search with Storage Browser When I click the first button containing "public" When I see input with placeholder "Search current folder" and type "DELETE" Then I click the "Search" button - Then I do not see the button containing "DO_NOT_DELETE/DONT_DELETE_SUB" + Then I do not see the button containing "DONT_DELETE_SUB" When I click the button containing "Clear search" When I click the "Include Subfolders" checkbox When I see input with placeholder "Search current folder" and type "DELETE" Then I click the "Search" button - Then I see "DO_NOT_DELETE/DONT_DELETE_SUB" + Then I see "DONT_DELETE_SUB" @react Scenario: Search with no matching results diff --git a/packages/react-storage/src/components/StorageBrowser/actions/handlers/__tests__/utils.spec.ts b/packages/react-storage/src/components/StorageBrowser/actions/handlers/__tests__/utils.spec.ts index f9cec8851ae..dc95db4ce64 100644 --- a/packages/react-storage/src/components/StorageBrowser/actions/handlers/__tests__/utils.spec.ts +++ b/packages/react-storage/src/components/StorageBrowser/actions/handlers/__tests__/utils.spec.ts @@ -5,6 +5,8 @@ import { shouldExcludeLocation, getFileKey, parseAccessGrantLocation, + getFolderPath, + getFolderName, } from '../utils'; describe('parseLocationAccess', () => { @@ -109,6 +111,56 @@ describe('getFileKey', () => { }); }); +describe('folder functions', () => { + describe('getFolderPath', () => { + it('should return the parent folder path for a given folder key', () => { + expect(getFolderPath('parent-folder/sub-folder/')).toBe('parent-folder/'); + }); + + it('should handle root-level folder correctly', () => { + expect(getFolderPath('root/')).toBe(''); + }); + + it('should return an empty string for an empty key', () => { + expect(getFolderPath('')).toBe(''); + }); + + it('should handle nested folder paths correctly', () => { + expect(getFolderPath('grandparent/parent/child/')).toBe( + 'grandparent/parent/' + ); + }); + + it('should handle multiple slashes', () => { + expect(getFolderPath('grandparent/parent///child/')).toBe( + 'grandparent/parent///' + ); + }); + }); + + describe('getFolderName', () => { + it('should return the folder name for a given folder key', () => { + expect(getFolderName('parent-folder/sub-folder/')).toBe('sub-folder'); + }); + + it('should handle root-level folder correctly', () => { + expect(getFolderName('root/')).toBe('root'); + }); + + it('should return an empty string for an empty key', () => { + expect(getFolderName('')).toBe(''); + }); + + it('should handle nested folder names correctly', () => { + expect(getFolderName('grandparent/parent/child/')).toBe('child'); + }); + + it('should handle multiple slashes', () => { + expect(getFolderName('grandparent///parent/child/')).toBe('child'); + }); + }); +}); + describe('shouldExcludeLocation', () => { const location: LocationData = { bucket: 'bucket', diff --git a/packages/react-storage/src/components/StorageBrowser/actions/handlers/utils.ts b/packages/react-storage/src/components/StorageBrowser/actions/handlers/utils.ts index 99610f61541..fa097a93c50 100644 --- a/packages/react-storage/src/components/StorageBrowser/actions/handlers/utils.ts +++ b/packages/react-storage/src/components/StorageBrowser/actions/handlers/utils.ts @@ -141,6 +141,15 @@ export const getFilteredLocations = ( export const getFileKey = (key: string): string => key.slice(key.lastIndexOf('/') + 1, key.length); +export const getFilePath = (key: string): string => + key.slice(0, key.lastIndexOf('/') + 1); + +export const getFolderPath = (key: string): string => + getFilePath(key.slice(0, -1)); + +export const getFolderName = (key: string): string => + getFileKey(key.slice(0, -1)); + export const createFileDataItem = (data: FileData): FileDataItem => ({ ...data, fileKey: getFileKey(data.key), diff --git a/packages/react-storage/src/components/StorageBrowser/actions/useAction/createEnhancedListHandler.ts b/packages/react-storage/src/components/StorageBrowser/actions/useAction/createEnhancedListHandler.ts index abb909eec2b..8e342de17ca 100644 --- a/packages/react-storage/src/components/StorageBrowser/actions/useAction/createEnhancedListHandler.ts +++ b/packages/react-storage/src/components/StorageBrowser/actions/useAction/createEnhancedListHandler.ts @@ -33,12 +33,13 @@ export interface EnhancedListHandlerOptions search?: SearchOptions; } -export interface SearchOutput { +export interface SearchOutput { hasExhaustedSearch: boolean; + options: SearchOptions; } export interface EnhancedListHandlerOutput extends ListHandlerOutput { - search?: SearchOutput; + search?: SearchOutput; } export interface EnhancedListHandlerInput @@ -198,6 +199,7 @@ export const createEnhancedListHandler = ( search: { // search limit reached but we still have a next token hasExhaustedSearch: !!nextNextToken, + options: search, }, nextToken: undefined, }; diff --git a/packages/react-storage/src/components/StorageBrowser/views/LocationActionView/__tests__/__snapshots__/getActionViewTableData.spec.ts.snap b/packages/react-storage/src/components/StorageBrowser/views/LocationActionView/__tests__/__snapshots__/getActionViewTableData.spec.ts.snap index fe90dc9d17f..0536def19c6 100644 --- a/packages/react-storage/src/components/StorageBrowser/views/LocationActionView/__tests__/__snapshots__/getActionViewTableData.spec.ts.snap +++ b/packages/react-storage/src/components/StorageBrowser/views/LocationActionView/__tests__/__snapshots__/getActionViewTableData.spec.ts.snap @@ -14,7 +14,7 @@ exports[`getActionViewTableData should handle tasks with prefix keys 1`] = ` }, { "content": { - "text": "/", + "text": "folder/subfolder/", }, "key": "folder-1", "type": "text", @@ -66,7 +66,7 @@ exports[`getActionViewTableData should handle tasks with prefix keys 1`] = ` }, { "content": { - "text": "/", + "text": "/root/", }, "key": "folder-2", "type": "text", @@ -180,7 +180,7 @@ exports[`getActionViewTableData should return correct table data for all task st }, { "content": { - "text": "/", + "text": "some-prefix/", }, "key": "folder-1", "type": "text", @@ -232,7 +232,7 @@ exports[`getActionViewTableData should return correct table data for all task st }, { "content": { - "text": "/", + "text": "some-prefix/", }, "key": "folder-2", "type": "text", @@ -284,7 +284,7 @@ exports[`getActionViewTableData should return correct table data for all task st }, { "content": { - "text": "/", + "text": "some-prefix/", }, "key": "folder-3", "type": "text", @@ -336,7 +336,7 @@ exports[`getActionViewTableData should return correct table data for all task st }, { "content": { - "text": "/", + "text": "some-prefix/", }, "key": "folder-4", "type": "text", @@ -388,7 +388,7 @@ exports[`getActionViewTableData should return correct table data for all task st }, { "content": { - "text": "/", + "text": "some-prefix/", }, "key": "folder-5", "type": "text", diff --git a/packages/react-storage/src/components/StorageBrowser/views/LocationActionView/getActionViewTableData.ts b/packages/react-storage/src/components/StorageBrowser/views/LocationActionView/getActionViewTableData.ts index 7d727005b2d..4088752474b 100644 --- a/packages/react-storage/src/components/StorageBrowser/views/LocationActionView/getActionViewTableData.ts +++ b/packages/react-storage/src/components/StorageBrowser/views/LocationActionView/getActionViewTableData.ts @@ -10,6 +10,7 @@ import { getPercentValue } from './getPercentValue'; import { getDefaultActionViewHeaders } from './getDefaultActionViewHeaders'; import { ActionViewHeaders } from './types'; import { DefaultActionViewDisplayText } from '../../displayText/types'; +import { getFilePath } from '../../actions/handlers'; const getTaskStatusDisplayLabel = ({ status, @@ -110,8 +111,12 @@ export const getActionViewTableData = ({ }; } case 'folder': { - if (locationKey) { - return { key, type: 'text', content: { text: locationKey } }; + if (isFileDataItem(data)) { + return { + key, + type: 'text', + content: { text: getFilePath(data.key) }, + }; } if (isFileItem(data)) { @@ -130,6 +135,10 @@ export const getActionViewTableData = ({ }; } + if (locationKey) { + return { key, type: 'text', content: { text: locationKey } }; + } + return { key, type: 'text', content: { text: '/' } }; } case 'type': { diff --git a/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/LocationDetailViewProvider.tsx b/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/LocationDetailViewProvider.tsx index c165b57e219..429e480fe09 100644 --- a/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/LocationDetailViewProvider.tsx +++ b/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/LocationDetailViewProvider.tsx @@ -43,7 +43,7 @@ export function LocationDetailViewProvider({ message, downloadErrorMessage, searchQuery, - hasExhaustedSearch, + searchInfo, onActionSelect, onDropFiles, onRefresh, @@ -64,6 +64,9 @@ export function LocationDetailViewProvider({ label: getActionListItemLabel(item.label), })); + const { hasExhaustedSearch = false, options: searchOptions } = + searchInfo ?? {}; + const showPaths = Boolean(searchOptions?.groupBy); const messageControlContent = getListItemsResultMessage({ isLoading, items: pageItems, @@ -102,6 +105,7 @@ export function LocationDetailViewProvider({ fileDataItems, getDateDisplayValue, hasFiles, + showPaths, pageItems, selectFileLabel, selectAllFilesLabel, diff --git a/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/__tests__/LocationDetailView.spec.tsx b/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/__tests__/LocationDetailView.spec.tsx index f84e98a66c4..732780c4612 100644 --- a/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/__tests__/LocationDetailView.spec.tsx +++ b/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/__tests__/LocationDetailView.spec.tsx @@ -12,6 +12,7 @@ import { ActionInputConfig, ListLocationItemsHandlerOutput, LocationData, + LocationItemData, } from '../../../actions'; import { useProcessTasks } from '../../../tasks/useProcessTasks'; import { INITIAL_STATUS_COUNTS } from '../../../tasks'; @@ -93,7 +94,7 @@ const mockListItemsAction = ({ isLoading?: boolean; message?: string; result: any[]; - search?: SearchOutput; + search?: SearchOutput; nextToken?: string; }) => { jest.spyOn(AmplifyReactCore, 'useDataState').mockReturnValue([ @@ -326,7 +327,10 @@ describe('LocationDetailView', () => { ]); mockListItemsAction({ result: testResult, - search: { hasExhaustedSearch: true }, + search: { + hasExhaustedSearch: true, + options: { filterBy: 'key', query: 'boo' }, + }, }); const { getByPlaceholderText, getByText } = render(); diff --git a/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/__tests__/getFileRowContent.spec.ts b/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/__tests__/getFileRowContent.spec.ts index fc7e932453d..3e7e249e97b 100644 --- a/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/__tests__/getFileRowContent.spec.ts +++ b/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/__tests__/getFileRowContent.spec.ts @@ -1,5 +1,6 @@ import { LocationPermissions } from '../../../../actions'; import { getFileRowContent } from '../getFileRowContent'; +import { LOCATION_DETAIL_VIEW_HEADERS } from '../constants'; describe('getFileRowContent', () => { const location = { @@ -20,13 +21,12 @@ describe('getFileRowContent', () => { size: 1, type: 'FILE', } as const; - const itemLocationKey = `${location.current.prefix}${location.path}`; it('should return file row content as expected', () => { expect( getFileRowContent({ + headers: LOCATION_DETAIL_VIEW_HEADERS, permissions: location.current.permissions, - itemLocationKey, isSelected: false, getDateDisplayValue: (date) => date.toLocaleString(), lastModified: fileItem.lastModified, @@ -76,7 +76,7 @@ describe('getFileRowContent', () => { it('should not render download button if location permission does not support download', () => { const row = getFileRowContent({ permissions: ['list', 'write'], - itemLocationKey, + headers: LOCATION_DETAIL_VIEW_HEADERS, isSelected: false, lastModified: fileItem.lastModified, rowId: 'row-id', diff --git a/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/__tests__/getFolderRowContent.spec.ts b/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/__tests__/getFolderRowContent.spec.ts index be51b769fa9..85ea3d8dfe0 100644 --- a/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/__tests__/getFolderRowContent.spec.ts +++ b/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/__tests__/getFolderRowContent.spec.ts @@ -1,4 +1,5 @@ import { getFolderRowContent } from '../getFolderRowContent'; +import { LOCATION_DETAIL_VIEW_HEADERS } from '../constants'; describe('getFolderRowContent', () => { const folderItem = { @@ -10,7 +11,8 @@ describe('getFolderRowContent', () => { it('should return folder row content as expected', () => { expect( getFolderRowContent({ - itemSubPath: folderItem.key, + headers: LOCATION_DETAIL_VIEW_HEADERS, + rowKey: folderItem.key, rowId: 'row-id', onNavigate: jest.fn(), }) @@ -19,7 +21,7 @@ describe('getFolderRowContent', () => { expect.objectContaining({ type: 'text', content: { text: '' } }), expect.objectContaining({ type: 'button', - content: expect.objectContaining({ label: folderItem.key }), + content: expect.objectContaining({ label: 'path' }), }), expect.objectContaining({ type: 'text', content: { text: 'Folder' } }), expect.objectContaining({ type: 'text', content: { text: '' } }), diff --git a/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/__tests__/getLocationDetailViewTableData.spec.ts b/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/__tests__/getLocationDetailViewTableData.spec.ts index d655a524d59..519505101b8 100644 --- a/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/__tests__/getLocationDetailViewTableData.spec.ts +++ b/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/__tests__/getLocationDetailViewTableData.spec.ts @@ -94,6 +94,7 @@ describe('getLocationDetailViewTableData', () => { areAllFilesSelected: false, location, hasFiles: true, + showPaths: false, pageItems: [folderItem, folderItem, fileItem, fileItem, fileItem], onDownload: mockOnDownload, getDateDisplayValue: (date: Date) => date.toLocaleString(), @@ -128,6 +129,7 @@ describe('getLocationDetailViewTableData', () => { areAllFilesSelected: false, location, hasFiles: true, + showPaths: false, pageItems: [folderItem, fileItem], selectAllFilesLabel: 'Select all files', selectFileLabel: 'Select file', @@ -150,6 +152,7 @@ describe('getLocationDetailViewTableData', () => { areAllFilesSelected: false, location, hasFiles: true, + showPaths: false, pageItems: [fileItem], selectAllFilesLabel: 'Select all files', selectFileLabel: 'Select file', @@ -172,6 +175,7 @@ describe('getLocationDetailViewTableData', () => { areAllFilesSelected: false, location, hasFiles: true, + showPaths: false, pageItems: [fileItem], selectAllFilesLabel: 'Select all files', selectFileLabel: 'Select file', @@ -194,6 +198,7 @@ describe('getLocationDetailViewTableData', () => { areAllFilesSelected: false, location, hasFiles: true, + showPaths: false, pageItems: [folderItem], selectAllFilesLabel: 'Select all files', selectFileLabel: 'Select file', @@ -213,4 +218,43 @@ describe('getLocationDetailViewTableData', () => { `${location.path}folder/` ); }); + + describe('has search results', () => { + it('should return table data with path', () => { + expect( + getLocationDetailViewTableData({ + areAllFilesSelected: false, + location, + hasFiles: true, + showPaths: true, + pageItems: [folderItem, folderItem, fileItem, fileItem, fileItem], + onDownload: mockOnDownload, + getDateDisplayValue: (date: Date) => date.toLocaleString(), + selectAllFilesLabel: 'Select all files', + selectFileLabel: 'Select file', + onNavigate: mockOnNavigate, + onSelect: mockOnSelect, + onSelectAll: mockOnSelectAll, + }) + ).toStrictEqual( + expect.objectContaining({ + headers: [ + expect.objectContaining({ + type: 'checkbox', + content: expect.objectContaining({ checked: false }), + }), + expect.objectContaining({ content: { label: 'Name' } }), + expect.objectContaining({ content: { label: 'Path' } }), + expect.objectContaining({ content: { label: 'Type' } }), + expect.objectContaining({ content: { label: 'Last modified' } }), + expect.objectContaining({ content: { label: 'Size' } }), + expect.objectContaining({ content: { text: '' } }), + ], + rows: expect.any(Array), + }) + ); + expect(mockGetFileRowContent).toHaveBeenCalledTimes(3); + expect(mockGetFolderRowContent).toHaveBeenCalledTimes(2); + }); + }); }); diff --git a/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getFileRowContent.ts b/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getFileRowContent.ts index 31cfd120d24..aa48ffd5b91 100644 --- a/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getFileRowContent.ts +++ b/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getFileRowContent.ts @@ -4,11 +4,12 @@ import { DataTableProps } from '../../../composables/DataTable'; import { LOCATION_DETAIL_VIEW_HEADERS } from './constants'; import { LocationPermissions } from '../../../actions'; +import { LocationDetailViewHeaders } from './types'; +import { getFileKey, getFilePath } from '../../../actions/handlers'; export const getFileRowContent = ({ permissions, isSelected, - itemLocationKey, getDateDisplayValue, lastModified, rowId, @@ -17,11 +18,12 @@ export const getFileRowContent = ({ size, onDownload, onSelect, + headers, }: { permissions: LocationPermissions; isSelected: boolean; - itemLocationKey: string; lastModified: Date; + headers: LocationDetailViewHeaders; getDateDisplayValue: (date: Date) => string; rowId: string; rowKey: string; @@ -30,7 +32,7 @@ export const getFileRowContent = ({ onDownload: () => void; onSelect: () => void; }): DataTableProps['rows'][number]['content'] => - LOCATION_DETAIL_VIEW_HEADERS.map(({ key: columnKey }) => { + headers.map(({ key: columnKey }) => { const key = `${columnKey}-${rowId}`; switch (columnKey) { case 'checkbox': { @@ -52,7 +54,16 @@ export const getFileRowContent = ({ content: { icon: 'file', ariaLabel: 'file', - text: rowKey.slice(itemLocationKey.length), + text: getFileKey(rowKey), + }, + }; + } + case 'path': { + return { + key, + type: 'text', + content: { + text: getFilePath(rowKey), }, }; } diff --git a/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getFolderRowContent.ts b/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getFolderRowContent.ts index 71e4e4df335..e5691134556 100644 --- a/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getFolderRowContent.ts +++ b/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getFolderRowContent.ts @@ -1,16 +1,19 @@ import { DataTableProps } from '../../../composables/DataTable'; -import { LOCATION_DETAIL_VIEW_HEADERS } from './constants'; +import { LocationDetailViewHeaders } from './types'; +import { getFolderName, getFolderPath } from '../../../actions/handlers'; export const getFolderRowContent = ({ - itemSubPath, rowId, + rowKey, + headers, onNavigate, }: { - itemSubPath: string; rowId: string; + rowKey: string; + headers: LocationDetailViewHeaders; onNavigate: () => void; }): DataTableProps['rows'][number]['content'] => - LOCATION_DETAIL_VIEW_HEADERS.map(({ key: columnKey }) => { + headers.map(({ key: columnKey }) => { const key = `${columnKey}-${rowId}`; switch (columnKey) { case 'checkbox': { @@ -22,12 +25,21 @@ export const getFolderRowContent = ({ type: 'button', content: { icon: 'folder', - ariaLabel: itemSubPath, - label: itemSubPath, + ariaLabel: getFolderName(rowKey), + label: getFolderName(rowKey), onClick: onNavigate, }, }; } + case 'path': { + return { + key, + type: 'text', + content: { + text: getFolderPath(rowKey), + }, + }; + } case 'type': { return { key, type: 'text', content: { text: 'Folder' } }; } diff --git a/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getLocationDetailViewTableData.ts b/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getLocationDetailViewTableData.ts index 94c5f70cd86..a34f111ecda 100644 --- a/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getLocationDetailViewTableData.ts +++ b/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getLocationDetailViewTableData.ts @@ -1,4 +1,7 @@ -import { DataTableProps } from '../../../composables/DataTable'; +import { + DataTableHeader, + DataTableProps, +} from '../../../composables/DataTable'; import { LocationData } from '../../../actions'; import { createFileDataItem, @@ -11,12 +14,15 @@ import { FileData } from '../../../actions/handlers'; import { LOCATION_DETAIL_VIEW_HEADERS } from './constants'; import { LocationState } from '../../../providers/store/location'; +import { HeaderKeys, LocationDetailViewHeaders } from './types'; +import { WithKey } from '../../../components/types'; export const getLocationDetailViewTableData = ({ areAllFilesSelected, location, fileDataItems, hasFiles, + showPaths, pageItems, selectFileLabel, selectAllFilesLabel, @@ -30,6 +36,7 @@ export const getLocationDetailViewTableData = ({ location: LocationState; fileDataItems?: FileData[]; hasFiles: boolean; + showPaths: boolean; pageItems: LocationItemData[]; selectFileLabel: string; selectAllFilesLabel: string; @@ -39,7 +46,7 @@ export const getLocationDetailViewTableData = ({ onSelect: (isSelected: boolean, fileItem: FileData) => void; onSelectAll: () => void; }): DataTableProps => { - const headerCheckbox: DataTableProps['headers'][number] = { + const headerCheckbox: WithKey = { key: 'checkbox', type: 'checkbox', content: { @@ -50,16 +57,27 @@ export const getLocationDetailViewTableData = ({ }, }; - const headers = hasFiles - ? [headerCheckbox, ...LOCATION_DETAIL_VIEW_HEADERS.slice(1)] - : LOCATION_DETAIL_VIEW_HEADERS; + const pathHeader: WithKey = { + key: 'path', + type: 'sort', + content: { label: 'Path' }, + }; + + const [noopCheckbox, nameHeader, ...rest] = LOCATION_DETAIL_VIEW_HEADERS; + + const headers: LocationDetailViewHeaders = [ + hasFiles ? headerCheckbox : noopCheckbox, + nameHeader, + ...(showPaths ? [pathHeader] : []), + ...rest, + ]; const rows: DataTableProps['rows'] = pageItems.map((locationItem) => { const { id, key, type } = locationItem; switch (type) { case 'FILE': { const { lastModified, size } = locationItem; - const { current, path } = location; + const { current } = location; const isSelected = fileDataItems?.some((item) => item.id === id) ?? false; const onFileDownload = () => { @@ -71,9 +89,9 @@ export const getLocationDetailViewTableData = ({ return { key: id, content: getFileRowContent({ + headers, permissions: current?.permissions ?? [], isSelected, - itemLocationKey: `${current?.prefix ?? ''}${path}`, lastModified, getDateDisplayValue, rowId: id, @@ -86,8 +104,7 @@ export const getLocationDetailViewTableData = ({ }; } case 'FOLDER': { - const { current, path } = location; - const itemSubPath = key.slice(`${current?.prefix ?? ''}${path}`.length); + const { current } = location; const itemLocationPath = key.slice(current?.prefix.length); const onFolderNavigate = () => { if (!current) { @@ -98,7 +115,8 @@ export const getLocationDetailViewTableData = ({ return { key: id, content: getFolderRowContent({ - itemSubPath, + headers, + rowKey: key, rowId: id, onNavigate: onFolderNavigate, }), diff --git a/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/types.ts b/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/types.ts index adcee7dc2db..d0c36ba7f64 100644 --- a/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/types.ts +++ b/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/types.ts @@ -5,6 +5,7 @@ export type HeaderKeys = | 'checkbox' | 'name' | 'type' + | 'path' | 'last-modified' | 'size' | 'download'; diff --git a/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/types.ts b/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/types.ts index 3074020d7ed..ed3bc1a1f97 100644 --- a/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/types.ts +++ b/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/types.ts @@ -8,6 +8,7 @@ import { ActionsListItem } from '../../composables/ActionsList'; import { LocationState } from '../../providers/store/location'; import { ListViewProps } from '../types'; +import { SearchOutput } from '../../actions/useAction/createEnhancedListHandler'; export interface LocationDetailViewState { actions: ActionsListItem[]; @@ -25,7 +26,7 @@ export interface LocationDetailViewState { downloadErrorMessage: string | undefined; shouldShowEmptyMessage: boolean; searchQuery: string; - hasExhaustedSearch: boolean; + searchInfo: SearchOutput | undefined; pageItems: LocationItemData[]; page: number; onActionSelect: (actionType: string) => void; diff --git a/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/useLocationDetailView.ts b/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/useLocationDetailView.ts index 1ef69380f67..9741ac9774a 100644 --- a/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/useLocationDetailView.ts +++ b/packages/react-storage/src/components/StorageBrowser/views/LocationDetailView/useLocationDetailView.ts @@ -73,7 +73,6 @@ export const useLocationDetailView = ( // set up pagination const { items, nextToken, search } = data; - const { hasExhaustedSearch = false } = search ?? {}; const hasNextToken = !!nextToken; const paginateCallback = () => { if (hasInvalidPrefix || !nextToken) return; @@ -208,7 +207,7 @@ export const useLocationDetailView = ( isSearchingSubfolders, onPaginate, searchQuery, - hasExhaustedSearch, + searchInfo: search, onRefresh, onNavigate: (location: LocationData, path?: string) => { onNavigate?.(location, path); diff --git a/packages/react-storage/src/components/StorageBrowser/views/LocationsView/__tests__/LocationsView.spec.tsx b/packages/react-storage/src/components/StorageBrowser/views/LocationsView/__tests__/LocationsView.spec.tsx index 64bb0b0343c..509aa32cd46 100644 --- a/packages/react-storage/src/components/StorageBrowser/views/LocationsView/__tests__/LocationsView.spec.tsx +++ b/packages/react-storage/src/components/StorageBrowser/views/LocationsView/__tests__/LocationsView.spec.tsx @@ -183,7 +183,6 @@ describe('LocationsView', () => { data: { items: [], nextToken: undefined, - search: { hasExhaustedSearch: false }, }, hasError: false, isLoading: true,