diff --git a/packages/react-storage/src/components/StorageBrowser/displayText/__tests__/context.spec.tsx b/packages/react-storage/src/components/StorageBrowser/displayText/__tests__/context.spec.tsx new file mode 100644 index 00000000000..e8c4ec8d149 --- /dev/null +++ b/packages/react-storage/src/components/StorageBrowser/displayText/__tests__/context.spec.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { renderHook } from '@testing-library/react'; + +import { DisplayTextProvider, useDisplayText } from '../context'; +import { DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT } from '../libraries'; + +describe('useDisplayText', () => { + it('returns default displayText`', () => { + const { result } = renderHook(useDisplayText, { + wrapper: (props) => , + }); + + expect(result.current.LocationDetailView).toStrictEqual( + DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT['LocationDetailView'] + ); + expect(result.current.LocationsView).toStrictEqual( + DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT['LocationsView'] + ); + expect(result.current.UploadView).toStrictEqual( + DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT['UploadView'] + ); + }); +}); diff --git a/packages/react-storage/src/components/StorageBrowser/displayText/context.tsx b/packages/react-storage/src/components/StorageBrowser/displayText/context.tsx new file mode 100644 index 00000000000..7016ef1803e --- /dev/null +++ b/packages/react-storage/src/components/StorageBrowser/displayText/context.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import { createContextUtilities } from '@aws-amplify/ui-react-core'; + +import { DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT } from './libraries'; +import { + DefaultStorageBrowserDisplayText, + StorageBrowserDisplayText, +} from './types'; + +export const { DisplayTextContext, useDisplayText } = createContextUtilities< + DefaultStorageBrowserDisplayText, + 'DisplayText' +>({ + contextName: 'DisplayText', + errorMessage: '`useDisplayText` must be called inside `DisplayTextProvider`', +}); + +export function DisplayTextProvider({ + children, + displayText: _override, +}: { + children?: React.ReactNode; + displayText?: StorageBrowserDisplayText; +}): React.JSX.Element { + // do deep merge here of default and override here + return ( + + {children} + + ); +} diff --git a/packages/react-storage/src/components/StorageBrowser/displayText/index.ts b/packages/react-storage/src/components/StorageBrowser/displayText/index.ts new file mode 100644 index 00000000000..19ffbdbe2d6 --- /dev/null +++ b/packages/react-storage/src/components/StorageBrowser/displayText/index.ts @@ -0,0 +1 @@ +export { DisplayTextProvider, useDisplayText } from './context'; diff --git a/packages/react-storage/src/components/StorageBrowser/displayText/libraries/en/__tests__/__snapshots__/index.spec.ts.snap b/packages/react-storage/src/components/StorageBrowser/displayText/libraries/en/__tests__/__snapshots__/index.spec.ts.snap new file mode 100644 index 00000000000..dfc95def098 --- /dev/null +++ b/packages/react-storage/src/components/StorageBrowser/displayText/libraries/en/__tests__/__snapshots__/index.spec.ts.snap @@ -0,0 +1,101 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.LocationDetailView should have expected keys 1`] = ` +{ + "getListResultsMessage": [Function], + "searchExhaustedMessage": "Showing results for up to the first 10,000 items", + "searchIncludeSubfoldersLabel": "Include subfolders", + "searchPlaceholder": "Search current folder", + "searchSubmitLabel": "Search", + "tableColumnLastModifiedHeader": "Last modified", + "tableColumnNameHeader": "Name", + "tableColumnSizeHeader": "Size", + "tableColumnTypeHeader": "Type", + "title": [Function], +} +`; + +exports[`DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.LocationsView should match snapshot 1`] = ` +{ + "getListResultsMessage": [Function], + "searchPlaceholder": "Filter files and folders", + "searchSubmitLabel": "Search", + "tableColumnBucketHeader": "Bucket", + "tableColumnFolderHeader": "Folder", + "tableColumnPermissionsHeader": "Permissions", +} +`; + +exports[`DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.UploadView should match snapshot 1`] = ` +{ + "actionCancelLabel": "Cancel", + "actionDestinationLabel": "Destination", + "actionExitLabel": "Exit", + "actionStartLabel": "Upload", + "addFilesLabel": "Add files", + "addFolderLabel": "Add folder", + "getActionCompleteMessage": [Function], + "overwriteExistingLabel": "Overwrite existing files", + "statusDisplayCanceledLabel": "Canceled", + "statusDisplayCompletedLabel": "Completed", + "statusDisplayFailedLabel": "Failed", + "statusDisplayOverridePreventedLabel": "Overwrite prevented", + "statusDisplayQueuedLabel": "Not Started", + "statusDisplayTotalLabel": "Total", + "tableColumnCancelHeader": "", + "tableColumnFolderHeader": "Folder", + "tableColumnNameHeader": "Name", + "tableColumnSizeHeader": "Size", + "tableColumnStatusHeader": "Status", + "tableColumnTypeHeader": "Type", + "title": "Upload", +} +`; + +exports[`DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT should match snapshot 1`] = ` +{ + "LocationDetailView": { + "getListResultsMessage": [Function], + "searchExhaustedMessage": "Showing results for up to the first 10,000 items", + "searchIncludeSubfoldersLabel": "Include subfolders", + "searchPlaceholder": "Search current folder", + "searchSubmitLabel": "Search", + "tableColumnLastModifiedHeader": "Last modified", + "tableColumnNameHeader": "Name", + "tableColumnSizeHeader": "Size", + "tableColumnTypeHeader": "Type", + "title": [Function], + }, + "LocationsView": { + "getListResultsMessage": [Function], + "searchPlaceholder": "Filter files and folders", + "searchSubmitLabel": "Search", + "tableColumnBucketHeader": "Bucket", + "tableColumnFolderHeader": "Folder", + "tableColumnPermissionsHeader": "Permissions", + }, + "UploadView": { + "actionCancelLabel": "Cancel", + "actionDestinationLabel": "Destination", + "actionExitLabel": "Exit", + "actionStartLabel": "Upload", + "addFilesLabel": "Add files", + "addFolderLabel": "Add folder", + "getActionCompleteMessage": [Function], + "overwriteExistingLabel": "Overwrite existing files", + "statusDisplayCanceledLabel": "Canceled", + "statusDisplayCompletedLabel": "Completed", + "statusDisplayFailedLabel": "Failed", + "statusDisplayOverridePreventedLabel": "Overwrite prevented", + "statusDisplayQueuedLabel": "Not Started", + "statusDisplayTotalLabel": "Total", + "tableColumnCancelHeader": "", + "tableColumnFolderHeader": "Folder", + "tableColumnNameHeader": "Name", + "tableColumnSizeHeader": "Size", + "tableColumnStatusHeader": "Status", + "tableColumnTypeHeader": "Type", + "title": "Upload", + }, +} +`; diff --git a/packages/react-storage/src/components/StorageBrowser/displayText/libraries/en/__tests__/index.spec.ts b/packages/react-storage/src/components/StorageBrowser/displayText/libraries/en/__tests__/index.spec.ts new file mode 100644 index 00000000000..d3975f00469 --- /dev/null +++ b/packages/react-storage/src/components/StorageBrowser/displayText/libraries/en/__tests__/index.spec.ts @@ -0,0 +1,83 @@ +import { StatusCounts } from '../../../../tasks'; +import { DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT } from '../default'; + +describe('DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT', () => { + it('should match snapshot', () => { + expect(DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT).toMatchSnapshot(); + }); + + describe('DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.LocationDetailView', () => { + it('should have expected keys', () => { + expect( + DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.LocationDetailView + ).toMatchObject({ + getListResultsMessage: expect.any(Function), + searchExhaustedMessage: expect.any(String), + searchIncludeSubfoldersLabel: expect.any(String), + searchPlaceholder: expect.any(String), + tableColumnLastModifiedHeader: expect.any(String), + tableColumnNameHeader: expect.any(String), + tableColumnSizeHeader: expect.any(String), + tableColumnTypeHeader: expect.any(String), + title: expect.any(Function), + }); + + expect( + DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.LocationDetailView + ).toMatchSnapshot(); + }); + + it('returns string values from callbacks', () => { + const { getListResultsMessage } = + DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.LocationDetailView; + + expect( + typeof getListResultsMessage({ + key: '', + id: '', + lastModified: new Date(), + size: 1000, + type: 'FILE', + }) + ).toBe('string'); + }); + }); + + describe('DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.LocationsView', () => { + it('should match snapshot', () => { + expect( + DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.LocationsView + ).toMatchSnapshot(); + }); + + it('returns string values from callbacks', () => { + const { getListResultsMessage } = + DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.LocationsView; + + expect( + typeof getListResultsMessage({ + bucket: '', + permission: 'READ', + prefix: '', + id: '', + type: 'PREFIX', + }) + ).toBe('string'); + }); + }); + + describe('DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.UploadView', () => { + it('should match snapshot', () => { + expect(DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.UploadView).toMatchSnapshot(); + }); + + it('returns string values from callbacks', () => { + const { getActionCompleteMessage } = + DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.UploadView; + + expect(typeof getActionCompleteMessage({} as StatusCounts)).toBe( + 'string' + ); + }); + }); +}); diff --git a/packages/react-storage/src/components/StorageBrowser/displayText/libraries/en/default.ts b/packages/react-storage/src/components/StorageBrowser/displayText/libraries/en/default.ts new file mode 100644 index 00000000000..9b3c7bfb97e --- /dev/null +++ b/packages/react-storage/src/components/StorageBrowser/displayText/libraries/en/default.ts @@ -0,0 +1,12 @@ +import { DefaultStorageBrowserDisplayText } from '../../types'; + +import { DEFAULT_LOCATION_DETAIL_VIEW_DISPLAY_TEXT } from './locationDetailView'; +import { DEFAULT_LOCATIONS_VIEW_DISPLAY_TEXT } from './locationsView'; +import { DEFAULT_UPLOAD_VIEW_DISPLAY_TEXT } from './uploadView'; + +export const DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT: DefaultStorageBrowserDisplayText = + { + LocationDetailView: DEFAULT_LOCATION_DETAIL_VIEW_DISPLAY_TEXT, + LocationsView: DEFAULT_LOCATIONS_VIEW_DISPLAY_TEXT, + UploadView: DEFAULT_UPLOAD_VIEW_DISPLAY_TEXT, + }; diff --git a/packages/react-storage/src/components/StorageBrowser/displayText/libraries/en/locationDetailView.ts b/packages/react-storage/src/components/StorageBrowser/displayText/libraries/en/locationDetailView.ts new file mode 100644 index 00000000000..411b9d158b9 --- /dev/null +++ b/packages/react-storage/src/components/StorageBrowser/displayText/libraries/en/locationDetailView.ts @@ -0,0 +1,16 @@ +import { DEFAULT_LIST_VIEW_DISPLAY_TEXT } from './shared'; +import { DefaultLocationDetailViewDisplayText } from '../../types'; + +export const DEFAULT_LOCATION_DETAIL_VIEW_DISPLAY_TEXT: DefaultLocationDetailViewDisplayText = + { + ...DEFAULT_LIST_VIEW_DISPLAY_TEXT, + getListResultsMessage: () => 'help me', + searchExhaustedMessage: 'Showing results for up to the first 10,000 items', + searchIncludeSubfoldersLabel: 'Include subfolders', + searchPlaceholder: 'Search current folder', + tableColumnLastModifiedHeader: 'Last modified', + tableColumnNameHeader: 'Name', + tableColumnSizeHeader: 'Size', + tableColumnTypeHeader: 'Type', + title: (_locations) => 'use _location to derive display value', + }; diff --git a/packages/react-storage/src/components/StorageBrowser/displayText/libraries/en/locationsView.ts b/packages/react-storage/src/components/StorageBrowser/displayText/libraries/en/locationsView.ts new file mode 100644 index 00000000000..5f798ecd345 --- /dev/null +++ b/packages/react-storage/src/components/StorageBrowser/displayText/libraries/en/locationsView.ts @@ -0,0 +1,12 @@ +import { DEFAULT_LIST_VIEW_DISPLAY_TEXT } from './shared'; +import { DefaultLocationsViewDisplayText } from '../../types'; + +export const DEFAULT_LOCATIONS_VIEW_DISPLAY_TEXT: DefaultLocationsViewDisplayText = + { + ...DEFAULT_LIST_VIEW_DISPLAY_TEXT, + searchPlaceholder: 'Filter files and folders', + getListResultsMessage: () => 'lol', + tableColumnBucketHeader: 'Bucket', + tableColumnFolderHeader: 'Folder', + tableColumnPermissionsHeader: 'Permissions', + }; diff --git a/packages/react-storage/src/components/StorageBrowser/displayText/libraries/en/shared.ts b/packages/react-storage/src/components/StorageBrowser/displayText/libraries/en/shared.ts new file mode 100644 index 00000000000..927976d446e --- /dev/null +++ b/packages/react-storage/src/components/StorageBrowser/displayText/libraries/en/shared.ts @@ -0,0 +1,32 @@ +import { + DefaultActionViewDisplayText, + DefaultListViewDisplayText, +} from '../../types'; + +export const DEFAULT_ACTION_VIEW_DISPLAY_TEXT: Omit< + DefaultActionViewDisplayText, + 'actionStartLabel' | 'getActionCompleteMessage' | 'title' +> = { + actionCancelLabel: 'Cancel', + actionExitLabel: 'Exit', + actionDestinationLabel: 'Destination', + statusDisplayCanceledLabel: 'Canceled', + statusDisplayCompletedLabel: 'Completed', + statusDisplayFailedLabel: 'Failed', + statusDisplayTotalLabel: 'Total', + statusDisplayQueuedLabel: 'Not Started', + // empty by default + tableColumnCancelHeader: '', + tableColumnStatusHeader: 'Status', + tableColumnFolderHeader: 'Folder', + tableColumnNameHeader: 'Name', + tableColumnTypeHeader: 'Type', + tableColumnSizeHeader: 'Size', +}; + +export const DEFAULT_LIST_VIEW_DISPLAY_TEXT: Omit< + DefaultListViewDisplayText, + 'getListResultsMessage' | 'searchPlaceholder' +> = { + searchSubmitLabel: 'Search', +}; diff --git a/packages/react-storage/src/components/StorageBrowser/displayText/libraries/en/uploadView.ts b/packages/react-storage/src/components/StorageBrowser/displayText/libraries/en/uploadView.ts new file mode 100644 index 00000000000..c65575159d3 --- /dev/null +++ b/packages/react-storage/src/components/StorageBrowser/displayText/libraries/en/uploadView.ts @@ -0,0 +1,62 @@ +import { DEFAULT_ACTION_VIEW_DISPLAY_TEXT } from './shared'; +import { DefaultUploadViewDisplayText } from '../../types'; + +export const DEFAULT_UPLOAD_VIEW_DISPLAY_TEXT: DefaultUploadViewDisplayText = { + ...DEFAULT_ACTION_VIEW_DISPLAY_TEXT, + title: 'Upload', + actionStartLabel: 'Upload', + addFilesLabel: 'Add files', + addFolderLabel: 'Add folder', + getActionCompleteMessage: (_counts) => { + // if (counts.FAILED === counts.TOTAL) { + // return 'All uploads failed to complete.'; + // } + + // if (counts.CANCELED === counts.TOTAL) { + // return 'All uploads canceled.'; + // } + + // if (counts.OVERWRITE_PREVENTED === counts.TOTAL) { + // return 'Overwrite prevention applied to all uploads.'; + // } + + // if (counts.TOTAL === counts.COMPLETE) { + // return 'All uploads completed successfully.'; + // } + + // const prefix = 'All uploads complete'; + + // const succeeded = `${counts.COMPLETE} uploads successful`; + // const overwritePrevented = `overwrite prevention applied to ${counts.OVERWRITE_PREVENTED} uploads`; + // const _canceled = `${counts.CANCELED} uploads canceled`; + // const _failed = `${counts.FAILED} uploads failed`; + + // // succeeded & errors + // // succeeded & errors & cancellations + // // succeeded & errors & cancellations & overwrite prevented + // // succeeded & cancellations + // // succeeded & cancellations & overwrite prevented + // // errors & cancellations + // // errors & cancellations & overwrite prevented + // // succeeded & cancellations & overwrite prevented + // // succeeded & overwrite prevented + // if (counts.TOTAL === counts.COMPLETE + counts.OVERWRITE_PREVENTED) { + // return `${prefix}. ${succeeded}, ${overwritePrevented}.`; + // } + + // const hasErrors = counts.FAILED > 0; + // const _hasCanceledTasks = counts.CANCELED > 0; + + // if (hasErrors) { + // return `All uploads complete. ${counts.COMPLETE} of ${counts.TOTAL} uploads successful, ${counts.FAILED} uploads failed to complete.`; + // } + + return '🤷'; + }, + statusDisplayCanceledLabel: 'Canceled', + statusDisplayCompletedLabel: 'Completed', + statusDisplayFailedLabel: 'Failed', + statusDisplayOverridePreventedLabel: 'Overwrite prevented', + statusDisplayQueuedLabel: 'Not Started', + overwriteExistingLabel: 'Overwrite existing files', +}; diff --git a/packages/react-storage/src/components/StorageBrowser/displayText/libraries/index.ts b/packages/react-storage/src/components/StorageBrowser/displayText/libraries/index.ts new file mode 100644 index 00000000000..56dfd99703b --- /dev/null +++ b/packages/react-storage/src/components/StorageBrowser/displayText/libraries/index.ts @@ -0,0 +1 @@ +export { DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT } from './en/default'; diff --git a/packages/react-storage/src/components/StorageBrowser/displayText/types.ts b/packages/react-storage/src/components/StorageBrowser/displayText/types.ts new file mode 100644 index 00000000000..85f686235e2 --- /dev/null +++ b/packages/react-storage/src/components/StorageBrowser/displayText/types.ts @@ -0,0 +1,84 @@ +import { StatusCounts } from '../tasks'; +import { LocationData, LocationItemData } from '../actions'; + +/** + * Common display text values available on each action view (e.g. upload, copy, etc) + */ +export interface DefaultActionViewDisplayText { + actionCancelLabel: string; + actionDestinationLabel: string; + actionExitLabel: string; + actionStartLabel: string; + getActionCompleteMessage: (counts: StatusCounts) => string; + statusDisplayCanceledLabel: string; + statusDisplayCompletedLabel: string; + statusDisplayFailedLabel: string; + statusDisplayQueuedLabel: string; + statusDisplayTotalLabel: string; + title: string; + tableColumnCancelHeader: string; + tableColumnStatusHeader: string; + tableColumnFolderHeader: string; + tableColumnNameHeader: string; + tableColumnTypeHeader: string; + tableColumnSizeHeader: string; +} + +/** + * Common list view display text values + */ +export interface DefaultListViewDisplayText { + searchPlaceholder: string; + searchSubmitLabel: string; + getListResultsMessage: (data: T, error?: Error) => string; +} + +export interface DefaultLocationsViewDisplayText + extends DefaultListViewDisplayText { + tableColumnFolderHeader: string; + tableColumnBucketHeader: string; + tableColumnPermissionsHeader: string; +} + +export interface DefaultLocationDetailViewDisplayText + extends DefaultListViewDisplayText { + title: string | ((location: LocationData) => string); + searchExhaustedMessage: string; + searchIncludeSubfoldersLabel: string; + tableColumnLastModifiedHeader: string; + tableColumnNameHeader: string; + tableColumnSizeHeader: string; + tableColumnTypeHeader: string; +} + +export interface DefaultUploadViewDisplayText + extends DefaultActionViewDisplayText { + addFilesLabel: string; + addFolderLabel: string; + statusDisplayOverridePreventedLabel: string; + overwriteExistingLabel: string; +} + +export interface DefaultStorageBrowserDisplayText { + LocationsView: DefaultLocationsViewDisplayText; + LocationDetailView: DefaultLocationDetailViewDisplayText; + UploadView: DefaultUploadViewDisplayText; + // CopyView + // DeleteView + // CreateFolderView +} + +interface LocationsViewDisplayText + extends Partial {} +interface LocationDetailViewDisplayText + extends Partial {} +interface UploadViewDisplayText extends Partial {} + +export interface StorageBrowserDisplayText { + LocationsView?: LocationsViewDisplayText; + LocationDetailView?: LocationDetailViewDisplayText; + UploadView?: UploadViewDisplayText; + // CopyView + // DeleteView + // CreateFolderView +}