Skip to content

Conversation

@reneshen0328
Copy link
Contributor

@reneshen0328 reneshen0328 commented Oct 9, 2025

What

Before this PR: cannot update permission
After this PR: updateSharedLink API call (created and used by existing contentSharingV1) is called, the updated permissions are passed in successfully, and the UI reflex the item permission is updated properly.

Testing:

Screen.Recording.2025-10-09.at.3.30.21.PM.mov

Summary by CodeRabbit

  • New Features

    • Share modal now accepts a sharing service to update shared-link permission levels and immediately reflects item and link changes.
    • Converted item data now includes top-level sharingService flags (can_set_share_access, can_share) for clearer permission UI.
  • Tests

    • Added comprehensive unit and hook tests covering sharing service behavior, permission mapping, and modal integration.

@reneshen0328 reneshen0328 requested review from a team as code owners October 9, 2025 22:28
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 9, 2025

Walkthrough

I pity the fool who misses this: a new sharing service and useSharingService hook were added, convertItemResponse now includes a top-level sharingService object, ContentSharingV2 wires and passes sharingService into UnifiedShareModal, and tests were added/updated for wiring and permissions.

Changes

Cohort / File(s) Summary
Component wiring
src/elements/content-sharing/ContentSharingV2.tsx
Imports and uses useSharingService; initializes sharingService and passes sharingService={sharingService} to UnifiedShareModal; renames destructured response fields (*FromAPI -> *FromApi) and updates state setters.
New hook
src/elements/content-sharing/hooks/useSharingService.ts
New hook useSharingService(api, item, itemId, itemType, setItem, setSharedLink) that selects file/folder API, builds itemData, creates sharing service via createSharingService, and updates item/sharedLink state on success.
Sharing service module
src/elements/content-sharing/sharingService.ts
New exports convertSharedLinkPermissions(permissionLevel) and createSharingService({ itemApiInstance, itemData, onSuccess }) which exposes changeSharedLinkPermission(permissionLevel) calling itemApiInstance.updateSharedLink.
Item conversion
src/elements/content-sharing/utils/convertItemResponse.ts
Adds top-level sharingService object to converted item data with can_set_share_access and can_share mapped from API flags.
Hook tests
src/elements/content-sharing/hooks/__tests__/useSharingService.test.ts
New tests validating useSharingService for null/invalid item, file and folder flows, API selection, creation of sharingService, and onSuccess state updates.
Service tests
src/elements/content-sharing/__tests__/sharingService.test.ts
Tests convertSharedLinkPermissions mapping and that changeSharedLinkPermission calls itemApiInstance.updateSharedLink with correct args.
Component tests
src/elements/content-sharing/__tests__/ContentSharingV2.test.tsx
Switches to renderComponent helper, globally mocks useSharingService (default sharingService: null), adds test overriding mock to supply sharingService and asserts UnifiedShareModal rendering.
Conversion tests
src/elements/content-sharing/utils/__tests__/convertItemResponse.test.ts
Updated expectations to include the new top-level sharingService flags.
Minor test formatting
src/elements/content-sharing/__tests__/useSharedLink.test.js
Consolidated a multi-line useState declaration into a single line; no behavior change.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant ContentSharingV2
  participant Hook as useSharingService
  participant ItemAPI as File/Folder API
  participant Service as sharingService
  participant Modal as UnifiedShareModal
  participant Utils as convertItemResponse

  User->>ContentSharingV2: open share UI
  ContentSharingV2->>Hook: init(api,item,id,type,setters)
  Hook->>ItemAPI: select file or folder API
  Hook->>Service: createSharingService(itemApiInstance,itemData,onSuccess)
  ContentSharingV2->>Modal: render(..., sharingService)

  note right of Modal: user changes shared link permission
  Modal->>Service: changeSharedLinkPermission(level)
  Service->>ItemAPI: updateSharedLink(itemData, permissions, onSuccess, {}, params)
  ItemAPI-->>Service: success(updatedData)
  Service->>Utils: convertItemResponse(updatedData)
  Utils-->>Hook: convertedItem, convertedSharedLink
  Hook->>ContentSharingV2: setItem(...), setSharedLink(...)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

ready-to-merge

Suggested reviewers

  • jfox-box
  • jpan-box
  • tjuanitas

Poem

I pity the fool who skips this test,
A hook, a service — code dressed its best.
Permissions mapped and modal paved the way,
State updates tidy, ain't no disarray.
🎉 Share on, champ, now ship away!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed I pity the fool who doesn’t see that this title clearly calls out the creation of a sharing service and its changeSharedLinkPermission feature, which is the core of the PR’s changes.
Description Check ✅ Passed I pity the fool who doesn’t see that the description provides clear “What” and “Testing” sections and correctly embeds the repository’s HTML comment template for ready-to-merge instructions as required.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch create-sharing-service

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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
src/elements/content-sharing/utils/convertItemResponse.ts (1)

99-99: Duplicate issue, fool!

I already flagged this permission duplication issue in the test file. The spread here creates both snake_case and camelCase versions of the same permission fields.

🧹 Nitpick comments (2)
src/elements/content-sharing/hooks/__tests__/useSharingService.test.ts (2)

92-112: Fool, this test ain't realistic enough!

Line 108 passes mockConvertedData (already converted) to onSuccessCallback, but in real usage, the callback receives raw API response data that then gets converted inside handleSuccess. This test would catch more bugs if it used raw API data.

Additionally, lines 110-111 only verify the setters were called once but don't check the actual arguments passed.

Consider this approach:

 test('should handle success callback correctly', () => {
+    const mockRawApiData = {
+        id: mockItemId,
+        permissions: { can_download: false, can_preview: true },
+        type: 'file',
+        // ... other raw API fields
+    };
     const mockConvertedData = {
         item: {
             id: mockItemId,
             permissions: { can_download: false },
         },
         sharedLink: {},
     };

-    (convertItemResponse as jest.Mock).mockReturnValue(mockConvertedData);
+    (convertItemResponse as jest.Mock).mockReturnValueOnce(mockConvertedData);
     renderHook(() =>
         useSharingService(mockApi, mockItem, mockItemId, TYPE_FILE, mockSetItem, mockSetSharedLink),
     );

     // Get the onSuccess callback that was passed to mock createSharingService
     const onSuccessCallback = (createSharingService as jest.Mock).mock.calls[0][0].onSuccess;
-    onSuccessCallback(mockConvertedData);
+    onSuccessCallback(mockRawApiData);

+    expect(convertItemResponse).toHaveBeenCalledWith(mockRawApiData);
-    expect(mockSetItem).toHaveBeenCalledTimes(1);
-    expect(mockSetSharedLink).toHaveBeenCalledTimes(1);
+    expect(mockSetItem).toHaveBeenCalledWith(expect.any(Function));
+    expect(mockSetSharedLink).toHaveBeenCalledWith(expect.any(Function));
 });

115-137: Where's the success callback test, fool?

The TYPE_FILE scenario has a success callback test (lines 92-112), but TYPE_FOLDER doesn't. You should test the success callback for folders too to ensure consistent coverage!

Add a test similar to lines 92-112:

test('should handle success callback correctly for folder', () => {
    const mockRawApiData = {
        id: mockItemId,
        permissions: { can_download: false, can_preview: true },
        type: 'folder',
        // ... other raw API fields
    };
    const mockConvertedData = {
        item: {
            id: mockItemId,
            permissions: { can_download: false },
        },
        sharedLink: {},
    };

    (convertItemResponse as jest.Mock).mockReturnValueOnce(mockConvertedData);
    renderHook(() =>
        useSharingService(mockApi, mockItem, mockItemId, TYPE_FOLDER, mockSetItem, mockSetSharedLink),
    );

    const onSuccessCallback = (createSharingService as jest.Mock).mock.calls[0][0].onSuccess;
    onSuccessCallback(mockRawApiData);

    expect(convertItemResponse).toHaveBeenCalledWith(mockRawApiData);
    expect(mockSetItem).toHaveBeenCalledWith(expect.any(Function));
    expect(mockSetSharedLink).toHaveBeenCalledWith(expect.any(Function));
});
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c08d9b5 and a683e6c.

📒 Files selected for processing (9)
  • src/elements/content-sharing/ContentSharingV2.tsx (3 hunks)
  • src/elements/content-sharing/__tests__/ContentSharingV2.test.tsx (3 hunks)
  • src/elements/content-sharing/__tests__/sharingService.test.ts (1 hunks)
  • src/elements/content-sharing/__tests__/useSharedLink.test.js (1 hunks)
  • src/elements/content-sharing/hooks/__tests__/useSharingService.test.ts (1 hunks)
  • src/elements/content-sharing/hooks/useSharingService.ts (1 hunks)
  • src/elements/content-sharing/sharingService.ts (1 hunks)
  • src/elements/content-sharing/utils/__tests__/convertItemResponse.test.ts (1 hunks)
  • src/elements/content-sharing/utils/convertItemResponse.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (6)
src/elements/content-sharing/__tests__/useSharedLink.test.js (2)
src/elements/content-sharing/hooks/useSharedLink.js (1)
  • changeSharedLinkPermissionLevel (39-42)
src/elements/content-sharing/SharingModal.js (1)
  • changeSharedLinkPermissionLevel (87-90)
src/elements/content-sharing/__tests__/sharingService.test.ts (1)
src/elements/content-sharing/sharingService.ts (2)
  • convertSharedLinkPermissions (4-11)
  • createSharingService (13-27)
src/elements/content-sharing/hooks/__tests__/useSharingService.test.ts (3)
src/elements/content-sharing/sharingService.ts (1)
  • createSharingService (13-27)
src/elements/content-sharing/utils/convertItemResponse.ts (1)
  • convertItemResponse (8-106)
src/elements/content-sharing/hooks/useSharingService.ts (1)
  • useSharingService (7-44)
src/elements/content-sharing/ContentSharingV2.tsx (2)
src/elements/content-sharing/hooks/useSharingService.ts (1)
  • useSharingService (7-44)
src/elements/content-sharing/utils/convertItemResponse.ts (1)
  • convertItemResponse (8-106)
src/elements/content-sharing/hooks/useSharingService.ts (2)
src/elements/content-sharing/utils/convertItemResponse.ts (1)
  • convertItemResponse (8-106)
src/elements/content-sharing/sharingService.ts (1)
  • createSharingService (13-27)
src/elements/content-sharing/__tests__/ContentSharingV2.test.tsx (1)
src/elements/content-sharing/hooks/useSharingService.ts (1)
  • useSharingService (7-44)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: lint_test_build
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Summary
🔇 Additional comments (13)
src/elements/content-sharing/__tests__/useSharedLink.test.js (1)

39-40: Fool, this formatting looks good!

I pity the fool who doesn't consolidate their useState declarations! This change makes the code more consistent with the pattern on lines 36-37.

src/elements/content-sharing/__tests__/ContentSharingV2.test.tsx (1)

50-52: Good setup, fool!

I like this default mock setup! It properly initializes useSharingService to return null by default, which matches the hook behavior when item is not available.

src/elements/content-sharing/__tests__/sharingService.test.ts (1)

1-67: Excellent test coverage, fool!

I pity the fool who doesn't write comprehensive tests! This test file covers:

  • Permission mapping for both CAN_DOWNLOAD and CAN_PREVIEW
  • Empty string handling
  • Service creation and structure
  • Correct parameter passing to updateSharedLink

Good work, sucka!

src/elements/content-sharing/ContentSharingV2.tsx (3)

11-11: Good integration, fool!

The import and initialization of the useSharingService hook looks solid. The hook is properly called with all required dependencies (api, item, itemID, itemType, setItem, setSharedLink).

Also applies to: 52-52


57-65: Nice cleanup, sucka!

I like this standardization from ...FromAPI to ...FromApi. Consistent naming makes the code easier to read and maintain!


157-157: Proper wiring, fool!

The sharingService is correctly passed to UnifiedShareModal. This enables the modal to trigger permission updates through the service.

src/elements/content-sharing/sharingService.ts (2)

4-11: Clean permission mapping, fool!

This function correctly maps permission levels to boolean flags. The early return for falsy values prevents unnecessary object creation. Good work, sucka!


13-27: Solid service creation, fool!

I like how this wraps the updateSharedLink call in a clean API. The changeSharedLinkPermission function properly converts the permission level and passes all required parameters to updateSharedLink.

src/elements/content-sharing/hooks/useSharingService.ts (2)

8-22: Proper API selection, fool!

This memo correctly handles the API instance selection based on item type. Returns null when item is missing or itemType is unsupported. Dependencies are correct too!


24-41: Solid hook implementation, sucka!

I like this sharingService memo! It:

  • Properly guards against missing itemApiInstance
  • Constructs itemData with necessary fields
  • Sets up a clean handleSuccess callback that converts the response and atomically updates both item and sharedLink state
  • Creates the service with all required dependencies

The dependencies array is correct, and the memoization prevents unnecessary service recreation.

src/elements/content-sharing/hooks/__tests__/useSharingService.test.ts (3)

1-32: Solid test setup, fool!

The imports, mocks, and test data structure are well-organized. The mock setup correctly isolates the hook for unit testing.


35-45: Clean lifecycle management!

The beforeEach and afterEach hooks properly manage mock state between tests.


47-67: I pity the fool who doesn't test edge cases!

These tests properly verify the guard conditions when item is null or itemType is invalid. Good defensive testing!

@reneshen0328 reneshen0328 force-pushed the create-sharing-service branch from a683e6c to aa3e67a Compare October 10, 2025 00:09
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aa3e67a and b937d4c.

📒 Files selected for processing (1)
  • src/elements/content-sharing/__tests__/ContentSharingV2.test.tsx (8 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/elements/content-sharing/__tests__/ContentSharingV2.test.tsx (1)
src/elements/content-sharing/hooks/useSharingService.ts (1)
  • useSharingService (7-44)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: lint_test_build
  • GitHub Check: Summary
🔇 Additional comments (1)
src/elements/content-sharing/__tests__/ContentSharingV2.test.tsx (1)

54-63: I pity the fool who doesn't follow RTL patterns! This change is solid, fool!

The refactor from getWrapper to renderComponent with a default empty object parameter addresses previous feedback perfectly. This is the proper React Testing Library pattern, sucka!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants