cozy-sharing 37.0.0 → 37.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/dist/components/FederatedFolder/FederatedFolderModal.js +3 -0
- package/dist/components/FederatedFolder/FederatedFolderModal.spec.js +67 -27
- package/package.json +3 -3
- package/src/components/FederatedFolder/FederatedFolderModal.jsx +4 -0
- package/src/components/FederatedFolder/FederatedFolderModal.spec.jsx +28 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [37.0.2](https://github.com/cozy/cozy-libs/compare/cozy-sharing@37.0.1...cozy-sharing@37.0.2) (2026-07-21)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package cozy-sharing
|
|
9
|
+
|
|
10
|
+
## [37.0.1](https://github.com/cozy/cozy-libs/compare/cozy-sharing@37.0.0...cozy-sharing@37.0.1) (2026-07-17)
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
- **cozy-sharing:** Restore federated recipient management ([7442f26](https://github.com/cozy/cozy-libs/commit/7442f26f6cdb757d62d656f19d237d7694335c0c))
|
|
15
|
+
|
|
6
16
|
# [37.0.0](https://github.com/cozy/cozy-libs/compare/cozy-sharing@36.5.0...cozy-sharing@37.0.0) (2026-07-16)
|
|
7
17
|
|
|
8
18
|
### Features
|
|
@@ -54,6 +54,7 @@ var FederatedFolderModalContent = function FederatedFolderModalContent(_ref) {
|
|
|
54
54
|
t = _useI18n.t;
|
|
55
55
|
|
|
56
56
|
var _useSharingContext = useSharingContext(),
|
|
57
|
+
canReshare = _useSharingContext.canReshare,
|
|
57
58
|
share = _useSharingContext.share,
|
|
58
59
|
getSharingById = _useSharingContext.getSharingById,
|
|
59
60
|
getSharingLink = _useSharingContext.getSharingLink,
|
|
@@ -278,6 +279,7 @@ var FederatedFolderModalContent = function FederatedFolderModalContent(_ref) {
|
|
|
278
279
|
var documentPermissions = documentId ? getDocumentPermissions(documentId) : [];
|
|
279
280
|
var displayedLink = existingDocument !== null && existingDocument !== void 0 && existingDocument.driveId ? getFederatedShareLink(existingDocument) : getSharingLink(existingDocument === null || existingDocument === void 0 ? void 0 : existingDocument._id);
|
|
280
281
|
var isCurrentUserOwner = documentId ? isOwner(documentId) : false;
|
|
282
|
+
var canManageSharing = isCurrentUserOwner || (documentId ? canReshare(documentId) : false);
|
|
281
283
|
|
|
282
284
|
var handleRevokeSelf = /*#__PURE__*/function () {
|
|
283
285
|
var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(document) {
|
|
@@ -389,6 +391,7 @@ var FederatedFolderModalContent = function FederatedFolderModalContent(_ref) {
|
|
|
389
391
|
enableCreateContact: true
|
|
390
392
|
}))), /*#__PURE__*/React.createElement(WhoHasAccess, {
|
|
391
393
|
isOwner: isCurrentUserOwner,
|
|
394
|
+
canManageSharing: canManageSharing,
|
|
392
395
|
isSharedDrive: true,
|
|
393
396
|
recipients: isSending ? frozenRecipients : existingRecipients,
|
|
394
397
|
document: isSending ? frozenDoc : existingDocument,
|
|
@@ -19,6 +19,7 @@ var mockShareByLink = jest.fn();
|
|
|
19
19
|
var mockRevoke = jest.fn();
|
|
20
20
|
var mockRevokeSelf = jest.fn();
|
|
21
21
|
var mockIsOwner = jest.fn();
|
|
22
|
+
var mockCanReshare = jest.fn();
|
|
22
23
|
var mockGetSharingLink = jest.fn();
|
|
23
24
|
var mockGetFederatedShareLink = jest.fn();
|
|
24
25
|
var mockGetRecipients = jest.fn().mockReturnValue([]);
|
|
@@ -38,6 +39,7 @@ jest.mock('../../hooks/useSharingContext', function () {
|
|
|
38
39
|
revoke: mockRevoke,
|
|
39
40
|
revokeSelf: mockRevokeSelf,
|
|
40
41
|
isOwner: mockIsOwner,
|
|
42
|
+
canReshare: mockCanReshare,
|
|
41
43
|
getSharingLink: mockGetSharingLink,
|
|
42
44
|
getFederatedShareLink: mockGetFederatedShareLink,
|
|
43
45
|
getDocumentPermissions: mockGetDocumentPermissions,
|
|
@@ -133,6 +135,7 @@ describe('FederatedFolderModal', function () {
|
|
|
133
135
|
mockRevoke.mockResolvedValue();
|
|
134
136
|
mockRevokeSelf.mockResolvedValue();
|
|
135
137
|
mockIsOwner.mockReturnValue(false);
|
|
138
|
+
mockCanReshare.mockReturnValue(false);
|
|
136
139
|
mockGetDocumentPermissions.mockReturnValue([]);
|
|
137
140
|
mockFetchSharedDriveSharingLinks.mockResolvedValue([]);
|
|
138
141
|
mockGetSharingLink.mockReturnValue('https://example.com/share/abc123');
|
|
@@ -726,36 +729,73 @@ describe('FederatedFolderModal', function () {
|
|
|
726
729
|
}
|
|
727
730
|
}, _callee19);
|
|
728
731
|
})));
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
it('should call onClose when close button is clicked', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee20() {
|
|
732
|
-
var _setup17, findByRole, closeButton;
|
|
732
|
+
it('should allow a write recipient to revoke another recipient', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee20() {
|
|
733
|
+
var otherRecipient, _setup17, findByLabelText;
|
|
733
734
|
|
|
734
735
|
return _regeneratorRuntime.wrap(function _callee20$(_context20) {
|
|
735
736
|
while (1) switch (_context20.prev = _context20.next) {
|
|
736
737
|
case 0:
|
|
737
|
-
|
|
738
|
-
|
|
738
|
+
otherRecipient = {
|
|
739
|
+
instance: 'https://other.mycozy.cloud',
|
|
740
|
+
memberIndex: 2,
|
|
741
|
+
sharingId: 'sharing-id',
|
|
742
|
+
type: 'two-way'
|
|
743
|
+
};
|
|
744
|
+
mockCanReshare.mockReturnValue(true);
|
|
745
|
+
mockGetRecipients.mockReturnValue([otherRecipient]);
|
|
746
|
+
_setup17 = setup(), findByLabelText = _setup17.findByLabelText;
|
|
747
|
+
_context20.t0 = fireEvent;
|
|
748
|
+
_context20.next = 7;
|
|
749
|
+
return findByLabelText('Remove from sharing');
|
|
750
|
+
|
|
751
|
+
case 7:
|
|
752
|
+
_context20.t1 = _context20.sent;
|
|
753
|
+
|
|
754
|
+
_context20.t0.click.call(_context20.t0, _context20.t1);
|
|
755
|
+
|
|
756
|
+
_context20.next = 11;
|
|
757
|
+
return waitFor(function () {
|
|
758
|
+
expect(mockCanReshare).toHaveBeenCalledWith(mockDocument._id);
|
|
759
|
+
expect(mockRevoke).toHaveBeenCalledWith(mockDocument, otherRecipient.sharingId, otherRecipient.memberIndex);
|
|
760
|
+
expect(mockRevokeSelf).not.toHaveBeenCalled();
|
|
761
|
+
});
|
|
762
|
+
|
|
763
|
+
case 11:
|
|
764
|
+
case "end":
|
|
765
|
+
return _context20.stop();
|
|
766
|
+
}
|
|
767
|
+
}, _callee20);
|
|
768
|
+
})));
|
|
769
|
+
});
|
|
770
|
+
describe('onClose callback', function () {
|
|
771
|
+
it('should call onClose when close button is clicked', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee21() {
|
|
772
|
+
var _setup18, findByRole, closeButton;
|
|
773
|
+
|
|
774
|
+
return _regeneratorRuntime.wrap(function _callee21$(_context21) {
|
|
775
|
+
while (1) switch (_context21.prev = _context21.next) {
|
|
776
|
+
case 0:
|
|
777
|
+
_setup18 = setup(), findByRole = _setup18.findByRole;
|
|
778
|
+
_context21.next = 3;
|
|
739
779
|
return findByRole('button', {
|
|
740
780
|
name: /close/i
|
|
741
781
|
});
|
|
742
782
|
|
|
743
783
|
case 3:
|
|
744
|
-
closeButton =
|
|
784
|
+
closeButton = _context21.sent;
|
|
745
785
|
fireEvent.click(closeButton);
|
|
746
786
|
expect(mockOnClose).toHaveBeenCalled();
|
|
747
787
|
|
|
748
788
|
case 6:
|
|
749
789
|
case "end":
|
|
750
|
-
return
|
|
790
|
+
return _context21.stop();
|
|
751
791
|
}
|
|
752
|
-
},
|
|
792
|
+
}, _callee21);
|
|
753
793
|
})));
|
|
754
|
-
it('should ask confirmation when close button is clicked with pending recipients', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function
|
|
755
|
-
var
|
|
794
|
+
it('should ask confirmation when close button is clicked with pending recipients', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee22() {
|
|
795
|
+
var _setup19, getByRole, findByRole, getByText, closeButton;
|
|
756
796
|
|
|
757
|
-
return _regeneratorRuntime.wrap(function
|
|
758
|
-
while (1) switch (
|
|
797
|
+
return _regeneratorRuntime.wrap(function _callee22$(_context22) {
|
|
798
|
+
while (1) switch (_context22.prev = _context22.next) {
|
|
759
799
|
case 0:
|
|
760
800
|
usePendingRecipients.mockReturnValue({
|
|
761
801
|
pendingRecipients: [{
|
|
@@ -766,14 +806,14 @@ describe('FederatedFolderModal', function () {
|
|
|
766
806
|
selectedOption: 'readWrite',
|
|
767
807
|
setSelectedOption: jest.fn()
|
|
768
808
|
});
|
|
769
|
-
|
|
770
|
-
|
|
809
|
+
_setup19 = setup(), getByRole = _setup19.getByRole, findByRole = _setup19.findByRole, getByText = _setup19.getByText;
|
|
810
|
+
_context22.next = 4;
|
|
771
811
|
return findByRole('button', {
|
|
772
812
|
name: /close/i
|
|
773
813
|
});
|
|
774
814
|
|
|
775
815
|
case 4:
|
|
776
|
-
closeButton =
|
|
816
|
+
closeButton = _context22.sent;
|
|
777
817
|
fireEvent.click(closeButton);
|
|
778
818
|
expect(getByText("Discard the changes you haven't saved?")).toBeTruthy();
|
|
779
819
|
expect(mockOnClose).not.toHaveBeenCalled();
|
|
@@ -784,15 +824,15 @@ describe('FederatedFolderModal', function () {
|
|
|
784
824
|
|
|
785
825
|
case 10:
|
|
786
826
|
case "end":
|
|
787
|
-
return
|
|
827
|
+
return _context22.stop();
|
|
788
828
|
}
|
|
789
|
-
},
|
|
829
|
+
}, _callee22);
|
|
790
830
|
})));
|
|
791
|
-
it('should close after discard confirmation', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function
|
|
792
|
-
var
|
|
831
|
+
it('should close after discard confirmation', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee23() {
|
|
832
|
+
var _setup20, getByRole, findByRole, getByText, closeButton;
|
|
793
833
|
|
|
794
|
-
return _regeneratorRuntime.wrap(function
|
|
795
|
-
while (1) switch (
|
|
834
|
+
return _regeneratorRuntime.wrap(function _callee23$(_context23) {
|
|
835
|
+
while (1) switch (_context23.prev = _context23.next) {
|
|
796
836
|
case 0:
|
|
797
837
|
usePendingRecipients.mockReturnValue({
|
|
798
838
|
pendingRecipients: [{
|
|
@@ -803,14 +843,14 @@ describe('FederatedFolderModal', function () {
|
|
|
803
843
|
selectedOption: 'readWrite',
|
|
804
844
|
setSelectedOption: jest.fn()
|
|
805
845
|
});
|
|
806
|
-
|
|
807
|
-
|
|
846
|
+
_setup20 = setup(), getByRole = _setup20.getByRole, findByRole = _setup20.findByRole, getByText = _setup20.getByText;
|
|
847
|
+
_context23.next = 4;
|
|
808
848
|
return findByRole('button', {
|
|
809
849
|
name: /close/i
|
|
810
850
|
});
|
|
811
851
|
|
|
812
852
|
case 4:
|
|
813
|
-
closeButton =
|
|
853
|
+
closeButton = _context23.sent;
|
|
814
854
|
fireEvent.click(closeButton);
|
|
815
855
|
expect(getByText("Discard the changes you haven't saved?")).toBeTruthy();
|
|
816
856
|
fireEvent.click(getByRole('button', {
|
|
@@ -820,9 +860,9 @@ describe('FederatedFolderModal', function () {
|
|
|
820
860
|
|
|
821
861
|
case 9:
|
|
822
862
|
case "end":
|
|
823
|
-
return
|
|
863
|
+
return _context23.stop();
|
|
824
864
|
}
|
|
825
|
-
},
|
|
865
|
+
}, _callee23);
|
|
826
866
|
})));
|
|
827
867
|
});
|
|
828
868
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cozy-sharing",
|
|
3
|
-
"version": "37.0.
|
|
3
|
+
"version": "37.0.2",
|
|
4
4
|
"description": "Provides sharing login for React applications.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"author": "Cozy",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"cozy-intent": "^2.31.1",
|
|
60
60
|
"cozy-minilog": "^3.10.1",
|
|
61
61
|
"cozy-ui": "^140.5.0",
|
|
62
|
-
"cozy-ui-plus": "^12.0
|
|
62
|
+
"cozy-ui-plus": "^12.1.0",
|
|
63
63
|
"jest": "30.3.0",
|
|
64
64
|
"jest-environment-jsdom": "30.3.0",
|
|
65
65
|
"react": "16.12.0",
|
|
@@ -85,5 +85,5 @@
|
|
|
85
85
|
"sideEffects": [
|
|
86
86
|
"*.css"
|
|
87
87
|
],
|
|
88
|
-
"gitHead": "
|
|
88
|
+
"gitHead": "22faa5b53511d7720c575564ec52f446743209e6"
|
|
89
89
|
}
|
|
@@ -35,6 +35,7 @@ const FederatedFolderModalContent = ({
|
|
|
35
35
|
const client = useClient()
|
|
36
36
|
const { t } = useI18n()
|
|
37
37
|
const {
|
|
38
|
+
canReshare,
|
|
38
39
|
share,
|
|
39
40
|
getSharingById,
|
|
40
41
|
getSharingLink,
|
|
@@ -224,6 +225,8 @@ const FederatedFolderModalContent = ({
|
|
|
224
225
|
? getFederatedShareLink(existingDocument)
|
|
225
226
|
: getSharingLink(existingDocument?._id)
|
|
226
227
|
const isCurrentUserOwner = documentId ? isOwner(documentId) : false
|
|
228
|
+
const canManageSharing =
|
|
229
|
+
isCurrentUserOwner || (documentId ? canReshare(documentId) : false)
|
|
227
230
|
|
|
228
231
|
const handleRevokeSelf = async document => {
|
|
229
232
|
await revokeSelf(document)
|
|
@@ -323,6 +326,7 @@ const FederatedFolderModalContent = ({
|
|
|
323
326
|
</div>
|
|
324
327
|
<WhoHasAccess
|
|
325
328
|
isOwner={isCurrentUserOwner}
|
|
329
|
+
canManageSharing={canManageSharing}
|
|
326
330
|
isSharedDrive
|
|
327
331
|
recipients={isSending ? frozenRecipients : existingRecipients}
|
|
328
332
|
document={isSending ? frozenDoc : existingDocument}
|
|
@@ -13,6 +13,7 @@ const mockShareByLink = jest.fn()
|
|
|
13
13
|
const mockRevoke = jest.fn()
|
|
14
14
|
const mockRevokeSelf = jest.fn()
|
|
15
15
|
const mockIsOwner = jest.fn()
|
|
16
|
+
const mockCanReshare = jest.fn()
|
|
16
17
|
const mockGetSharingLink = jest.fn()
|
|
17
18
|
const mockGetFederatedShareLink = jest.fn()
|
|
18
19
|
const mockGetRecipients = jest.fn().mockReturnValue([])
|
|
@@ -31,6 +32,7 @@ jest.mock('../../hooks/useSharingContext', () => ({
|
|
|
31
32
|
revoke: mockRevoke,
|
|
32
33
|
revokeSelf: mockRevokeSelf,
|
|
33
34
|
isOwner: mockIsOwner,
|
|
35
|
+
canReshare: mockCanReshare,
|
|
34
36
|
getSharingLink: mockGetSharingLink,
|
|
35
37
|
getFederatedShareLink: mockGetFederatedShareLink,
|
|
36
38
|
getDocumentPermissions: mockGetDocumentPermissions,
|
|
@@ -109,6 +111,7 @@ describe('FederatedFolderModal', () => {
|
|
|
109
111
|
mockRevoke.mockResolvedValue()
|
|
110
112
|
mockRevokeSelf.mockResolvedValue()
|
|
111
113
|
mockIsOwner.mockReturnValue(false)
|
|
114
|
+
mockCanReshare.mockReturnValue(false)
|
|
112
115
|
mockGetDocumentPermissions.mockReturnValue([])
|
|
113
116
|
mockFetchSharedDriveSharingLinks.mockResolvedValue([])
|
|
114
117
|
mockGetSharingLink.mockReturnValue('https://example.com/share/abc123')
|
|
@@ -472,6 +475,31 @@ describe('FederatedFolderModal', () => {
|
|
|
472
475
|
expect(onRevokeSuccess).toHaveBeenCalledWith(mockDocument)
|
|
473
476
|
})
|
|
474
477
|
})
|
|
478
|
+
|
|
479
|
+
it('should allow a write recipient to revoke another recipient', async () => {
|
|
480
|
+
const otherRecipient = {
|
|
481
|
+
instance: 'https://other.mycozy.cloud',
|
|
482
|
+
memberIndex: 2,
|
|
483
|
+
sharingId: 'sharing-id',
|
|
484
|
+
type: 'two-way'
|
|
485
|
+
}
|
|
486
|
+
mockCanReshare.mockReturnValue(true)
|
|
487
|
+
mockGetRecipients.mockReturnValue([otherRecipient])
|
|
488
|
+
|
|
489
|
+
const { findByLabelText } = setup()
|
|
490
|
+
|
|
491
|
+
fireEvent.click(await findByLabelText('Remove from sharing'))
|
|
492
|
+
|
|
493
|
+
await waitFor(() => {
|
|
494
|
+
expect(mockCanReshare).toHaveBeenCalledWith(mockDocument._id)
|
|
495
|
+
expect(mockRevoke).toHaveBeenCalledWith(
|
|
496
|
+
mockDocument,
|
|
497
|
+
otherRecipient.sharingId,
|
|
498
|
+
otherRecipient.memberIndex
|
|
499
|
+
)
|
|
500
|
+
expect(mockRevokeSelf).not.toHaveBeenCalled()
|
|
501
|
+
})
|
|
502
|
+
})
|
|
475
503
|
})
|
|
476
504
|
|
|
477
505
|
describe('onClose callback', () => {
|