This commit is contained in:
Florian 2026-08-28 06:13:43 +02:00 committed by GitHub
commit 02660c5678
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 161 additions and 17 deletions

View file

@ -16,7 +16,7 @@
import { onMount, tick, getContext, createEventDispatcher } from 'svelte';
import { createPicker, getAuthToken } from '$lib/utils/google-drive-picker';
import { pickAndDownloadFile } from '$lib/utils/onedrive-file-picker';
import { pickAndDownloadFiles } from '$lib/utils/onedrive-file-picker';
import { KokoroWorker } from '$lib/workers/KokoroWorker';
const dispatch = createEventDispatcher();
@ -2216,17 +2216,47 @@
}}
uploadOneDriveHandler={async (authorityType) => {
try {
const fileData = await pickAndDownloadFile(authorityType);
if (fileData) {
const file = new File([fileData.blob], fileData.name, {
type: fileData.blob.type || 'application/octet-stream'
});
await uploadFileHandler(file);
const maxFileCount = $config?.file?.max_count;
const filesData = await pickAndDownloadFiles(
authorityType,
maxFileCount
);
if (filesData && filesData.length > 0) {
if (filesData.length > 1) {
toast.success(
$i18n.t('Uploading {{count}} files from OneDrive...', {
count: filesData.length
})
);
}
for (const fileData of filesData) {
const file = new File([fileData.blob], fileData.name, {
type: fileData.blob.type || 'application/octet-stream'
});
await uploadFileHandler(file);
}
} else {
console.log('No file was selected from OneDrive');
console.log('No files were selected from OneDrive');
}
} catch (error) {
console.error('OneDrive Error:', error);
// Handle specific max file count error
if (error.message?.startsWith('MAX_FILE_COUNT_EXCEEDED:')) {
const [, count, max] = error.message.split(':');
toast.error(
$i18n.t('Selected items contain {{count}} files, but maximum is {{max}}.', {
count,
max
})
);
} else {
toast.error(
$i18n.t('OneDrive Error: {{error}}', {
error: error.message
})
);
}
}
}}
{onUpload}

View file

@ -180,6 +180,9 @@ interface PickerParams {
search: {
enabled: boolean;
};
selection?: {
mode?: 'single' | 'multiple' | 'pick';
};
typesAndSources: {
mode: string;
pivots: Record<string, boolean>;
@ -211,12 +214,18 @@ function getPickerParams(): PickerParams {
search: {
enabled: true
},
selection: {
mode: 'multiple'
},
typesAndSources: {
mode: 'files',
mode: 'all',
pivots: {
oneDrive: true,
recent: true,
myOrganization: config.getAuthorityType() === 'organizations'
shared: true,
sharedLibraries: true,
myOrganization: config.getAuthorityType() === 'organizations',
site: config.getAuthorityType() === 'organizations'
}
}
};
@ -236,10 +245,66 @@ interface OneDriveFileInfo {
driveId: string;
};
'@sharePoint.endpoint': string;
folder?: {
childCount?: number;
};
file?: {
mimeType?: string;
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: any;
}
// List all items in a folder recursively
async function listFolderContentsRecursive(
folderInfo: OneDriveFileInfo,
authorityType?: 'personal' | 'organizations',
currentPath: string = ''
): Promise<OneDriveFileInfo[]> {
const accessToken = await getToken(undefined, authorityType);
if (!accessToken) {
throw new Error('Unable to retrieve OneDrive access token.');
}
const childrenUrl = `${folderInfo['@sharePoint.endpoint']}/drives/${folderInfo.parentReference.driveId}/items/${folderInfo.id}/children`;
const response = await fetch(childrenUrl, {
headers: {
Authorization: `Bearer ${accessToken}`
}
});
if (!response.ok) {
throw new Error(`Failed to list folder contents: ${response.status} ${response.statusText}`);
}
const data = await response.json();
const items: OneDriveFileInfo[] = data.value || [];
const allFiles: OneDriveFileInfo[] = [];
// Process all items
for (const item of items) {
// Inherit the @sharePoint.endpoint from parent folder if not present
if (!item['@sharePoint.endpoint']) {
item['@sharePoint.endpoint'] = folderInfo['@sharePoint.endpoint'];
}
if (item.folder) {
// Recursively get files from subfolder
const subPath = currentPath ? `${currentPath}/${item.name}` : item.name;
const subfolderFiles = await listFolderContentsRecursive(item, authorityType, subPath);
allFiles.push(...subfolderFiles);
} else if (item.file) {
// It's a file, add it to the list
allFiles.push(item);
}
// Skip items that are neither files nor folders (e.g., packages, OneNote notebooks)
}
return allFiles;
}
// Download file from OneDrive
async function downloadOneDriveFile(
fileInfo: OneDriveFileInfo,
@ -435,20 +500,69 @@ export async function openOneDrivePicker(
});
}
// Pick and download file from OneDrive
export async function pickAndDownloadFile(
authorityType?: 'personal' | 'organizations'
): Promise<{ blob: Blob; name: string } | null> {
// Pick and download multiple files from OneDrive (with folder support)
export async function pickAndDownloadFiles(
authorityType?: 'personal' | 'organizations',
maxFileCount?: number
): Promise<{ blob: Blob; name: string }[] | null> {
const pickerResult = await openOneDrivePicker(authorityType);
if (!pickerResult || !pickerResult.items || pickerResult.items.length === 0) {
return null;
}
const selectedFile = pickerResult.items[0];
const blob = await downloadOneDriveFile(selectedFile, authorityType);
const allFiles: OneDriveFileInfo[] = [];
return { blob, name: selectedFile.name };
// First, expand folders to get all files
for (const item of pickerResult.items) {
if (item.folder) {
// It's a folder, get all files recursively
const folderFiles = await listFolderContentsRecursive(item, authorityType, item.name);
allFiles.push(...folderFiles);
} else {
// It's a file
allFiles.push(item);
}
}
// Check if any files were actually found
if (allFiles.length === 0) {
throw new Error('No files found in the selected items.');
}
// Check if the number of files exceeds the configured maximum
if (maxFileCount && allFiles.length > maxFileCount) {
throw new Error(
`MAX_FILE_COUNT_EXCEEDED:${allFiles.length}:${maxFileCount}`
);
}
// Download all files with error handling
const downloadPromises = allFiles.map(async (fileInfo) => {
const blob = await downloadOneDriveFile(fileInfo, authorityType);
return {
blob,
name: fileInfo.name
};
});
const results = await Promise.allSettled(downloadPromises);
const successful = results
.filter((r): r is PromiseFulfilledResult<{ blob: Blob; name: string }> => r.status === 'fulfilled')
.map((r) => r.value);
const failed = results.filter((r) => r.status === 'rejected');
if (failed.length > 0) {
console.warn(`Failed to download ${failed.length} out of ${allFiles.length} files from OneDrive`);
// If all downloads failed, throw error
if (successful.length === 0) {
throw new Error('Failed to download any files from OneDrive');
}
// If some succeeded, log warning but continue with successful ones
}
return successful.length > 0 ? successful : null;
}
export { downloadOneDriveFile };