Skip to content

feat(cozy-sharing): Show shared drive links#3032

Merged
doubleface merged 3 commits into
masterfrom
feat/readSharedDriveLinks
Jun 15, 2026
Merged

feat(cozy-sharing): Show shared drive links#3032
doubleface merged 3 commits into
masterfrom
feat/readSharedDriveLinks

Conversation

@doubleface

@doubleface doubleface commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

https://app.notion.com/p/linagora/LINKS-on-reciver-side-doen-t-work-37c62718bad1801c8041e23d64eae181

Needs next cozy-stack-client with linagora/cozy-client#1689

Summary by CodeRabbit

Release Notes

  • New Features

    • Added automatic link prefetching for shared drives to improve responsiveness when opening sharing dialogs.
  • Bug Fixes

    • Improved shared drive link creation to automatically recover from conflicts by fetching and reusing existing sharing links instead of failing.

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

SharingProvider gains a new fetchSharedDriveSharingLinks(document) method that retrieves drive-scoped permission links by document id, dispatches newly discovered ones to the store, and returns the full fetched list. This method is exposed through SharingContext. shareByLink is updated with a try/catch that, on HTTP 409 for shared-drive documents, calls fetchSharedDriveSharingLinks and returns the first existing permission instead of propagating the error. getFederatedShareLink is fixed to resolve the document id via document._id || document.id. FederatedFolderModal adds a useEffect that prefetches shared-drive sharing links on mount when the document has a driveId and no permissions are loaded yet, guarding against duplicate fetches. The cozy-client dependency is bumped to ^60.28.0.

Possibly related PRs

  • linagora/cozy-libs#3022: Modifies FederatedFolderModal.jsx with the same document._id || document.id pattern and shared-drive link computation logic that this PR also touches.
  • linagora/cozy-libs#3023: Also modifies FederatedFolderModal.jsx and its spec file for shared-drive-specific behavior changes in the same modal component.

Suggested reviewers

  • rezk2ll
  • zatteo
  • JF-Cozy
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main feature: introducing functionality to display shared drive links in the cozy-sharing package, which is the primary objective of this PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/readSharedDriveLinks

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@doubleface doubleface changed the title feat(sharing): Show shared drive links feat(cozy-sharing): Show shared drive links Jun 12, 2026
@doubleface doubleface marked this pull request as draft June 12, 2026 14:20
Comment thread packages/cozy-sharing/src/SharingProvider.jsx Outdated
@doubleface doubleface force-pushed the feat/readSharedDriveLinks branch from 4bc9c7d to 971c2ae Compare June 15, 2026 08:29
Track the current fetch attempt per document so the federated folder
modal does not refetch indefinitely when fetched permissions stay
unindexed.
@doubleface doubleface force-pushed the feat/readSharedDriveLinks branch from 971c2ae to 2e1a2cf Compare June 15, 2026 08:46
@doubleface doubleface marked this pull request as ready for review June 15, 2026 08:55
@doubleface doubleface requested a review from rezk2ll June 15, 2026 08:55

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/cozy-sharing/src/SharingProvider.jsx (1)

451-453: Inconsistent input format for addSharingLink action may reduce code clarity.

Line 381 passes a single permission object (resp.data), while line 451-453 passes an array of permissions. The reducer handles both formats via an Array.isArray() check, so the code works correctly, but this inconsistency could confuse maintainers. Consider normalizing the input format at the call sites (e.g., always passing an array, or wrapping single objects) for clearer intent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cozy-sharing/src/SharingProvider.jsx` around lines 451 - 453, The
addSharingLink action is being called with inconsistent input formats across the
codebase—sometimes with a single permission object and sometimes with an array
of permissions. Normalize the input format at all call sites of addSharingLink
to use a consistent approach (either always passing an array, or always wrapping
single objects in an array). This will eliminate the need for the
Array.isArray() check in the reducer and make the expected input format
immediately clear to maintainers.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@packages/cozy-sharing/src/components/FederatedFolder/FederatedFolderModal.jsx`:
- Around line 189-218: The useEffect hook that fetches sharing links performs
state updates in the finally block even if the component unmounts before the
promise settles, causing React warnings. Add a cleanup mechanism to prevent
state updates after unmount by either using an AbortController to cancel the
fetch operation or by tracking a mounted flag with a ref that gets set to false
in the cleanup function returned by the effect. Before calling
setFetchedSharingLinksDocumentId and setIsFetchingSharingLinks in the finally
block, check the abort signal status or mounted flag to ensure the component is
still mounted before performing the state updates.

In
`@packages/cozy-sharing/src/components/FederatedFolder/FederatedFolderModal.spec.jsx`:
- Around line 287-294: The test assertion
`expect(mockFetchSharedDriveSharingLinks).toHaveBeenCalledTimes(1)` immediately
after the `rerender()` call may execute before the `useEffect` hook runs,
causing the test to miss a real duplicate-fetch regression. Wrap the assertion
in an asynchronous utility like `waitFor()` to ensure the component's
`useEffect` has completed and the mock call count is stable before verifying
that the fetch was only called once after the rerender.

---

Nitpick comments:
In `@packages/cozy-sharing/src/SharingProvider.jsx`:
- Around line 451-453: The addSharingLink action is being called with
inconsistent input formats across the codebase—sometimes with a single
permission object and sometimes with an array of permissions. Normalize the
input format at all call sites of addSharingLink to use a consistent approach
(either always passing an array, or always wrapping single objects in an array).
This will eliminate the need for the Array.isArray() check in the reducer and
make the expected input format immediately clear to maintainers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8eef2511-80ca-415c-b543-05f7b3ac4f54

📥 Commits

Reviewing files that changed from the base of the PR and between 05ad9dd and a7000b7.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (5)
  • packages/cozy-sharing/package.json
  • packages/cozy-sharing/src/SharingProvider.jsx
  • packages/cozy-sharing/src/SharingProvider.spec.jsx
  • packages/cozy-sharing/src/components/FederatedFolder/FederatedFolderModal.jsx
  • packages/cozy-sharing/src/components/FederatedFolder/FederatedFolderModal.spec.jsx

Comment on lines +189 to +218
useEffect(() => {
if (!existingDocument?.driveId) return
if (!documentId) return
if (!fetchSharedDriveSharingLinks) return
if (documentPermissions.length > 0) return
if (isFetchingSharingLinks) return
if (fetchedSharingLinksDocumentId === documentId) return

const fetchSharingLinks = async () => {
setIsFetchingSharingLinks(true)

try {
await fetchSharedDriveSharingLinks(existingDocument)
} catch (error) {
log.error('Failed to fetch shared drive sharing links', error)
} finally {
setFetchedSharingLinksDocumentId(documentId)
setIsFetchingSharingLinks(false)
}
}

fetchSharingLinks()
}, [
documentId,
existingDocument,
documentPermissions.length,
fetchedSharingLinksDocumentId,
fetchSharedDriveSharingLinks,
isFetchingSharingLinks
])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Avoid state updates after unmount in the async prefetch effect.

If the modal closes before fetchSharedDriveSharingLinks settles, the finally block still calls setState, which can trigger React “update on unmounted component” warnings.

Suggested fix
 useEffect(() => {
+  let isMounted = true
+
   if (!existingDocument?.driveId) return
   if (!documentId) return
   if (!fetchSharedDriveSharingLinks) return
   if (documentPermissions.length > 0) return
   if (isFetchingSharingLinks) return
   if (fetchedSharingLinksDocumentId === documentId) return

   const fetchSharingLinks = async () => {
-    setIsFetchingSharingLinks(true)
+    if (isMounted) setIsFetchingSharingLinks(true)

     try {
       await fetchSharedDriveSharingLinks(existingDocument)
     } catch (error) {
       log.error('Failed to fetch shared drive sharing links', error)
     } finally {
-      setFetchedSharingLinksDocumentId(documentId)
-      setIsFetchingSharingLinks(false)
+      if (isMounted) {
+        setFetchedSharingLinksDocumentId(documentId)
+        setIsFetchingSharingLinks(false)
+      }
     }
   }

   fetchSharingLinks()
+
+  return () => {
+    isMounted = false
+  }
 }, [
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
useEffect(() => {
if (!existingDocument?.driveId) return
if (!documentId) return
if (!fetchSharedDriveSharingLinks) return
if (documentPermissions.length > 0) return
if (isFetchingSharingLinks) return
if (fetchedSharingLinksDocumentId === documentId) return
const fetchSharingLinks = async () => {
setIsFetchingSharingLinks(true)
try {
await fetchSharedDriveSharingLinks(existingDocument)
} catch (error) {
log.error('Failed to fetch shared drive sharing links', error)
} finally {
setFetchedSharingLinksDocumentId(documentId)
setIsFetchingSharingLinks(false)
}
}
fetchSharingLinks()
}, [
documentId,
existingDocument,
documentPermissions.length,
fetchedSharingLinksDocumentId,
fetchSharedDriveSharingLinks,
isFetchingSharingLinks
])
useEffect(() => {
let isMounted = true
if (!existingDocument?.driveId) return
if (!documentId) return
if (!fetchSharedDriveSharingLinks) return
if (documentPermissions.length > 0) return
if (isFetchingSharingLinks) return
if (fetchedSharingLinksDocumentId === documentId) return
const fetchSharingLinks = async () => {
if (isMounted) setIsFetchingSharingLinks(true)
try {
await fetchSharedDriveSharingLinks(existingDocument)
} catch (error) {
log.error('Failed to fetch shared drive sharing links', error)
} finally {
if (isMounted) {
setFetchedSharingLinksDocumentId(documentId)
setIsFetchingSharingLinks(false)
}
}
}
fetchSharingLinks()
return () => {
isMounted = false
}
}, [
documentId,
existingDocument,
documentPermissions.length,
fetchedSharingLinksDocumentId,
fetchSharedDriveSharingLinks,
isFetchingSharingLinks
])
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/cozy-sharing/src/components/FederatedFolder/FederatedFolderModal.jsx`
around lines 189 - 218, The useEffect hook that fetches sharing links performs
state updates in the finally block even if the component unmounts before the
promise settles, causing React warnings. Add a cleanup mechanism to prevent
state updates after unmount by either using an AbortController to cancel the
fetch operation or by tracking a mounted flag with a ref that gets set to false
in the cleanup function returned by the effect. Before calling
setFetchedSharingLinksDocumentId and setIsFetchingSharingLinks in the finally
block, check the abort signal status or mounted flag to ensure the component is
still mounted before performing the state updates.

Comment on lines +287 to +294
rerender(
<AppLike client={client} sharingContextValue={sharingContextValue}>
<FederatedFolderModal document={document} onClose={mockOnClose} />
</AppLike>
)

expect(mockFetchSharedDriveSharingLinks).toHaveBeenCalledTimes(1)
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Make the post-rerender “no refetch” check asynchronous.

The immediate toHaveBeenCalledTimes(1) can pass before useEffect after rerender runs, so this test can miss a real duplicate-fetch regression.

Suggested fix
       rerender(
         <AppLike client={client} sharingContextValue={sharingContextValue}>
           <FederatedFolderModal document={document} onClose={mockOnClose} />
         </AppLike>
       )

-      expect(mockFetchSharedDriveSharingLinks).toHaveBeenCalledTimes(1)
+      await waitFor(() => {
+        expect(mockFetchSharedDriveSharingLinks).toHaveBeenCalledTimes(1)
+      })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/cozy-sharing/src/components/FederatedFolder/FederatedFolderModal.spec.jsx`
around lines 287 - 294, The test assertion
`expect(mockFetchSharedDriveSharingLinks).toHaveBeenCalledTimes(1)` immediately
after the `rerender()` call may execute before the `useEffect` hook runs,
causing the test to miss a real duplicate-fetch regression. Wrap the assertion
in an asynchronous utility like `waitFor()` to ensure the component's
`useEffect` has completed and the mock call count is stable before verifying
that the fetch was only called once after the rerender.

@doubleface doubleface merged commit 0d93ae5 into master Jun 15, 2026
3 checks passed
@doubleface doubleface deleted the feat/readSharedDriveLinks branch June 15, 2026 09:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants