feat:(PB-6297) download and preview individual items in public shared folder - #2054
feat:(PB-6297) download and preview individual items in public shared folder#2054victor-ferro wants to merge 12 commits into
Conversation
9c0ef9b to
87247c8
Compare
Deploying drive-web with
|
| Latest commit: |
6f83655
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://2427487e.drive-web.pages.dev |
| Branch Preview URL: | https://pb-6297-preview-download.drive-web.pages.dev |
…terators New-code coverage was failing the SonarCloud quality gate (75% vs 80% required). Adds tests for the untested useWarnBeforeUnload hook and for the previously uncovered lines in share.service.ts: the folders/files iterator factories passed to downloadFolderAsZip, and the happy/error paths of downloadPublicSharedFolder.
# Conflicts: # src/views/PublicShared/hooks/usePublicSharedFolderContent.ts
# Conflicts: # src/views/PublicShared/components/PublicSharedFolderContent.tsx # src/views/PublicShared/components/PublicSharedItemList.tsx # src/views/PublicShared/hooks/usePublicSharedFolderContent.ts
| downloadFile({ | ||
| bucketId: (shareItem as unknown as DriveFileData).bucket, | ||
| fileId: (shareItem as unknown as DriveFileData).fileId, | ||
| creds: shareCredentials, | ||
| key: publicShareKey, | ||
| options: { | ||
| notifyProgress: (totalBytes, downloadedBytes) => { | ||
| setPreviewProgress(downloadedBytes / totalBytes); | ||
| }, | ||
| }, | ||
| }) | ||
| .then((fileStream) => binaryStreamToBlob(fileStream, shareItem.type || '')) | ||
| .then((fileBlob) => { | ||
| setPreviewBlob(fileBlob); | ||
| }) |
There was a problem hiding this comment.
need to verify that the downloaded item is the same as actually opened, this can cause that user press one item, close instantalnealy, open another, and flash the preview of first item until the second is downloaded
| if (!isTypeAllowed(shareItem) || !isFileSizePreviewable(Number(shareItem.size))) return; | ||
|
|
||
| downloadFile({ | ||
| bucketId: (shareItem as unknown as DriveFileData).bucket, |
There was a problem hiding this comment.
avoid as unknown cast outside of tests
There was a problem hiding this comment.
Done! It's been detected that the AdvancedSharedItem type doesn't have fileId because the SharedFiles imported from the SDK has a field called 'fileiId' but doesn't have 'fileId'
| const downloadItems = (itemsToDownload: AdvancedSharedItem[]) => { | ||
| if (isDownloading || itemsToDownload.length === 0 || !shareCredentials) return; | ||
|
|
||
| setIsDownloading(true); | ||
|
|
||
| downloadPublicSharedItems({ | ||
| items: itemsToDownload, | ||
| credentials: shareCredentials, | ||
| key: publicShareKey, | ||
| code, | ||
| resourcesToken: nextLevelToken, | ||
| }) | ||
| .catch((err) => { | ||
| errorService.reportError(err); | ||
| notificationsService.show({ text: errorService.castError(err).message, type: ToastType.Error }); | ||
| }) | ||
| .finally(() => { | ||
| setIsDownloading(false); | ||
| }); | ||
| }; |
There was a problem hiding this comment.
I would extract all the download logic added for previewing into a hook
| return confirmationMessage; // WebKit, Chrome <34 | ||
| }; | ||
|
|
||
| const useWarnBeforeUnload = (isActive: boolean): void => { |
There was a problem hiding this comment.
this hook already exists: useBeforeUnload.ts
There was a problem hiding this comment.
I hadn't seen it. The functionality I put into the hook was also being used in other places, and I thought there wasn't already an existing hook for this. My bad!!
Done!
| return `${item.plainName ?? item.name}${extension}`; | ||
| }; | ||
|
|
||
| export async function downloadPublicSharedItems({ |
There was a problem hiding this comment.
Doesn't the DownloadManager cover this?
There was a problem hiding this comment.
True, it can be done, but it touches several things in the main download flow. Because for public downloads we'd run into some blockers:
- generateTasksForItem calls localStorageService.getUser() and throws 'User not found' before even looking at downloadCredentials, so anonymous visitors crash right away.
- Progress is reported through tasksService, and TaskLogger is only mounted in HeaderAndSidenavLayout — an anonymous user would get a download with zero feedback, and the preview UI here doesn't read from tasks.
- Single files go through the download worker, and postMessage turns the { bucketKey: Buffer } key (new sharing version) into a plain Uint8Array, which the network crypto won't accept without re-hydrating it in the worker.
If you want me to get started on it, I will. But maybe it might be work for a separate ticket
There was a problem hiding this comment.
Okay, so we’ll have to create a task to decouple DownloadManager from everything that isn’t handle ‘download', because, as we have seen, it does not allow us to reuse it 😞
Moves download and preview state out of PublicSharedFolderContent into usePublicSharedDownload, discarding stale preview downloads when the preview is closed or replaced, and removes 'as unknown as' casts by typing fileId on AdvancedSharedItem and narrowing helper signatures.
| @@ -0,0 +1,102 @@ | |||
| /** | |||
| * @jest-environment jsdom | |||
| */ | |||
There was a problem hiding this comment.
we don't use jest, this tag is not necessary
| @@ -0,0 +1,267 @@ | |||
| /** | |||
| * @jest-environment jsdom | |||
| */ | |||
There was a problem hiding this comment.
same here, we don't use jest
|



Description
Third and final part of PB-6297, stacked on #2053. The public shared folder preview becomes actionable: items can now be downloaded individually (or in multi-selection) and files can be previewed in the viewer, all without authentication.
Per-item download
downloadPublicSharedItems(new inshare.service.ts): generalizes the existing root-folder download to any selection — a single file downloads directly (stream → blob → save), a single folder zips through the public iterators, and a mixed selection packs everything into one zip.downloadPublicSharedFolderis now a thin wrapper over it (same behavior as before for the main Download button).beforeunloadwarning while a download is in flight.File preview
FileViewerwith the decrypted blob, download progress, and the same gates asShareFileView: previewable type and size limit — otherwise the viewer opens with its fallback without fetching the blob.TopBarActionsgets a dedicated share-view variant: Download + Report (reusinghandleReportShare, now exported fromReportButton). This also removes a dead branch: the old copy-link button was unreachable in share views. Phosphor deprecated icon names updated (DotsThreeIcon,WarningCircleIcon).Cleanups (code created earlier in this stack)
usePublicSharedFolderContent:fetchFolders/fetchFilesmerged into a singlefetchLevelItems(type)— same phase machine (folders per level, then files), ~20 duplicated lines removed. Test assertions updated accordingly.useWarnBeforeUnload(new hook): replaces the three identicalhandleLeavePage+beforeunloadeffect copies inShareFolderView,ShareFileViewand the new preview; also fixes the effect depending only onprogressinstead of the full active condition.isTypeAllowednow reusesgetIsTypeAllowedAndFileExtensionGroupValuesfromfileViewerUtils(also fixes uppercase extensions being rejected).ShareLayout: user menu dropdown getsz-50so it stays above the new preview content.Related Issues
Relates to PB-6297.
Related Pull Requests
PB-6297-thumbnails), which is stacked on feat:(PB-6297) preview public shared folder contents #2052 — merge in order: feat:(PB-6297) preview public shared folder contents #2052 → feat:(PB-6297) show image thumbnails in public shared folder preview #2053 → this one.Checklist
Testing Process
yarn vitest run src/app/share/services/share.service.test.ts— three new cases fordownloadPublicSharedItems(single file with share credentials/key and plain name, single folder zipped through the public iterators, mixed selection packed into one zip closed at the end). Hook tests updated for the unified fetch.yarn typecheckandyarn lintclean; full unit suite run by the pre-commit hook.