浏览代码

@uppy/google-photos: fix various issues (#5275)

Fixes: https://github.com/transloadit/uppy/pull/5061#issuecomment-2188717555

Also change the type of `UppyFile.name`, because it can be `undefined`.
Mikael Finstad 10 月之前
父节点
当前提交
d536a3525f

+ 3 - 2
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()
       ])
 

+ 4 - 2
packages/@uppy/core/src/Restricter.ts

@@ -148,7 +148,7 @@ class Restricter<M extends Meta, B extends Body> {
       throw new RestrictionError(
         this.getI18n()('exceedsSize', {
           size: prettierBytes(maxFileSize),
-          file: file.name,
+          file: file.name ?? this.getI18n()('unnamed'),
         }),
         { file } as { file: UppyFile<M, B> },
       )
@@ -191,7 +191,9 @@ class Restricter<M extends Meta, B extends Body> {
     error: RestrictionError<M, B>
   } {
     const error = new RestrictionError<M, B>(
-      this.getI18n()('missingRequiredMetaFieldOnFile', { fileName: file.name }),
+      this.getI18n()('missingRequiredMetaFieldOnFile', {
+        fileName: file.name ?? this.getI18n()('unnamed'),
+      }),
     )
     const { requiredMetaFields } = this.getOpts().restrictions
     const missingFields: string[] = []

+ 3 - 1
packages/@uppy/core/src/Uppy.ts

@@ -1021,7 +1021,9 @@ export class Uppy<M extends Meta, B extends Body = Record<string, never>> {
           this.checkIfFileAlreadyExists(newFile.id)
         ) {
           throw new RestrictionError(
-            this.i18n('noDuplicates', { fileName: newFile.name }),
+            this.i18n('noDuplicates', {
+              fileName: newFile.name ?? this.i18n('unnamed'),
+            }),
             { file: fileToAdd },
           )
         }

+ 3 - 1
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,
       })

+ 5 - 2
packages/@uppy/provider-views/src/Breadcrumbs.tsx

@@ -8,12 +8,13 @@ type BreadcrumbsProps<M extends Meta, B extends Body> = {
   title: string
   breadcrumbsIcon: h.JSX.Element
   breadcrumbs: PartialTreeFolder[]
+  i18n: any
 }
 
 export default function Breadcrumbs<M extends Meta, B extends Body>(
   props: BreadcrumbsProps<M, B>,
 ): h.JSX.Element {
-  const { openFolder, title, breadcrumbsIcon, breadcrumbs } = props
+  const { openFolder, title, breadcrumbsIcon, breadcrumbs, i18n } = props
 
   return (
     <div className="uppy-Provider-breadcrumbs">
@@ -26,7 +27,9 @@ export default function Breadcrumbs<M extends Meta, B extends Body>(
             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')}
           </button>
           {breadcrumbs.length === index + 1 ? '' : ' / '}
         </Fragment>

+ 4 - 2
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 (
     <li
@@ -41,11 +43,11 @@ function GridItem({
       />
       <label
         htmlFor={file.id}
-        aria-label={file.data.name}
+        aria-label={file.data.name ?? i18n('unnamed')}
         className="uppy-u-reset uppy-ProviderBrowserItem-inner"
       >
         <ItemIcon itemIconString={file.data.thumbnail || file.data.icon} />
-        {showTitles && file.data.name}
+        {showTitles && (file.data.name ?? i18n('unnamed'))}
         {children}
       </label>
     </li>

+ 7 - 3
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'),
+            })}
           >
             <div className="uppy-ProviderBrowserItem-iconWrap">
               <ItemIcon itemIconString={file.data.icon} />
@@ -83,7 +87,7 @@ export default function ListItem({
             <div className="uppy-ProviderBrowserItem-iconWrap">
               <ItemIcon itemIconString={file.data.icon} />
             </div>
-            {showTitles && file.data.name}
+            {showTitles && (file.data.name ?? i18n('unnamed'))}
           </label>
 
       }

+ 1 - 0
packages/@uppy/provider-views/src/ProviderView/Header.tsx

@@ -36,6 +36,7 @@ export default function Header<M extends Meta, B extends Body>(
             breadcrumbs={props.breadcrumbs}
             breadcrumbsIcon={props.pluginIcon && props.pluginIcon()}
             title={props.title}
+            i18n={props.i18n}
           />
         )}
         <User

+ 3 - 2
packages/@uppy/provider-views/src/ProviderView/ProviderView.tsx

@@ -390,8 +390,9 @@ export default class ProviderView<M extends Meta, B extends Body> {
       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,
         )
       )
 

+ 1 - 1
packages/@uppy/transloadit/src/Client.ts

@@ -159,7 +159,7 @@ export default class Client<M extends Meta, B extends Body> {
     }
     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}`

+ 1 - 1
packages/@uppy/utils/src/CompanionFile.ts

@@ -3,7 +3,7 @@
  */
 export type CompanionFile = {
   id: string
-  name: string
+  name?: string
   /*
    * Url to the thumbnail icon
    */

+ 1 - 1
packages/@uppy/utils/src/UppyFile.ts

@@ -16,7 +16,7 @@ export interface UppyFile<M extends Meta, B extends Body> {
   isRemote: boolean
   isGhost: boolean
   meta: InternalMetadata & M
-  name: string
+  name?: string
   preview?: string
   progress: FileProgress
   missingRequiredMetaFields?: string[]

+ 9 - 4
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<any, any>,
+  file: Omit<MinimalRequiredUppyFile<any, any>, 'name'> &
+    Pick<UppyFile<any, any>, '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<any, any>): boolean {
+function hasFileStableId(
+  file: Omit<MinimalRequiredUppyFile<any, any>, 'name'> &
+    Pick<UppyFile<any, any>, '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<any, any>): boolean {
 }
 
 export function getSafeFileId(
-  file: MinimalRequiredUppyFile<any, any>,
+  file: Omit<MinimalRequiredUppyFile<any, any>, 'name'> &
+    Pick<UppyFile<any, any>, 'name'>,
   instanceId: string,
 ): string {
   if (hasFileStableId(file)) return file.id!