diff --git a/packages/react-storage/src/components/StorageBrowser/composables/Navigation.tsx b/packages/react-storage/src/components/StorageBrowser/composables/Navigation.tsx index f62a8ed7f22..b1b179187e1 100644 --- a/packages/react-storage/src/components/StorageBrowser/composables/Navigation.tsx +++ b/packages/react-storage/src/components/StorageBrowser/composables/Navigation.tsx @@ -15,7 +15,7 @@ export interface NavigationProps { export const Navigation = ({ items, }: NavigationProps): React.JSX.Element | null => { - if (!items?.length) { + if (!items.length) { return null; } diff --git a/packages/react-storage/src/components/StorageBrowser/composables/Search.tsx b/packages/react-storage/src/components/StorageBrowser/composables/Search.tsx index 0b717f730f4..ea4583d66b1 100644 --- a/packages/react-storage/src/components/StorageBrowser/composables/Search.tsx +++ b/packages/react-storage/src/components/StorageBrowser/composables/Search.tsx @@ -17,7 +17,7 @@ const BLOCK_NAME = `${CLASS_BASE}__search`; const TOGGLE_BLOCK = 'toggle'; export interface SearchProps { - onSearch: (term: string, includeSubfolders: boolean) => void; + onSearch?: (term: string, includeSubfolders: boolean) => void; searchPlaceholder?: string; showIncludeSubfolders?: boolean; } @@ -47,7 +47,7 @@ export const Search = ({ placeholder={searchPlaceholder} onKeyUp={(event) => { if (event.key === 'Enter') { - onSearch(term, subfoldersIncluded); + onSearch?.(term, subfoldersIncluded); } }} value={term} @@ -58,7 +58,7 @@ export const Search = ({ className={`${BLOCK_NAME}__field-clear-button`} onClick={() => { setTerm(''); - onSearch('', subfoldersIncluded); + onSearch?.('', subfoldersIncluded); }} variant="refresh" > @@ -68,7 +68,7 @@ export const Search = ({ onSearch(term, subfoldersIncluded)} + onClick={() => onSearch?.(term, subfoldersIncluded)} > Submit diff --git a/packages/react-storage/src/components/StorageBrowser/controls/DropZoneControl.tsx b/packages/react-storage/src/components/StorageBrowser/controls/DropZoneControl.tsx index 70300d76b23..6c942ca620a 100644 --- a/packages/react-storage/src/components/StorageBrowser/controls/DropZoneControl.tsx +++ b/packages/react-storage/src/components/StorageBrowser/controls/DropZoneControl.tsx @@ -10,7 +10,7 @@ export const DropZoneControl = ({ className, children, }: ControlProps & { children: React.ReactNode }): React.JSX.Element | null => { - const { props } = useDropZone(); + const props = useDropZone(); const ResolvedDropZone = useResolvedComposable(DropZone, 'DropZone'); diff --git a/packages/react-storage/src/components/StorageBrowser/controls/NavigationControl.tsx b/packages/react-storage/src/components/StorageBrowser/controls/NavigationControl.tsx index a8b6279502a..692e7a1459d 100644 --- a/packages/react-storage/src/components/StorageBrowser/controls/NavigationControl.tsx +++ b/packages/react-storage/src/components/StorageBrowser/controls/NavigationControl.tsx @@ -13,10 +13,6 @@ export const NavigationControl = ({ const ResolvedNavigation = useResolvedComposable(Navigation, 'Navigation'); - if (!props) { - return null; - } - return ( diff --git a/packages/react-storage/src/components/StorageBrowser/controls/SearchControl.tsx b/packages/react-storage/src/components/StorageBrowser/controls/SearchControl.tsx index 7728f2b76aa..8b0542f3577 100644 --- a/packages/react-storage/src/components/StorageBrowser/controls/SearchControl.tsx +++ b/packages/react-storage/src/components/StorageBrowser/controls/SearchControl.tsx @@ -13,10 +13,6 @@ export const SearchControl = ({ const { showIncludeSubfolders, searchPlaceholder } = data; const ResolvedSearch = useResolvedComposable(Search, 'Search'); - if (!onSearch) { - return null; - } - return ( diff --git a/packages/react-storage/src/components/StorageBrowser/controls/__tests__/NavigationControl.spec.tsx b/packages/react-storage/src/components/StorageBrowser/controls/__tests__/NavigationControl.spec.tsx index e5819a08f53..54945eabe3b 100644 --- a/packages/react-storage/src/components/StorageBrowser/controls/__tests__/NavigationControl.spec.tsx +++ b/packages/react-storage/src/components/StorageBrowser/controls/__tests__/NavigationControl.spec.tsx @@ -41,12 +41,4 @@ describe('NavigationControl', () => { expect(item1).toHaveTextContent('Item 1'); expect(item2).toHaveTextContent('Item 2'); }); - - it('returns null without props', () => { - mockUseNavigation.mockReturnValue(null); - - render(); - - expect(screen.queryByRole('navigation')).not.toBeInTheDocument(); - }); }); diff --git a/packages/react-storage/src/components/StorageBrowser/controls/context.ts b/packages/react-storage/src/components/StorageBrowser/controls/context.ts index 4f901b7283b..0418deaf014 100644 --- a/packages/react-storage/src/components/StorageBrowser/controls/context.ts +++ b/packages/react-storage/src/components/StorageBrowser/controls/context.ts @@ -1,10 +1,7 @@ import { createContextUtilities } from '@aws-amplify/ui-react-core'; import { ControlsContext } from './types'; -const defaultValue = { - data: {}, - actionsConfig: {}, -} as ControlsContext; +const defaultValue = { data: {} } as ControlsContext; export const { useControlsContext, ControlsContextProvider } = createContextUtilities({ diff --git a/packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useActionCancel.spec.tsx b/packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useActionCancel.spec.ts similarity index 93% rename from packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useActionCancel.spec.tsx rename to packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useActionCancel.spec.ts index 186b6676e73..2941e5c9518 100644 --- a/packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useActionCancel.spec.tsx +++ b/packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useActionCancel.spec.ts @@ -8,10 +8,6 @@ describe('useActionCancel', () => { actionCancelLabel: 'Cancel', isActionCancelDisabled: false, }, - actionsConfig: { - isCancelable: true, - type: 'BATCH_ACTION', - }, onActionCancel: jest.fn(), }; const useControlsContextSpy = jest.spyOn( diff --git a/packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useActionStart.spec.ts b/packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useActionStart.spec.ts index 2fdb066964b..0cd1b8342a8 100644 --- a/packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useActionStart.spec.ts +++ b/packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useActionStart.spec.ts @@ -7,10 +7,6 @@ describe('useActionStart', () => { data: { actionStartLabel: 'Start', }, - actionsConfig: { - isCancelable: true, - type: 'BATCH_ACTION', - }, onActionStart: jest.fn(), }; diff --git a/packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useDataTable.spec.tsx b/packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useDataTable.spec.ts similarity index 100% rename from packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useDataTable.spec.tsx rename to packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useDataTable.spec.ts diff --git a/packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useDropZone.spec.tsx b/packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useDropZone.spec.ts similarity index 86% rename from packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useDropZone.spec.tsx rename to packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useDropZone.spec.ts index 94d69863334..099d450e903 100644 --- a/packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useDropZone.spec.tsx +++ b/packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useDropZone.spec.ts @@ -19,12 +19,10 @@ describe('useDropZone', () => { }); const result = useDropZone(); - result.props!.onDropComplete!(files); + result.onDropComplete?.(files); expect(result).toStrictEqual({ - props: { - onDropComplete: expect.any(Function), - }, + onDropComplete: expect.any(Function), }); expect(mockOnDropFiles).toHaveBeenCalledWith(files); }); diff --git a/packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useNavigation.spec.tsx b/packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useNavigation.spec.ts similarity index 98% rename from packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useNavigation.spec.tsx rename to packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useNavigation.spec.ts index 74d75a915b0..96bd0192ec5 100644 --- a/packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useNavigation.spec.tsx +++ b/packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useNavigation.spec.ts @@ -57,12 +57,12 @@ describe('useNavigation', () => { }); }); - it('returns null if current location is undefined', () => { + it('returns empty items if current location is undefined', () => { mockUseControlsContext.mockReturnValue({ data: {} }); const { result } = renderHook(() => useNavigation()); - expect(result.current).toBeNull(); + expect(result.current).toStrictEqual({ items: [] }); }); it('calls onNavigateHome', () => { diff --git a/packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useStatusDisplay.spec.ts b/packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useStatusDisplay.spec.ts new file mode 100644 index 00000000000..9a434ba642d --- /dev/null +++ b/packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useStatusDisplay.spec.ts @@ -0,0 +1,61 @@ +import { useControlsContext } from '../../../controls/context'; +import { useStatusDisplay } from '../useStatusDisplay'; + +jest.mock('../../../controls/context'); + +describe('useStatusDisplay', () => { + const data = { + statusCounts: { + CANCELED: 2, + COMPLETE: 4, + FAILED: 3, + PENDING: 0, + QUEUED: 1, + TOTAL: 10, + }, + }; + + // assert mocks + const mockUseControlsContext = useControlsContext as jest.Mock; + + afterEach(() => { + mockUseControlsContext.mockReset(); + }); + + it('returns useStatusDisplay data', () => { + mockUseControlsContext.mockReturnValue({ data }); + + expect(useStatusDisplay()).toStrictEqual({ + statuses: [ + expect.objectContaining({ count: 4 }), + expect.objectContaining({ count: 3 }), + expect.objectContaining({ count: 2 }), + expect.objectContaining({ count: 1 }), + ], + total: 10, + }); + }); + + it('returns default values if statusCounts is undefined', () => { + mockUseControlsContext.mockReturnValue({ data: {} }); + + expect(useStatusDisplay()).toStrictEqual({ statuses: [], total: 0 }); + }); + + it('returns default values if statusCounts total is 0', () => { + mockUseControlsContext.mockReturnValue({ + data: { + statusCounts: { + CANCELED: 0, + COMPLETE: 0, + FAILED: 0, + PENDING: 0, + QUEUED: 0, + TOTAL: 0, + }, + }, + }); + + expect(useStatusDisplay()).toStrictEqual({ statuses: [], total: 0 }); + }); +}); diff --git a/packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useStatusDisplay.spec.tsx b/packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useStatusDisplay.spec.tsx deleted file mode 100644 index 175c2d7c623..00000000000 --- a/packages/react-storage/src/components/StorageBrowser/controls/hooks/__tests__/useStatusDisplay.spec.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import { useControlsContext } from '../../../controls/context'; -import { useStatusDisplay } from '../useStatusDisplay'; - -jest.mock('../../../controls/context'); - -describe('useStatusDisplay', () => { - const data = { - statusCounts: { - CANCELED: 2, - COMPLETE: 4, - FAILED: 3, - PENDING: 0, - QUEUED: 1, - TOTAL: 10, - }, - }; - - const actionsConfig = { - isCancelable: true, - type: 'BATCH_ACTION', - }; - // assert mocks - const mockUseControlsContext = useControlsContext as jest.Mock; - - afterEach(() => { - mockUseControlsContext.mockReset(); - }); - - it('returns useStatusDisplay data', () => { - mockUseControlsContext.mockReturnValue({ data, actionsConfig }); - - expect(useStatusDisplay()).toStrictEqual({ - statuses: [ - expect.objectContaining({ count: 4 }), - expect.objectContaining({ count: 3 }), - expect.objectContaining({ count: 2 }), - expect.objectContaining({ count: 1 }), - ], - total: 10, - }); - }); - - it('returns empty object if statusCounts is undefined', () => { - mockUseControlsContext.mockReturnValue({ data: {}, actionsConfig }); - - expect(useStatusDisplay()).toBeNull(); - }); - - it('returns empty object if taksCount total is 0', () => { - mockUseControlsContext.mockReturnValue({ - data: { - statusCounts: { - CANCELED: 0, - COMPLETE: 0, - FAILED: 0, - PENDING: 0, - QUEUED: 0, - TOTAL: 0, - }, - }, - actionsConfig, - }); - - expect(useStatusDisplay()).toBeNull(); - }); - - it('returns empty object if not a batch action', () => { - mockUseControlsContext.mockReturnValue({ - data, - actionsConfig: { - isCancelable: true, - type: 'SINGLE_ACTION', - }, - }); - - expect(useStatusDisplay()).toBeNull(); - }); - - it('omits canceled status if action is not cancelable', () => { - mockUseControlsContext.mockReturnValue({ - data: { - statusCounts: { - CANCELED: 0, - COMPLETE: 4, - FAILED: 3, - PENDING: 0, - QUEUED: 1, - TOTAL: 8, - }, - }, - actionsConfig: { - isCancelable: false, - type: 'BATCH_ACTION', - }, - }); - - expect(useStatusDisplay()).toStrictEqual({ - statuses: [ - expect.objectContaining({ count: 4 }), - expect.objectContaining({ count: 3 }), - expect.objectContaining({ count: 1 }), - ], - total: 8, - }); - }); -}); diff --git a/packages/react-storage/src/components/StorageBrowser/controls/hooks/useActionCancel.tsx b/packages/react-storage/src/components/StorageBrowser/controls/hooks/useActionCancel.ts similarity index 100% rename from packages/react-storage/src/components/StorageBrowser/controls/hooks/useActionCancel.tsx rename to packages/react-storage/src/components/StorageBrowser/controls/hooks/useActionCancel.ts diff --git a/packages/react-storage/src/components/StorageBrowser/controls/hooks/useActionStart.tsx b/packages/react-storage/src/components/StorageBrowser/controls/hooks/useActionStart.ts similarity index 100% rename from packages/react-storage/src/components/StorageBrowser/controls/hooks/useActionStart.tsx rename to packages/react-storage/src/components/StorageBrowser/controls/hooks/useActionStart.ts diff --git a/packages/react-storage/src/components/StorageBrowser/controls/hooks/useDropZone.ts b/packages/react-storage/src/components/StorageBrowser/controls/hooks/useDropZone.ts index 2a8bc461d16..bad47788948 100644 --- a/packages/react-storage/src/components/StorageBrowser/controls/hooks/useDropZone.ts +++ b/packages/react-storage/src/components/StorageBrowser/controls/hooks/useDropZone.ts @@ -1,22 +1,12 @@ import { DropZoneProps } from '../../composables/DropZone'; import { useControlsContext } from '../../controls/context'; -export type UseDropZone = () => { - props?: { - onDropComplete: DropZoneProps['onDropComplete']; - }; -}; - /** * This hook, not to be confused with the useDropZone vended from @aws-amplify/ui-react-core, is only intended for use * with its corresponding DropZone control. */ -export const useDropZone: UseDropZone = () => { +export const useDropZone = (): Pick => { const { onDropFiles } = useControlsContext(); - return { - props: { - onDropComplete: onDropFiles, - }, - }; + return { onDropComplete: onDropFiles }; }; diff --git a/packages/react-storage/src/components/StorageBrowser/controls/hooks/useNavigation.ts b/packages/react-storage/src/components/StorageBrowser/controls/hooks/useNavigation.ts index 39b280f889e..254e4b3c426 100644 --- a/packages/react-storage/src/components/StorageBrowser/controls/hooks/useNavigation.ts +++ b/packages/react-storage/src/components/StorageBrowser/controls/hooks/useNavigation.ts @@ -2,13 +2,13 @@ import React from 'react'; import { NavigationProps } from '../../composables/Navigation'; import { useControlsContext } from '../../controls/context'; -export const useNavigation = (): NavigationProps | null => { +export const useNavigation = (): NavigationProps => { const { data, onNavigate, onNavigateHome } = useControlsContext(); const { currentLocation, currentPath = '' } = data; return React.useMemo(() => { if (!currentLocation) { - return null; + return { items: [] }; } const { bucket, permission, prefix = '', type } = currentLocation; diff --git a/packages/react-storage/src/components/StorageBrowser/controls/hooks/useStatusDisplay.ts b/packages/react-storage/src/components/StorageBrowser/controls/hooks/useStatusDisplay.ts index 9626779a841..494d72899ce 100644 --- a/packages/react-storage/src/components/StorageBrowser/controls/hooks/useStatusDisplay.ts +++ b/packages/react-storage/src/components/StorageBrowser/controls/hooks/useStatusDisplay.ts @@ -2,30 +2,20 @@ import { StatusDisplayProps } from '../../composables/StatusDisplay'; import { useControlsContext } from '../../controls/context'; import { displayText } from '../../displayText/en'; -export const useStatusDisplay = (): StatusDisplayProps | null => { - const { data, actionsConfig } = useControlsContext(); +export const useStatusDisplay = (): StatusDisplayProps => { + const { data } = useControlsContext(); const { statusCounts } = data; - const { isCancelable, type } = actionsConfig ?? {}; - if (!statusCounts?.TOTAL || type !== 'BATCH_ACTION') { - return null; + if (!statusCounts?.TOTAL) { + return { statuses: [], total: 0 }; } const statuses = [ { name: displayText.statusDisplayCompleted, count: statusCounts.COMPLETE }, { name: displayText.statusDisplayFailed, count: statusCounts.FAILED }, + { name: displayText.statusDisplayCanceled, count: statusCounts.CANCELED }, { name: displayText.statusDisplayQueued, count: statusCounts.QUEUED }, ]; - if (isCancelable) { - statuses.splice(2, 0, { - name: displayText.statusDisplayCanceled, - count: statusCounts.CANCELED, - }); - } - - return { - statuses, - total: statusCounts.TOTAL, - }; + return { statuses, total: statusCounts.TOTAL }; }; diff --git a/packages/react-storage/src/components/StorageBrowser/controls/types.ts b/packages/react-storage/src/components/StorageBrowser/controls/types.ts index 6743ff02555..ecd2285b8d4 100644 --- a/packages/react-storage/src/components/StorageBrowser/controls/types.ts +++ b/packages/react-storage/src/components/StorageBrowser/controls/types.ts @@ -48,14 +48,6 @@ export interface ControlsContext { tableData?: TableData; statusCounts?: StatusCounts; }; - actionsConfig?: { - type: - | 'SINGLE_ACTION' - | 'BATCH_ACTION' - | 'LIST_LOCATIONS' - | 'LIST_LOCATION_ITEMS'; - isCancelable?: boolean; - }; onActionCancel?: () => void; onActionStart?: () => void; onDropComplete?: DropZoneProps['onDropComplete']; diff --git a/packages/react-storage/src/components/StorageBrowser/views/LocationActionView/CopyFilesControls.tsx b/packages/react-storage/src/components/StorageBrowser/views/LocationActionView/CopyFilesControls.tsx index 38b2da4706d..3534be22563 100644 --- a/packages/react-storage/src/components/StorageBrowser/views/LocationActionView/CopyFilesControls.tsx +++ b/packages/react-storage/src/components/StorageBrowser/views/LocationActionView/CopyFilesControls.tsx @@ -62,7 +62,6 @@ export const CopyFilesControls = (props: { isActionCancelDisabled, actionCancelLabel: 'Cancel', }, - actionsConfig: { type: 'BATCH_ACTION', isCancelable: true }, onActionStart, onActionCancel, }; diff --git a/packages/react-storage/src/components/StorageBrowser/views/LocationActionView/CreateFolderControls.tsx b/packages/react-storage/src/components/StorageBrowser/views/LocationActionView/CreateFolderControls.tsx index 145ac4081d4..2493a81bfd8 100644 --- a/packages/react-storage/src/components/StorageBrowser/views/LocationActionView/CreateFolderControls.tsx +++ b/packages/react-storage/src/components/StorageBrowser/views/LocationActionView/CreateFolderControls.tsx @@ -103,10 +103,6 @@ export const CreateFolderControls = ({ ? !folderName || !!fieldValidationError : undefined, }, - actionsConfig: { - type: 'SINGLE_ACTION', - isCancelable: true, - }, onActionStart: hasCompletedStatus ? handleClose : handleCreateFolder, }; diff --git a/packages/react-storage/src/components/StorageBrowser/views/LocationActionView/DeleteFilesControls.tsx b/packages/react-storage/src/components/StorageBrowser/views/LocationActionView/DeleteFilesControls.tsx index 061c2e3d0d7..5a040de92c4 100644 --- a/packages/react-storage/src/components/StorageBrowser/views/LocationActionView/DeleteFilesControls.tsx +++ b/packages/react-storage/src/components/StorageBrowser/views/LocationActionView/DeleteFilesControls.tsx @@ -47,7 +47,6 @@ export const DeleteFilesControls = (props?: { actionCancelLabel: 'Cancel', isActionCancelDisabled: !isProcessing || isProcessingComplete, }, - actionsConfig: { type: 'BATCH_ACTION', isCancelable: true }, onActionStart, onActionCancel, }; diff --git a/packages/react-storage/src/components/StorageBrowser/views/LocationActionView/UploadControls.tsx b/packages/react-storage/src/components/StorageBrowser/views/LocationActionView/UploadControls.tsx index 2ebef148178..efb7c637444 100644 --- a/packages/react-storage/src/components/StorageBrowser/views/LocationActionView/UploadControls.tsx +++ b/packages/react-storage/src/components/StorageBrowser/views/LocationActionView/UploadControls.tsx @@ -334,10 +334,6 @@ export const UploadControls = (props: { isOverwriteCheckboxDisabled, statusCounts, }, - actionsConfig: { - type: 'BATCH_ACTION', - isCancelable: true, - }, onActionStart, onActionCancel, };