diff --git a/packages/@uppy/companion/src/server/provider/google/googlephotos/index.js b/packages/@uppy/companion/src/server/provider/google/googlephotos/index.js index efd6831caa..54c31f642e 100644 --- a/packages/@uppy/companion/src/server/provider/google/googlephotos/index.js +++ b/packages/@uppy/companion/src/server/provider/google/googlephotos/index.js @@ -66,7 +66,7 @@ class GooglePhotos extends Provider { return paginate( (pageToken) => client.get('albums', { searchParams: { pageToken, pageSize: 50 }, responseType: 'json' }).json(), - (response) => response.albums, + (response) => response.albums ?? [], // seems to be undefined if no albums ) } @@ -85,7 +85,8 @@ class GooglePhotos extends Provider { return resp } - const [sharedAlbums, albums, { mediaItems, nextPageToken }] = await Promise.all([ + // mediaItems seems to be undefined if empty folder + const [sharedAlbums, albums, { mediaItems = [], nextPageToken }] = await Promise.all([ fetchSharedAlbums(), fetchAlbums(), fetchMediaItems() ]) diff --git a/packages/@uppy/core/src/Restricter.ts b/packages/@uppy/core/src/Restricter.ts index 663e8cb6de..a0a490890a 100644 --- a/packages/@uppy/core/src/Restricter.ts +++ b/packages/@uppy/core/src/Restricter.ts @@ -148,7 +148,7 @@ class Restricter { throw new RestrictionError( this.getI18n()('exceedsSize', { size: prettierBytes(maxFileSize), - file: file.name, + file: file.name ?? this.getI18n()('unnamed'), }), { file } as { file: UppyFile }, ) @@ -191,7 +191,9 @@ class Restricter { error: RestrictionError } { const error = new RestrictionError( - this.getI18n()('missingRequiredMetaFieldOnFile', { fileName: file.name }), + this.getI18n()('missingRequiredMetaFieldOnFile', { + fileName: file.name ?? this.getI18n()('unnamed'), + }), ) const { requiredMetaFields } = this.getOpts().restrictions const missingFields: string[] = [] diff --git a/packages/@uppy/core/src/Uppy.ts b/packages/@uppy/core/src/Uppy.ts index 52d05d8c52..e635c957d9 100644 --- a/packages/@uppy/core/src/Uppy.ts +++ b/packages/@uppy/core/src/Uppy.ts @@ -1021,7 +1021,9 @@ export class Uppy> { this.checkIfFileAlreadyExists(newFile.id) ) { throw new RestrictionError( - this.i18n('noDuplicates', { fileName: newFile.name }), + this.i18n('noDuplicates', { + fileName: newFile.name ?? this.i18n('unnamed'), + }), { file: fileToAdd }, ) } diff --git a/packages/@uppy/image-editor/src/ImageEditor.tsx b/packages/@uppy/image-editor/src/ImageEditor.tsx index 01f6e01510..7517bd2057 100644 --- a/packages/@uppy/image-editor/src/ImageEditor.tsx +++ b/packages/@uppy/image-editor/src/ImageEditor.tsx @@ -155,7 +155,9 @@ export default class ImageEditor< this.uppy.setFileState(currentImage!.id, { // Reinserting image's name and type, because .toBlob loses both. - data: new File([blob!], currentImage!.name, { type: blob!.type }), + data: new File([blob!], currentImage!.name ?? this.i18n('unnamed'), { + type: blob!.type, + }), size: blob!.size, preview: undefined, }) diff --git a/packages/@uppy/provider-views/src/Breadcrumbs.tsx b/packages/@uppy/provider-views/src/Breadcrumbs.tsx index 9e61083992..f7d1c8d205 100644 --- a/packages/@uppy/provider-views/src/Breadcrumbs.tsx +++ b/packages/@uppy/provider-views/src/Breadcrumbs.tsx @@ -8,12 +8,13 @@ type BreadcrumbsProps = { title: string breadcrumbsIcon: h.JSX.Element breadcrumbs: PartialTreeFolder[] + i18n: any } export default function Breadcrumbs( props: BreadcrumbsProps, ): h.JSX.Element { - const { openFolder, title, breadcrumbsIcon, breadcrumbs } = props + const { openFolder, title, breadcrumbsIcon, breadcrumbs, i18n } = props return (
@@ -26,7 +27,9 @@ export default function Breadcrumbs( className="uppy-u-reset uppy-c-btn" onClick={() => openFolder(folder.id)} > - {folder.type === 'root' ? title : folder.data.name} + {folder.type === 'root' ? + title + : folder.data.name ?? i18n('unnamed')} {breadcrumbs.length === index + 1 ? '' : ' / '} diff --git a/packages/@uppy/provider-views/src/Item/components/GridItem.tsx b/packages/@uppy/provider-views/src/Item/components/GridItem.tsx index 9dd3cfb1d1..74b7f7c9bc 100644 --- a/packages/@uppy/provider-views/src/Item/components/GridItem.tsx +++ b/packages/@uppy/provider-views/src/Item/components/GridItem.tsx @@ -13,6 +13,7 @@ type GridItemProps = { restrictionError: string | null showTitles: boolean children?: h.JSX.Element | null + i18n: any } function GridItem({ @@ -23,6 +24,7 @@ function GridItem({ restrictionError, showTitles, children = null, + i18n, }: GridItemProps): h.JSX.Element { return (
  • diff --git a/packages/@uppy/provider-views/src/Item/components/ListItem.tsx b/packages/@uppy/provider-views/src/Item/components/ListItem.tsx index 11ccfb47b3..b129a0d50f 100644 --- a/packages/@uppy/provider-views/src/Item/components/ListItem.tsx +++ b/packages/@uppy/provider-views/src/Item/components/ListItem.tsx @@ -52,7 +52,9 @@ export default function ListItem({ checked={file.status === 'checked'} aria-label={ file.data.isFolder ? - i18n('allFilesFromFolderNamed', { name: file.data.name }) + i18n('allFilesFromFolderNamed', { + name: file.data.name ?? i18n('unnamed'), + }) : null } disabled={isDisabled} @@ -66,7 +68,9 @@ export default function ListItem({ type="button" className="uppy-u-reset uppy-c-btn uppy-ProviderBrowserItem-inner" onClick={() => openFolder(file.id)} - aria-label={i18n('openFolderNamed', { name: file.data.name })} + aria-label={i18n('openFolderNamed', { + name: file.data.name ?? i18n('unnamed'), + })} >
    @@ -83,7 +87,7 @@ export default function ListItem({
    - {showTitles && file.data.name} + {showTitles && (file.data.name ?? i18n('unnamed'))} } diff --git a/packages/@uppy/provider-views/src/ProviderView/Header.tsx b/packages/@uppy/provider-views/src/ProviderView/Header.tsx index 2bdb4255c1..699a4ec947 100644 --- a/packages/@uppy/provider-views/src/ProviderView/Header.tsx +++ b/packages/@uppy/provider-views/src/ProviderView/Header.tsx @@ -36,6 +36,7 @@ export default function Header( breadcrumbs={props.breadcrumbs} breadcrumbsIcon={props.pluginIcon && props.pluginIcon()} title={props.title} + i18n={props.i18n} /> )} { searchString === '' ? inThisFolder : ( inThisFolder.filter( (item) => - item.data.name.toLowerCase().indexOf(searchString.toLowerCase()) !== - -1, + (item.data.name ?? this.plugin.uppy.i18n('unnamed')) + .toLowerCase() + .indexOf(searchString.toLowerCase()) !== -1, ) ) diff --git a/packages/@uppy/transloadit/src/Client.ts b/packages/@uppy/transloadit/src/Client.ts index b7e3e0511f..abc6be7a72 100644 --- a/packages/@uppy/transloadit/src/Client.ts +++ b/packages/@uppy/transloadit/src/Client.ts @@ -159,7 +159,7 @@ export default class Client { } const size = encodeURIComponent(file.size!) const uploadUrl = encodeURIComponent(file.uploadURL) - const filename = encodeURIComponent(file.name) + const filename = encodeURIComponent(file.name ?? 'Unnamed') const fieldname = 'file' const qs = `size=${size}&filename=${filename}&fieldname=${fieldname}&s3Url=${uploadUrl}` diff --git a/packages/@uppy/utils/src/CompanionFile.ts b/packages/@uppy/utils/src/CompanionFile.ts index 621837450a..03245ececf 100644 --- a/packages/@uppy/utils/src/CompanionFile.ts +++ b/packages/@uppy/utils/src/CompanionFile.ts @@ -3,7 +3,7 @@ */ export type CompanionFile = { id: string - name: string + name?: string /* * Url to the thumbnail icon */ diff --git a/packages/@uppy/utils/src/UppyFile.ts b/packages/@uppy/utils/src/UppyFile.ts index 624b0baee2..e783520f2e 100644 --- a/packages/@uppy/utils/src/UppyFile.ts +++ b/packages/@uppy/utils/src/UppyFile.ts @@ -16,7 +16,7 @@ export interface UppyFile { isRemote: boolean isGhost: boolean meta: InternalMetadata & M - name: string + name?: string preview?: string progress: FileProgress missingRequiredMetaFields?: string[] diff --git a/packages/@uppy/utils/src/generateFileID.ts b/packages/@uppy/utils/src/generateFileID.ts index 5f4e733d1a..67ce8e2eb3 100644 --- a/packages/@uppy/utils/src/generateFileID.ts +++ b/packages/@uppy/utils/src/generateFileID.ts @@ -1,4 +1,4 @@ -import type { MinimalRequiredUppyFile } from './UppyFile.js' +import type { MinimalRequiredUppyFile, UppyFile } from './UppyFile.js' import getFileType from './getFileType.ts' function encodeCharacter(character: string): string { @@ -20,7 +20,8 @@ function encodeFilename(name: string): string { * removing extra characters and adding type, size and lastModified */ export default function generateFileID( - file: MinimalRequiredUppyFile, + file: Omit, 'name'> & + Pick, 'name'>, instanceId: string, ): string { // It's tempting to do `[items].filter(Boolean).join('-')` here, but that @@ -51,7 +52,10 @@ export default function generateFileID( // If the provider has a stable, unique ID, then we can use that to identify the file. // Then we don't have to generate our own ID, and we can add the same file many times if needed (different path) -function hasFileStableId(file: MinimalRequiredUppyFile): boolean { +function hasFileStableId( + file: Omit, 'name'> & + Pick, 'name'>, +): boolean { if (!file.isRemote || !file.remote) return false // These are the providers that it seems like have stable IDs for their files. The other's I haven't checked yet. const stableIdProviders = new Set([ @@ -65,7 +69,8 @@ function hasFileStableId(file: MinimalRequiredUppyFile): boolean { } export function getSafeFileId( - file: MinimalRequiredUppyFile, + file: Omit, 'name'> & + Pick, 'name'>, instanceId: string, ): string { if (hasFileStableId(file)) return file.id!