mirror of
https://github.com/transloadit/uppy.git
synced 2026-07-17 16:50:22 +00:00
allow selecting folders (#6074)
for google drive #5532 --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
4817585b66
commit
e6613488fc
4 changed files with 94 additions and 8 deletions
5
.changeset/lazy-games-pump.md
Normal file
5
.changeset/lazy-games-pump.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
"@uppy/provider-views": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Allow selecting folders with Google Drive Picker. They will be recursively resolved.
|
||||||
|
|
@ -105,6 +105,11 @@ export default function GooglePickerView({
|
||||||
appId,
|
appId,
|
||||||
onFilesPicked,
|
onFilesPicked,
|
||||||
signal,
|
signal,
|
||||||
|
onLoadingChange: (isLoading: boolean) => setLoading(isLoading),
|
||||||
|
onError: (err: unknown) => {
|
||||||
|
uppy.log(err)
|
||||||
|
uppy.info(i18n('failedToAddFiles'), 'error')
|
||||||
|
},
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// photos
|
// photos
|
||||||
|
|
@ -175,6 +180,7 @@ export default function GooglePickerView({
|
||||||
pickerType,
|
pickerType,
|
||||||
setAccessToken,
|
setAccessToken,
|
||||||
uppy,
|
uppy,
|
||||||
|
i18n,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -209,12 +209,16 @@ export async function showDrivePicker({
|
||||||
appId,
|
appId,
|
||||||
onFilesPicked,
|
onFilesPicked,
|
||||||
signal,
|
signal,
|
||||||
|
onLoadingChange,
|
||||||
|
onError,
|
||||||
}: {
|
}: {
|
||||||
token: string
|
token: string
|
||||||
apiKey: string
|
apiKey: string
|
||||||
appId: string
|
appId: string
|
||||||
onFilesPicked: (files: PickedItem[], accessToken: string) => void
|
onFilesPicked: (files: PickedItem[], accessToken: string) => void
|
||||||
signal: AbortSignal | undefined
|
signal: AbortSignal | undefined
|
||||||
|
onLoadingChange: (loading: boolean) => void
|
||||||
|
onError: (err: unknown) => void
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
// google drive picker will crash hard if given an invalid token, so we need to check it first
|
// google drive picker will crash hard if given an invalid token, so we need to check it first
|
||||||
// https://github.com/transloadit/uppy/pull/5443#pullrequestreview-2452439265
|
// https://github.com/transloadit/uppy/pull/5443#pullrequestreview-2452439265
|
||||||
|
|
@ -222,18 +226,88 @@ export async function showDrivePicker({
|
||||||
throw new InvalidTokenError()
|
throw new InvalidTokenError()
|
||||||
}
|
}
|
||||||
|
|
||||||
const onPicked = (picked: google.picker.ResponseObject) => {
|
async function listFilesInDriveFolder({
|
||||||
if (picked.action === google.picker.Action.PICKED) {
|
doc,
|
||||||
// console.log('Picker response', JSON.stringify(picked, null, 2));
|
token,
|
||||||
onFilesPicked(
|
signal,
|
||||||
picked.docs.map((doc) => ({
|
}: {
|
||||||
|
doc: PickedItemBase
|
||||||
|
token: string
|
||||||
|
signal?: AbortSignal
|
||||||
|
}): Promise<PickedDriveItem[]> {
|
||||||
|
if (doc.mimeType !== 'application/vnd.google-apps.folder') {
|
||||||
|
return [
|
||||||
|
{
|
||||||
platform: 'drive',
|
platform: 'drive',
|
||||||
id: doc.id,
|
id: doc.id,
|
||||||
name: doc.name,
|
name: doc.name,
|
||||||
mimeType: doc.mimeType,
|
mimeType: doc.mimeType,
|
||||||
})),
|
},
|
||||||
token,
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const headers = getAuthHeader(token)
|
||||||
|
const items: PickedDriveItem[] = []
|
||||||
|
let pageToken: string | undefined
|
||||||
|
|
||||||
|
do {
|
||||||
|
const params = new URLSearchParams({
|
||||||
|
q: `'${doc.id.replace(/'/g, "\\'")}' in parents and trashed = false`,
|
||||||
|
fields: 'nextPageToken, files(id, name, mimeType)',
|
||||||
|
pageSize: '1000',
|
||||||
|
...(pageToken && { pageToken }),
|
||||||
|
})
|
||||||
|
const res = await fetch(
|
||||||
|
`https://www.googleapis.com/drive/v3/files?${params.toString()}`,
|
||||||
|
{ headers, signal },
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to list folder contents for '${doc.name}' (${doc.id}): ${res.status} ${res.statusText}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const json: { nextPageToken?: string; files: PickedItemBase[] } =
|
||||||
|
await res.json()
|
||||||
|
pageToken = json.nextPageToken
|
||||||
|
|
||||||
|
for (const file of json.files) {
|
||||||
|
items.push(
|
||||||
|
...(await listFilesInDriveFolder({ doc: file, token, signal })),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} while (pageToken)
|
||||||
|
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
|
const onPicked = async (picked: google.picker.ResponseObject) => {
|
||||||
|
if (picked.action !== google.picker.Action.PICKED) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
onLoadingChange(true)
|
||||||
|
|
||||||
|
// console.log('Picker response', JSON.stringify(picked, null, 2));
|
||||||
|
const results: PickedDriveItem[] = []
|
||||||
|
for (const doc of picked.docs) {
|
||||||
|
if (doc.mimeType === 'application/vnd.google-apps.folder') {
|
||||||
|
results.push(
|
||||||
|
...(await listFilesInDriveFolder({ doc, token, signal })),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
results.push({
|
||||||
|
platform: 'drive',
|
||||||
|
id: doc.id,
|
||||||
|
name: doc.name,
|
||||||
|
mimeType: doc.mimeType,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onFilesPicked(results, token)
|
||||||
|
} catch (err) {
|
||||||
|
onError(err)
|
||||||
|
} finally {
|
||||||
|
onLoadingChange(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -248,7 +322,7 @@ export async function showDrivePicker({
|
||||||
.setIncludeFolders(true)
|
.setIncludeFolders(true)
|
||||||
// Note: setEnableDrives doesn't seem to work
|
// Note: setEnableDrives doesn't seem to work
|
||||||
// .setEnableDrives(true)
|
// .setEnableDrives(true)
|
||||||
.setSelectFolderEnabled(false)
|
.setSelectFolderEnabled(true)
|
||||||
.setMode(google.picker.DocsViewMode.LIST),
|
.setMode(google.picker.DocsViewMode.LIST),
|
||||||
)
|
)
|
||||||
// NOTE: photos is broken and results in an error being returned from Google
|
// NOTE: photos is broken and results in an error being returned from Google
|
||||||
|
|
|
||||||
|
|
@ -46,5 +46,6 @@ export default {
|
||||||
1: '%{smart_count} more files added',
|
1: '%{smart_count} more files added',
|
||||||
},
|
},
|
||||||
showErrorDetails: 'Show error details',
|
showErrorDetails: 'Show error details',
|
||||||
|
failedToAddFiles: 'Failed to add files',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue