resolve folder inside shared drive (#6093)

also ignore shortcuts to folders
and simplify

closes #6089

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Merlijn Vos <merlijn@soverin.net>
This commit is contained in:
Mikael Finstad 2025-12-05 22:45:00 +07:00 committed by GitHub
parent 943ed7ad56
commit 50e242098b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 40 additions and 17 deletions

View file

@ -0,0 +1,6 @@
---
"@uppy/google-drive-picker": patch
"@uppy/provider-views": patch
---
Improve Google Drive Picker folder picking: Resolve also folders inside shared drives (but not symlinks to folders)

View file

@ -226,15 +226,39 @@ export async function showDrivePicker({
throw new InvalidTokenError() throw new InvalidTokenError()
} }
async function listFilesInDriveFolder({ async function handleDocObjectRecursively({
doc, doc,
token, token,
signal, signal,
}: { }: {
doc: PickedItemBase doc: {
id: string
name: string
mimeType: string
shortcutDetails?: { targetMimeType: string }
}
token: string token: string
signal?: AbortSignal signal?: AbortSignal
}): Promise<PickedDriveItem[]> { }): Promise<PickedDriveItem[]> {
if (doc.mimeType === 'application/vnd.google-apps.shortcut') {
if (
doc.shortcutDetails?.targetMimeType ===
'application/vnd.google-apps.folder'
) {
// If we were to recurse into shortcuts to folders, it could get a bit crazy. We could end up picking things outside of the user's intended scope as well as infinite loops
// If we were to just pass it through as-is, Companion would not be able to download it, so we just ignore it entirely
return []
}
// for other shortcut types, we just treat them as normal files and pass them to Companion to resolve
return [
{
platform: 'drive',
id: doc.id,
name: doc.name,
mimeType: doc.mimeType,
},
]
}
if (doc.mimeType !== 'application/vnd.google-apps.folder') { if (doc.mimeType !== 'application/vnd.google-apps.folder') {
return [ return [
{ {
@ -253,7 +277,10 @@ export async function showDrivePicker({
do { do {
const params = new URLSearchParams({ const params = new URLSearchParams({
q: `'${doc.id.replace(/'/g, "\\'")}' in parents and trashed = false`, q: `'${doc.id.replace(/'/g, "\\'")}' in parents and trashed = false`,
fields: 'nextPageToken, files(id, name, mimeType)', fields:
'nextPageToken, files(id, name, mimeType, shortcutDetails(targetMimeType))',
includeItemsFromAllDrives: 'true',
supportsAllDrives: 'true',
pageSize: '1000', pageSize: '1000',
...(pageToken && { pageToken }), ...(pageToken && { pageToken }),
}) })
@ -273,7 +300,7 @@ export async function showDrivePicker({
for (const file of json.files) { for (const file of json.files) {
items.push( items.push(
...(await listFilesInDriveFolder({ doc: file, token, signal })), ...(await handleDocObjectRecursively({ doc: file, token, signal })),
) )
} }
} while (pageToken) } while (pageToken)
@ -287,21 +314,11 @@ export async function showDrivePicker({
try { try {
onLoadingChange(true) onLoadingChange(true)
// console.log('Picker response', JSON.stringify(picked, null, 2));
const results: PickedDriveItem[] = [] const results: PickedDriveItem[] = []
for (const doc of picked.docs) { for (const doc of picked.docs) {
if (doc.mimeType === 'application/vnd.google-apps.folder') { results.push(
results.push( ...(await handleDocObjectRecursively({ doc, token, signal })),
...(await listFilesInDriveFolder({ doc, token, signal })), )
)
} else {
results.push({
platform: 'drive',
id: doc.id,
name: doc.name,
mimeType: doc.mimeType,
})
}
} }
onFilesPicked(results, token) onFilesPicked(results, token)
} catch (err) { } catch (err) {