cozy-sharing 34.1.1 → 35.0.0
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 +16 -0
- package/dist/components/FederatedFolder/FederatedFolderModal.js +46 -16
- package/dist/components/FederatedFolder/FederatedFolderModal.spec.js +79 -28
- package/dist/components/Recipient/MemberRecipientPermissions.js +7 -5
- package/dist/components/Recipient/RecipientList.js +2 -0
- package/dist/components/ShareModal/ShareModal.js +2 -1
- package/dist/components/WhoHasAccess.js +4 -0
- package/jest.config.js +1 -2
- package/package.json +5 -5
- package/src/components/FederatedFolder/FederatedFolderModal.jsx +13 -2
- package/src/components/FederatedFolder/FederatedFolderModal.spec.jsx +35 -0
- package/src/components/Recipient/MemberRecipientPermissions.jsx +14 -5
- package/src/components/Recipient/RecipientList.jsx +2 -0
- package/src/components/ShareModal/ShareModal.jsx +7 -1
- package/src/components/WhoHasAccess.jsx +3 -0
- package/jestHelpers/mocks/twake-icons.js +0 -23
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,22 @@
|
|
|
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
|
+
# [35.0.0](https://github.com/cozy/cozy-libs/compare/cozy-sharing@34.1.2...cozy-sharing@35.0.0) (2026-06-25)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
- Ugrade twake-icons in libs and remove test mock ([46178bc](https://github.com/cozy/cozy-libs/commit/46178bcfff73fb8486b6a5209a14e306b497371b))
|
|
11
|
+
|
|
12
|
+
### BREAKING CHANGES
|
|
13
|
+
|
|
14
|
+
- You must have `@linagora/twake-icons >=2.6.6`
|
|
15
|
+
|
|
16
|
+
## [34.1.2](https://github.com/cozy/cozy-libs/compare/cozy-sharing@34.1.1...cozy-sharing@34.1.2) (2026-06-25)
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
- **sharing:** Call self revoke for federated recipients ([25e62c2](https://github.com/cozy/cozy-libs/commit/25e62c2416e4b91bdab1e06fbbd77b00574a0b11))
|
|
21
|
+
|
|
6
22
|
## [34.1.1](https://github.com/cozy/cozy-libs/compare/cozy-sharing@34.1.0...cozy-sharing@34.1.1) (2026-06-25)
|
|
7
23
|
|
|
8
24
|
### Bug Fixes
|
|
@@ -44,6 +44,7 @@ var FederatedFolderModalContent = function FederatedFolderModalContent(_ref) {
|
|
|
44
44
|
var _sharedDriveSharing$a, _sharedDriveSharing$a2;
|
|
45
45
|
|
|
46
46
|
var onClose = _ref.onClose,
|
|
47
|
+
onRevokeSuccess = _ref.onRevokeSuccess,
|
|
47
48
|
existingDocument = _ref.document,
|
|
48
49
|
autoOpenShareRestriction = _ref.autoOpenShareRestriction,
|
|
49
50
|
showGenerateLinkButton = _ref.showGenerateLinkButton;
|
|
@@ -63,7 +64,9 @@ var FederatedFolderModalContent = function FederatedFolderModalContent(_ref) {
|
|
|
63
64
|
getSharedParentPath = _useSharingContext.getSharedParentPath,
|
|
64
65
|
hasSharedChild = _useSharingContext.hasSharedChild,
|
|
65
66
|
hasSharedParent = _useSharingContext.hasSharedParent,
|
|
66
|
-
|
|
67
|
+
isOwner = _useSharingContext.isOwner,
|
|
68
|
+
revoke = _useSharingContext.revoke,
|
|
69
|
+
revokeSelf = _useSharingContext.revokeSelf;
|
|
67
70
|
|
|
68
71
|
var _useAlert = useAlert(),
|
|
69
72
|
showAlert = _useAlert.showAlert;
|
|
@@ -274,6 +277,31 @@ var FederatedFolderModalContent = function FederatedFolderModalContent(_ref) {
|
|
|
274
277
|
var existingRecipients = sharedDriveSharing !== null && sharedDriveSharing !== void 0 && (_sharedDriveSharing$a2 = sharedDriveSharing.attributes) !== null && _sharedDriveSharing$a2 !== void 0 && _sharedDriveSharing$a2.members && documentId ? getRecipientsFromSharing(sharedDriveSharing, documentId) : sharingReferenceId ? getRecipients(sharingReferenceId) : [];
|
|
275
278
|
var documentPermissions = documentId ? getDocumentPermissions(documentId) : [];
|
|
276
279
|
var displayedLink = existingDocument !== null && existingDocument !== void 0 && existingDocument.driveId ? getFederatedShareLink(existingDocument) : getSharingLink(existingDocument === null || existingDocument === void 0 ? void 0 : existingDocument._id);
|
|
280
|
+
var isCurrentUserOwner = documentId ? isOwner(documentId) : false;
|
|
281
|
+
|
|
282
|
+
var handleRevokeSelf = /*#__PURE__*/function () {
|
|
283
|
+
var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(document) {
|
|
284
|
+
return _regeneratorRuntime.wrap(function _callee3$(_context3) {
|
|
285
|
+
while (1) switch (_context3.prev = _context3.next) {
|
|
286
|
+
case 0:
|
|
287
|
+
_context3.next = 2;
|
|
288
|
+
return revokeSelf(document);
|
|
289
|
+
|
|
290
|
+
case 2:
|
|
291
|
+
onRevokeSuccess === null || onRevokeSuccess === void 0 || onRevokeSuccess(document);
|
|
292
|
+
|
|
293
|
+
case 3:
|
|
294
|
+
case "end":
|
|
295
|
+
return _context3.stop();
|
|
296
|
+
}
|
|
297
|
+
}, _callee3);
|
|
298
|
+
}));
|
|
299
|
+
|
|
300
|
+
return function handleRevokeSelf(_x) {
|
|
301
|
+
return _ref4.apply(this, arguments);
|
|
302
|
+
};
|
|
303
|
+
}();
|
|
304
|
+
|
|
277
305
|
useEffect(function () {
|
|
278
306
|
if (!(existingDocument !== null && existingDocument !== void 0 && existingDocument.driveId)) return;
|
|
279
307
|
if (!documentId) return;
|
|
@@ -283,39 +311,39 @@ var FederatedFolderModalContent = function FederatedFolderModalContent(_ref) {
|
|
|
283
311
|
if (fetchedSharingLinksDocumentId === documentId) return;
|
|
284
312
|
|
|
285
313
|
var fetchSharingLinks = /*#__PURE__*/function () {
|
|
286
|
-
var
|
|
287
|
-
return _regeneratorRuntime.wrap(function
|
|
288
|
-
while (1) switch (
|
|
314
|
+
var _ref5 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
|
|
315
|
+
return _regeneratorRuntime.wrap(function _callee4$(_context4) {
|
|
316
|
+
while (1) switch (_context4.prev = _context4.next) {
|
|
289
317
|
case 0:
|
|
290
318
|
setIsFetchingSharingLinks(true);
|
|
291
|
-
|
|
292
|
-
|
|
319
|
+
_context4.prev = 1;
|
|
320
|
+
_context4.next = 4;
|
|
293
321
|
return fetchSharedDriveSharingLinks(existingDocument);
|
|
294
322
|
|
|
295
323
|
case 4:
|
|
296
|
-
|
|
324
|
+
_context4.next = 9;
|
|
297
325
|
break;
|
|
298
326
|
|
|
299
327
|
case 6:
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
log.error('Failed to fetch shared drive sharing links',
|
|
328
|
+
_context4.prev = 6;
|
|
329
|
+
_context4.t0 = _context4["catch"](1);
|
|
330
|
+
log.error('Failed to fetch shared drive sharing links', _context4.t0);
|
|
303
331
|
|
|
304
332
|
case 9:
|
|
305
|
-
|
|
333
|
+
_context4.prev = 9;
|
|
306
334
|
setFetchedSharingLinksDocumentId(documentId);
|
|
307
335
|
setIsFetchingSharingLinks(false);
|
|
308
|
-
return
|
|
336
|
+
return _context4.finish(9);
|
|
309
337
|
|
|
310
338
|
case 13:
|
|
311
339
|
case "end":
|
|
312
|
-
return
|
|
340
|
+
return _context4.stop();
|
|
313
341
|
}
|
|
314
|
-
},
|
|
342
|
+
}, _callee4, null, [[1, 6, 9, 13]]);
|
|
315
343
|
}));
|
|
316
344
|
|
|
317
345
|
return function fetchSharingLinks() {
|
|
318
|
-
return
|
|
346
|
+
return _ref5.apply(this, arguments);
|
|
319
347
|
};
|
|
320
348
|
}();
|
|
321
349
|
|
|
@@ -360,13 +388,14 @@ var FederatedFolderModalContent = function FederatedFolderModalContent(_ref) {
|
|
|
360
388
|
onSelectedOptionChange: setSelectedOption,
|
|
361
389
|
enableCreateContact: true
|
|
362
390
|
}))), /*#__PURE__*/React.createElement(WhoHasAccess, {
|
|
363
|
-
isOwner:
|
|
391
|
+
isOwner: isCurrentUserOwner,
|
|
364
392
|
isSharedDrive: true,
|
|
365
393
|
recipients: isSending ? frozenRecipients : existingRecipients,
|
|
366
394
|
document: isSending ? frozenDoc : existingDocument,
|
|
367
395
|
documentType: "Files",
|
|
368
396
|
className: styles['share-dialog-members'],
|
|
369
397
|
onRevoke: revoke,
|
|
398
|
+
onRevokeSelf: handleRevokeSelf,
|
|
370
399
|
link: displayedLink
|
|
371
400
|
})),
|
|
372
401
|
actions: /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ShareByLink, {
|
|
@@ -389,6 +418,7 @@ export var FederatedFolderModal = withLocales(function (props) {
|
|
|
389
418
|
});
|
|
390
419
|
FederatedFolderModal.propTypes = {
|
|
391
420
|
onClose: PropTypes.func.isRequired,
|
|
421
|
+
onRevokeSuccess: PropTypes.func,
|
|
392
422
|
document: PropTypes.object.isRequired,
|
|
393
423
|
autoOpenShareRestriction: PropTypes.bool,
|
|
394
424
|
showGenerateLinkButton: PropTypes.bool
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
1
|
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
3
2
|
import _extends from "@babel/runtime/helpers/extends";
|
|
3
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
4
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
4
5
|
|
|
5
6
|
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
6
7
|
|
|
7
8
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
8
9
|
|
|
9
|
-
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
10
10
|
import { act, fireEvent, render, waitFor } from '@testing-library/react';
|
|
11
11
|
import React from 'react';
|
|
12
12
|
import { createMockClient } from 'cozy-client';
|
|
@@ -17,6 +17,8 @@ import AppLike from '../SharingBanner/test/AppLike';
|
|
|
17
17
|
var mockShare = jest.fn();
|
|
18
18
|
var mockShareByLink = jest.fn();
|
|
19
19
|
var mockRevoke = jest.fn();
|
|
20
|
+
var mockRevokeSelf = jest.fn();
|
|
21
|
+
var mockIsOwner = jest.fn();
|
|
20
22
|
var mockGetSharingLink = jest.fn();
|
|
21
23
|
var mockGetFederatedShareLink = jest.fn();
|
|
22
24
|
var mockGetRecipients = jest.fn().mockReturnValue([]);
|
|
@@ -34,6 +36,8 @@ jest.mock('../../hooks/useSharingContext', function () {
|
|
|
34
36
|
share: mockShare,
|
|
35
37
|
shareByLink: mockShareByLink,
|
|
36
38
|
revoke: mockRevoke,
|
|
39
|
+
revokeSelf: mockRevokeSelf,
|
|
40
|
+
isOwner: mockIsOwner,
|
|
37
41
|
getSharingLink: mockGetSharingLink,
|
|
38
42
|
getFederatedShareLink: mockGetFederatedShareLink,
|
|
39
43
|
getDocumentPermissions: mockGetDocumentPermissions,
|
|
@@ -123,6 +127,9 @@ describe('FederatedFolderModal', function () {
|
|
|
123
127
|
var sharingContextValue;
|
|
124
128
|
beforeEach(function () {
|
|
125
129
|
jest.clearAllMocks();
|
|
130
|
+
mockRevoke.mockResolvedValue();
|
|
131
|
+
mockRevokeSelf.mockResolvedValue();
|
|
132
|
+
mockIsOwner.mockReturnValue(false);
|
|
126
133
|
mockGetDocumentPermissions.mockReturnValue([]);
|
|
127
134
|
mockFetchSharedDriveSharingLinks.mockResolvedValue([]);
|
|
128
135
|
mockGetSharingLink.mockReturnValue('https://example.com/share/abc123');
|
|
@@ -147,6 +154,9 @@ describe('FederatedFolderModal', function () {
|
|
|
147
154
|
}
|
|
148
155
|
});
|
|
149
156
|
client = createTestClient();
|
|
157
|
+
client.options = _objectSpread(_objectSpread({}, client.options), {}, {
|
|
158
|
+
uri: 'https://me.mycozy.cloud'
|
|
159
|
+
});
|
|
150
160
|
sharingContextValue = createSharingContextValue();
|
|
151
161
|
usePendingRecipients.mockReturnValue({
|
|
152
162
|
pendingRecipients: [],
|
|
@@ -673,35 +683,76 @@ describe('FederatedFolderModal', function () {
|
|
|
673
683
|
}, _callee18);
|
|
674
684
|
})));
|
|
675
685
|
});
|
|
676
|
-
describe('
|
|
677
|
-
|
|
678
|
-
|
|
686
|
+
describe('onRevoke callback', function () {
|
|
687
|
+
var currentUserRecipient = {
|
|
688
|
+
instance: 'https://me.mycozy.cloud',
|
|
689
|
+
memberIndex: 1,
|
|
690
|
+
sharingId: 'sharing-id',
|
|
691
|
+
type: 'two-way'
|
|
692
|
+
};
|
|
693
|
+
it('should call onRevokeSelf and onRevokeSuccess when the current user is revoked', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee19() {
|
|
694
|
+
var onRevokeSuccess, _setup16, findByLabelText;
|
|
679
695
|
|
|
680
696
|
return _regeneratorRuntime.wrap(function _callee19$(_context19) {
|
|
681
697
|
while (1) switch (_context19.prev = _context19.next) {
|
|
682
698
|
case 0:
|
|
683
|
-
|
|
684
|
-
|
|
699
|
+
onRevokeSuccess = jest.fn();
|
|
700
|
+
mockGetRecipients.mockReturnValue([currentUserRecipient]);
|
|
701
|
+
_setup16 = setup({
|
|
702
|
+
onRevokeSuccess: onRevokeSuccess
|
|
703
|
+
}), findByLabelText = _setup16.findByLabelText;
|
|
704
|
+
_context19.t0 = fireEvent;
|
|
705
|
+
_context19.next = 6;
|
|
706
|
+
return findByLabelText('Remove from sharing');
|
|
707
|
+
|
|
708
|
+
case 6:
|
|
709
|
+
_context19.t1 = _context19.sent;
|
|
710
|
+
|
|
711
|
+
_context19.t0.click.call(_context19.t0, _context19.t1);
|
|
712
|
+
|
|
713
|
+
_context19.next = 10;
|
|
714
|
+
return waitFor(function () {
|
|
715
|
+
expect(mockRevokeSelf).toHaveBeenCalledWith(mockDocument);
|
|
716
|
+
expect(mockRevoke).not.toHaveBeenCalled();
|
|
717
|
+
expect(onRevokeSuccess).toHaveBeenCalledWith(mockDocument);
|
|
718
|
+
});
|
|
719
|
+
|
|
720
|
+
case 10:
|
|
721
|
+
case "end":
|
|
722
|
+
return _context19.stop();
|
|
723
|
+
}
|
|
724
|
+
}, _callee19);
|
|
725
|
+
})));
|
|
726
|
+
});
|
|
727
|
+
describe('onClose callback', function () {
|
|
728
|
+
it('should call onClose when close button is clicked', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee20() {
|
|
729
|
+
var _setup17, findByRole, closeButton;
|
|
730
|
+
|
|
731
|
+
return _regeneratorRuntime.wrap(function _callee20$(_context20) {
|
|
732
|
+
while (1) switch (_context20.prev = _context20.next) {
|
|
733
|
+
case 0:
|
|
734
|
+
_setup17 = setup(), findByRole = _setup17.findByRole;
|
|
735
|
+
_context20.next = 3;
|
|
685
736
|
return findByRole('button', {
|
|
686
737
|
name: /close/i
|
|
687
738
|
});
|
|
688
739
|
|
|
689
740
|
case 3:
|
|
690
|
-
closeButton =
|
|
741
|
+
closeButton = _context20.sent;
|
|
691
742
|
fireEvent.click(closeButton);
|
|
692
743
|
expect(mockOnClose).toHaveBeenCalled();
|
|
693
744
|
|
|
694
745
|
case 6:
|
|
695
746
|
case "end":
|
|
696
|
-
return
|
|
747
|
+
return _context20.stop();
|
|
697
748
|
}
|
|
698
|
-
},
|
|
749
|
+
}, _callee20);
|
|
699
750
|
})));
|
|
700
|
-
it('should ask confirmation when close button is clicked with pending recipients', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function
|
|
701
|
-
var
|
|
751
|
+
it('should ask confirmation when close button is clicked with pending recipients', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee21() {
|
|
752
|
+
var _setup18, getByRole, findByRole, getByText, closeButton;
|
|
702
753
|
|
|
703
|
-
return _regeneratorRuntime.wrap(function
|
|
704
|
-
while (1) switch (
|
|
754
|
+
return _regeneratorRuntime.wrap(function _callee21$(_context21) {
|
|
755
|
+
while (1) switch (_context21.prev = _context21.next) {
|
|
705
756
|
case 0:
|
|
706
757
|
usePendingRecipients.mockReturnValue({
|
|
707
758
|
pendingRecipients: [{
|
|
@@ -712,14 +763,14 @@ describe('FederatedFolderModal', function () {
|
|
|
712
763
|
selectedOption: 'readWrite',
|
|
713
764
|
setSelectedOption: jest.fn()
|
|
714
765
|
});
|
|
715
|
-
|
|
716
|
-
|
|
766
|
+
_setup18 = setup(), getByRole = _setup18.getByRole, findByRole = _setup18.findByRole, getByText = _setup18.getByText;
|
|
767
|
+
_context21.next = 4;
|
|
717
768
|
return findByRole('button', {
|
|
718
769
|
name: /close/i
|
|
719
770
|
});
|
|
720
771
|
|
|
721
772
|
case 4:
|
|
722
|
-
closeButton =
|
|
773
|
+
closeButton = _context21.sent;
|
|
723
774
|
fireEvent.click(closeButton);
|
|
724
775
|
expect(getByText("Discard the changes you haven't saved?")).toBeTruthy();
|
|
725
776
|
expect(mockOnClose).not.toHaveBeenCalled();
|
|
@@ -730,15 +781,15 @@ describe('FederatedFolderModal', function () {
|
|
|
730
781
|
|
|
731
782
|
case 10:
|
|
732
783
|
case "end":
|
|
733
|
-
return
|
|
784
|
+
return _context21.stop();
|
|
734
785
|
}
|
|
735
|
-
},
|
|
786
|
+
}, _callee21);
|
|
736
787
|
})));
|
|
737
|
-
it('should close after discard confirmation', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function
|
|
738
|
-
var
|
|
788
|
+
it('should close after discard confirmation', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee22() {
|
|
789
|
+
var _setup19, getByRole, findByRole, getByText, closeButton;
|
|
739
790
|
|
|
740
|
-
return _regeneratorRuntime.wrap(function
|
|
741
|
-
while (1) switch (
|
|
791
|
+
return _regeneratorRuntime.wrap(function _callee22$(_context22) {
|
|
792
|
+
while (1) switch (_context22.prev = _context22.next) {
|
|
742
793
|
case 0:
|
|
743
794
|
usePendingRecipients.mockReturnValue({
|
|
744
795
|
pendingRecipients: [{
|
|
@@ -749,14 +800,14 @@ describe('FederatedFolderModal', function () {
|
|
|
749
800
|
selectedOption: 'readWrite',
|
|
750
801
|
setSelectedOption: jest.fn()
|
|
751
802
|
});
|
|
752
|
-
|
|
753
|
-
|
|
803
|
+
_setup19 = setup(), getByRole = _setup19.getByRole, findByRole = _setup19.findByRole, getByText = _setup19.getByText;
|
|
804
|
+
_context22.next = 4;
|
|
754
805
|
return findByRole('button', {
|
|
755
806
|
name: /close/i
|
|
756
807
|
});
|
|
757
808
|
|
|
758
809
|
case 4:
|
|
759
|
-
closeButton =
|
|
810
|
+
closeButton = _context22.sent;
|
|
760
811
|
fireEvent.click(closeButton);
|
|
761
812
|
expect(getByText("Discard the changes you haven't saved?")).toBeTruthy();
|
|
762
813
|
fireEvent.click(getByRole('button', {
|
|
@@ -766,9 +817,9 @@ describe('FederatedFolderModal', function () {
|
|
|
766
817
|
|
|
767
818
|
case 9:
|
|
768
819
|
case "end":
|
|
769
|
-
return
|
|
820
|
+
return _context22.stop();
|
|
770
821
|
}
|
|
771
|
-
},
|
|
822
|
+
}, _callee22);
|
|
772
823
|
})));
|
|
773
824
|
});
|
|
774
825
|
});
|
|
@@ -20,6 +20,8 @@ var log = minilog('MemberRecipientPermissions');
|
|
|
20
20
|
|
|
21
21
|
var MemberRecipientPermissions = function MemberRecipientPermissions(_ref) {
|
|
22
22
|
var isOwner = _ref.isOwner,
|
|
23
|
+
_ref$canManageSharing = _ref.canManageSharing,
|
|
24
|
+
canManageSharing = _ref$canManageSharing === void 0 ? isOwner : _ref$canManageSharing,
|
|
23
25
|
isReadOnly = _ref.isReadOnly,
|
|
24
26
|
status = _ref.status,
|
|
25
27
|
instance = _ref.instance,
|
|
@@ -54,7 +56,7 @@ var MemberRecipientPermissions = function MemberRecipientPermissions(_ref) {
|
|
|
54
56
|
|
|
55
57
|
var instanceMatchesClient = instance !== undefined && instance === client.options.uri;
|
|
56
58
|
var contactIsOwner = status === 'owner';
|
|
57
|
-
var shouldShowMenu = !isReadOnly && !revoking && !contactIsOwner && (instanceMatchesClient && !isOwner ||
|
|
59
|
+
var shouldShowMenu = !isReadOnly && !revoking && !contactIsOwner && (instanceMatchesClient && !isOwner || canManageSharing);
|
|
58
60
|
var toggleMenu = useCallback(function () {
|
|
59
61
|
setMenuDisplayed(function (displayed) {
|
|
60
62
|
return !displayed;
|
|
@@ -70,13 +72,13 @@ var MemberRecipientPermissions = function MemberRecipientPermissions(_ref) {
|
|
|
70
72
|
setRevoking(true);
|
|
71
73
|
_context.prev = 1;
|
|
72
74
|
|
|
73
|
-
if (!isOwner) {
|
|
75
|
+
if (!(instanceMatchesClient && !isOwner)) {
|
|
74
76
|
_context.next = 7;
|
|
75
77
|
break;
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
_context.next = 5;
|
|
79
|
-
return
|
|
81
|
+
return onRevokeSelf(document);
|
|
80
82
|
|
|
81
83
|
case 5:
|
|
82
84
|
_context.next = 9;
|
|
@@ -84,7 +86,7 @@ var MemberRecipientPermissions = function MemberRecipientPermissions(_ref) {
|
|
|
84
86
|
|
|
85
87
|
case 7:
|
|
86
88
|
_context.next = 9;
|
|
87
|
-
return
|
|
89
|
+
return onRevoke(document, sharingId, memberIndex);
|
|
88
90
|
|
|
89
91
|
case 9:
|
|
90
92
|
_context.prev = 9;
|
|
@@ -96,7 +98,7 @@ var MemberRecipientPermissions = function MemberRecipientPermissions(_ref) {
|
|
|
96
98
|
return _context.stop();
|
|
97
99
|
}
|
|
98
100
|
}, _callee, null, [[1,, 9, 12]]);
|
|
99
|
-
})), [isOwner, onRevoke, onRevokeSelf,
|
|
101
|
+
})), [document, instanceMatchesClient, isOwner, memberIndex, onRevoke, onRevokeSelf, sharingId]);
|
|
100
102
|
var setType = useCallback( /*#__PURE__*/function () {
|
|
101
103
|
var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(newType) {
|
|
102
104
|
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
|
|
@@ -9,6 +9,7 @@ var RecipientList = function RecipientList(_ref) {
|
|
|
9
9
|
var recipients = _ref.recipients,
|
|
10
10
|
recipientsToBeConfirmed = _ref.recipientsToBeConfirmed,
|
|
11
11
|
isOwner = _ref.isOwner,
|
|
12
|
+
canManageSharing = _ref.canManageSharing,
|
|
12
13
|
isSharedDrive = _ref.isSharedDrive,
|
|
13
14
|
isReadOnly = _ref.isReadOnly,
|
|
14
15
|
document = _ref.document,
|
|
@@ -40,6 +41,7 @@ var RecipientList = function RecipientList(_ref) {
|
|
|
40
41
|
return /*#__PURE__*/React.createElement(MemberRecipient, _extends({}, recipient, {
|
|
41
42
|
key: recipient.index,
|
|
42
43
|
isOwner: isOwner,
|
|
44
|
+
canManageSharing: canManageSharing,
|
|
43
45
|
isSharedDrive: isSharedDrive,
|
|
44
46
|
isReadOnly: isReadOnly,
|
|
45
47
|
document: document,
|
|
@@ -63,7 +63,8 @@ export var ShareModal = withLocales(function (props) {
|
|
|
63
63
|
|
|
64
64
|
if (isFederatedMode && allLoaded) {
|
|
65
65
|
return /*#__PURE__*/React.createElement(FederatedFolderModal, _extends({
|
|
66
|
-
document: document
|
|
66
|
+
document: document,
|
|
67
|
+
onRevokeSuccess: onRevokeSuccess
|
|
67
68
|
}, rest));
|
|
68
69
|
}
|
|
69
70
|
|
|
@@ -30,6 +30,8 @@ var RecipientWaitingForConfirmationAlert = function RecipientWaitingForConfirmat
|
|
|
30
30
|
var WhoHasAccess = function WhoHasAccess(_ref2) {
|
|
31
31
|
var _ref2$isOwner = _ref2.isOwner,
|
|
32
32
|
isOwner = _ref2$isOwner === void 0 ? false : _ref2$isOwner,
|
|
33
|
+
_ref2$canManageSharin = _ref2.canManageSharing,
|
|
34
|
+
canManageSharing = _ref2$canManageSharin === void 0 ? isOwner : _ref2$canManageSharin,
|
|
33
35
|
_ref2$isSharedDrive = _ref2.isSharedDrive,
|
|
34
36
|
isSharedDrive = _ref2$isSharedDrive === void 0 ? false : _ref2$isSharedDrive,
|
|
35
37
|
_ref2$isReadOnly = _ref2.isReadOnly,
|
|
@@ -68,6 +70,7 @@ var WhoHasAccess = function WhoHasAccess(_ref2) {
|
|
|
68
70
|
recipients: recipients,
|
|
69
71
|
recipientsToBeConfirmed: recipientsToBeConfirmed,
|
|
70
72
|
isOwner: isOwner,
|
|
73
|
+
canManageSharing: canManageSharing,
|
|
71
74
|
isSharedDrive: isSharedDrive,
|
|
72
75
|
isReadOnly: isReadOnly,
|
|
73
76
|
document: document,
|
|
@@ -81,6 +84,7 @@ var WhoHasAccess = function WhoHasAccess(_ref2) {
|
|
|
81
84
|
|
|
82
85
|
WhoHasAccess.propTypes = {
|
|
83
86
|
isOwner: PropTypes.bool,
|
|
87
|
+
canManageSharing: PropTypes.bool,
|
|
84
88
|
showOwner: PropTypes.bool,
|
|
85
89
|
recipients: PropTypes.array.isRequired,
|
|
86
90
|
recipientsToBeConfirmed: PropTypes.arrayOf(PropTypes.shape({
|
package/jest.config.js
CHANGED
|
@@ -26,8 +26,7 @@ module.exports = {
|
|
|
26
26
|
'^cozy-client$': '<rootDir>/node_modules/cozy-client/dist/index.js',
|
|
27
27
|
'^cozy-client/dist/types$':
|
|
28
28
|
'<rootDir>/node_modules/cozy-client/dist/types.js',
|
|
29
|
-
'^twake-i18n$': '<rootDir>/../twake-i18n/dist/index.js'
|
|
30
|
-
'^@linagora/twake-icons$': '<rootDir>/jestHelpers/mocks/twake-icons.js'
|
|
29
|
+
'^twake-i18n$': '<rootDir>/../twake-i18n/dist/index.js'
|
|
31
30
|
},
|
|
32
31
|
transformIgnorePatterns: [
|
|
33
32
|
'<rootDir>/node_modules/(?!(cozy-ui|cozy-harvest-lib|cozy-ui-plus))'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cozy-sharing",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "35.0.0",
|
|
4
4
|
"description": "Provides sharing login for React applications.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"author": "Cozy",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@babel/cli": "7.16.8",
|
|
42
42
|
"@babel/core": "7.16.12",
|
|
43
|
-
"@linagora/twake-icons": "^2.6.
|
|
43
|
+
"@linagora/twake-icons": "^2.6.6",
|
|
44
44
|
"@storybook/addon-essentials": "7.6.0",
|
|
45
45
|
"@storybook/addon-interactions": "7.6.0",
|
|
46
46
|
"@storybook/addon-links": "7.6.0",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"cozy-intent": "^2.31.1",
|
|
60
60
|
"cozy-minilog": "^3.10.1",
|
|
61
61
|
"cozy-ui": "^139.0.2",
|
|
62
|
-
"cozy-ui-plus": "^
|
|
62
|
+
"cozy-ui-plus": "^10.0.0",
|
|
63
63
|
"jest": "30.3.0",
|
|
64
64
|
"jest-environment-jsdom": "30.3.0",
|
|
65
65
|
"react": "16.12.0",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"twake-i18n": "^0.4.1"
|
|
70
70
|
},
|
|
71
71
|
"peerDependencies": {
|
|
72
|
-
"@linagora/twake-icons": ">=2.6.
|
|
72
|
+
"@linagora/twake-icons": ">=2.6.6",
|
|
73
73
|
"cozy-client": ">=60.28.0",
|
|
74
74
|
"cozy-device-helper": ">=4.0.0",
|
|
75
75
|
"cozy-flags": ">=4.8.1",
|
|
@@ -85,5 +85,5 @@
|
|
|
85
85
|
"sideEffects": [
|
|
86
86
|
"*.css"
|
|
87
87
|
],
|
|
88
|
-
"gitHead": "
|
|
88
|
+
"gitHead": "113feef92df29d2b6fe30bad984d3f5a70659b6f"
|
|
89
89
|
}
|
|
@@ -27,6 +27,7 @@ const log = minilog('FederatedFolderModal')
|
|
|
27
27
|
|
|
28
28
|
const FederatedFolderModalContent = ({
|
|
29
29
|
onClose,
|
|
30
|
+
onRevokeSuccess,
|
|
30
31
|
document: existingDocument,
|
|
31
32
|
autoOpenShareRestriction,
|
|
32
33
|
showGenerateLinkButton
|
|
@@ -44,7 +45,9 @@ const FederatedFolderModalContent = ({
|
|
|
44
45
|
getSharedParentPath,
|
|
45
46
|
hasSharedChild,
|
|
46
47
|
hasSharedParent,
|
|
47
|
-
|
|
48
|
+
isOwner,
|
|
49
|
+
revoke,
|
|
50
|
+
revokeSelf
|
|
48
51
|
} = useSharingContext()
|
|
49
52
|
const { showAlert } = useAlert()
|
|
50
53
|
const { showConfirmDialog, closeConfirmDialog } = useConfirmDialog()
|
|
@@ -220,6 +223,12 @@ const FederatedFolderModalContent = ({
|
|
|
220
223
|
const displayedLink = existingDocument?.driveId
|
|
221
224
|
? getFederatedShareLink(existingDocument)
|
|
222
225
|
: getSharingLink(existingDocument?._id)
|
|
226
|
+
const isCurrentUserOwner = documentId ? isOwner(documentId) : false
|
|
227
|
+
|
|
228
|
+
const handleRevokeSelf = async document => {
|
|
229
|
+
await revokeSelf(document)
|
|
230
|
+
onRevokeSuccess?.(document)
|
|
231
|
+
}
|
|
223
232
|
|
|
224
233
|
useEffect(() => {
|
|
225
234
|
if (!existingDocument?.driveId) return
|
|
@@ -313,13 +322,14 @@ const FederatedFolderModalContent = ({
|
|
|
313
322
|
)}
|
|
314
323
|
</div>
|
|
315
324
|
<WhoHasAccess
|
|
316
|
-
isOwner
|
|
325
|
+
isOwner={isCurrentUserOwner}
|
|
317
326
|
isSharedDrive
|
|
318
327
|
recipients={isSending ? frozenRecipients : existingRecipients}
|
|
319
328
|
document={isSending ? frozenDoc : existingDocument}
|
|
320
329
|
documentType="Files"
|
|
321
330
|
className={styles['share-dialog-members']}
|
|
322
331
|
onRevoke={revoke}
|
|
332
|
+
onRevokeSelf={handleRevokeSelf}
|
|
323
333
|
link={displayedLink}
|
|
324
334
|
/>
|
|
325
335
|
</div>
|
|
@@ -355,6 +365,7 @@ export const FederatedFolderModal = withLocales(props => (
|
|
|
355
365
|
|
|
356
366
|
FederatedFolderModal.propTypes = {
|
|
357
367
|
onClose: PropTypes.func.isRequired,
|
|
368
|
+
onRevokeSuccess: PropTypes.func,
|
|
358
369
|
document: PropTypes.object.isRequired,
|
|
359
370
|
autoOpenShareRestriction: PropTypes.bool,
|
|
360
371
|
showGenerateLinkButton: PropTypes.bool
|
|
@@ -11,6 +11,8 @@ import AppLike from '../SharingBanner/test/AppLike'
|
|
|
11
11
|
const mockShare = jest.fn()
|
|
12
12
|
const mockShareByLink = jest.fn()
|
|
13
13
|
const mockRevoke = jest.fn()
|
|
14
|
+
const mockRevokeSelf = jest.fn()
|
|
15
|
+
const mockIsOwner = jest.fn()
|
|
14
16
|
const mockGetSharingLink = jest.fn()
|
|
15
17
|
const mockGetFederatedShareLink = jest.fn()
|
|
16
18
|
const mockGetRecipients = jest.fn().mockReturnValue([])
|
|
@@ -27,6 +29,8 @@ jest.mock('../../hooks/useSharingContext', () => ({
|
|
|
27
29
|
share: mockShare,
|
|
28
30
|
shareByLink: mockShareByLink,
|
|
29
31
|
revoke: mockRevoke,
|
|
32
|
+
revokeSelf: mockRevokeSelf,
|
|
33
|
+
isOwner: mockIsOwner,
|
|
30
34
|
getSharingLink: mockGetSharingLink,
|
|
31
35
|
getFederatedShareLink: mockGetFederatedShareLink,
|
|
32
36
|
getDocumentPermissions: mockGetDocumentPermissions,
|
|
@@ -101,6 +105,9 @@ describe('FederatedFolderModal', () => {
|
|
|
101
105
|
|
|
102
106
|
beforeEach(() => {
|
|
103
107
|
jest.clearAllMocks()
|
|
108
|
+
mockRevoke.mockResolvedValue()
|
|
109
|
+
mockRevokeSelf.mockResolvedValue()
|
|
110
|
+
mockIsOwner.mockReturnValue(false)
|
|
104
111
|
mockGetDocumentPermissions.mockReturnValue([])
|
|
105
112
|
mockFetchSharedDriveSharingLinks.mockResolvedValue([])
|
|
106
113
|
mockGetSharingLink.mockReturnValue('https://example.com/share/abc123')
|
|
@@ -125,6 +132,10 @@ describe('FederatedFolderModal', () => {
|
|
|
125
132
|
}
|
|
126
133
|
})
|
|
127
134
|
client = createTestClient()
|
|
135
|
+
client.options = {
|
|
136
|
+
...client.options,
|
|
137
|
+
uri: 'https://me.mycozy.cloud'
|
|
138
|
+
}
|
|
128
139
|
sharingContextValue = createSharingContextValue()
|
|
129
140
|
usePendingRecipients.mockReturnValue({
|
|
130
141
|
pendingRecipients: [],
|
|
@@ -438,6 +449,30 @@ describe('FederatedFolderModal', () => {
|
|
|
438
449
|
})
|
|
439
450
|
})
|
|
440
451
|
|
|
452
|
+
describe('onRevoke callback', () => {
|
|
453
|
+
const currentUserRecipient = {
|
|
454
|
+
instance: 'https://me.mycozy.cloud',
|
|
455
|
+
memberIndex: 1,
|
|
456
|
+
sharingId: 'sharing-id',
|
|
457
|
+
type: 'two-way'
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
it('should call onRevokeSelf and onRevokeSuccess when the current user is revoked', async () => {
|
|
461
|
+
const onRevokeSuccess = jest.fn()
|
|
462
|
+
mockGetRecipients.mockReturnValue([currentUserRecipient])
|
|
463
|
+
|
|
464
|
+
const { findByLabelText } = setup({ onRevokeSuccess })
|
|
465
|
+
|
|
466
|
+
fireEvent.click(await findByLabelText('Remove from sharing'))
|
|
467
|
+
|
|
468
|
+
await waitFor(() => {
|
|
469
|
+
expect(mockRevokeSelf).toHaveBeenCalledWith(mockDocument)
|
|
470
|
+
expect(mockRevoke).not.toHaveBeenCalled()
|
|
471
|
+
expect(onRevokeSuccess).toHaveBeenCalledWith(mockDocument)
|
|
472
|
+
})
|
|
473
|
+
})
|
|
474
|
+
})
|
|
475
|
+
|
|
441
476
|
describe('onClose callback', () => {
|
|
442
477
|
it('should call onClose when close button is clicked', async () => {
|
|
443
478
|
const { findByRole } = setup()
|
|
@@ -20,6 +20,7 @@ const log = minilog('MemberRecipientPermissions')
|
|
|
20
20
|
|
|
21
21
|
const MemberRecipientPermissions = ({
|
|
22
22
|
isOwner,
|
|
23
|
+
canManageSharing = isOwner,
|
|
23
24
|
isReadOnly,
|
|
24
25
|
status,
|
|
25
26
|
instance,
|
|
@@ -46,7 +47,7 @@ const MemberRecipientPermissions = ({
|
|
|
46
47
|
!isReadOnly &&
|
|
47
48
|
!revoking &&
|
|
48
49
|
!contactIsOwner &&
|
|
49
|
-
((instanceMatchesClient && !isOwner) ||
|
|
50
|
+
((instanceMatchesClient && !isOwner) || canManageSharing)
|
|
50
51
|
|
|
51
52
|
const toggleMenu = useCallback(() => {
|
|
52
53
|
setMenuDisplayed(displayed => !displayed)
|
|
@@ -58,15 +59,23 @@ const MemberRecipientPermissions = ({
|
|
|
58
59
|
const handleRevocation = useCallback(async () => {
|
|
59
60
|
setRevoking(true)
|
|
60
61
|
try {
|
|
61
|
-
if (isOwner) {
|
|
62
|
-
await onRevoke(document, sharingId, memberIndex)
|
|
63
|
-
} else {
|
|
62
|
+
if (instanceMatchesClient && !isOwner) {
|
|
64
63
|
await onRevokeSelf(document)
|
|
64
|
+
} else {
|
|
65
|
+
await onRevoke(document, sharingId, memberIndex)
|
|
65
66
|
}
|
|
66
67
|
} finally {
|
|
67
68
|
setRevoking(false)
|
|
68
69
|
}
|
|
69
|
-
}, [
|
|
70
|
+
}, [
|
|
71
|
+
document,
|
|
72
|
+
instanceMatchesClient,
|
|
73
|
+
isOwner,
|
|
74
|
+
memberIndex,
|
|
75
|
+
onRevoke,
|
|
76
|
+
onRevokeSelf,
|
|
77
|
+
sharingId
|
|
78
|
+
])
|
|
70
79
|
|
|
71
80
|
const setType = useCallback(
|
|
72
81
|
async newType => {
|
|
@@ -9,6 +9,7 @@ const RecipientList = ({
|
|
|
9
9
|
recipients,
|
|
10
10
|
recipientsToBeConfirmed,
|
|
11
11
|
isOwner,
|
|
12
|
+
canManageSharing,
|
|
12
13
|
isSharedDrive,
|
|
13
14
|
isReadOnly,
|
|
14
15
|
document,
|
|
@@ -50,6 +51,7 @@ const RecipientList = ({
|
|
|
50
51
|
{...recipient}
|
|
51
52
|
key={recipient.index}
|
|
52
53
|
isOwner={isOwner}
|
|
54
|
+
canManageSharing={canManageSharing}
|
|
53
55
|
isSharedDrive={isSharedDrive}
|
|
54
56
|
isReadOnly={isReadOnly}
|
|
55
57
|
document={document}
|
|
@@ -38,7 +38,13 @@ export const ShareModal = withLocales(props => {
|
|
|
38
38
|
if (isEditable) {
|
|
39
39
|
const isFederatedMode = flag('drive.federated-shared-folder.enabled')
|
|
40
40
|
if (isFederatedMode && allLoaded) {
|
|
41
|
-
return
|
|
41
|
+
return (
|
|
42
|
+
<FederatedFolderModal
|
|
43
|
+
document={document}
|
|
44
|
+
onRevokeSuccess={onRevokeSuccess}
|
|
45
|
+
{...rest}
|
|
46
|
+
/>
|
|
47
|
+
)
|
|
42
48
|
}
|
|
43
49
|
|
|
44
50
|
return <EditableSharingModal document={document} {...rest} />
|
|
@@ -28,6 +28,7 @@ const RecipientWaitingForConfirmationAlert = ({ recipientsToBeConfirmed }) => {
|
|
|
28
28
|
|
|
29
29
|
const WhoHasAccess = ({
|
|
30
30
|
isOwner = false,
|
|
31
|
+
canManageSharing = isOwner,
|
|
31
32
|
isSharedDrive = false,
|
|
32
33
|
isReadOnly = false,
|
|
33
34
|
showOwner = true,
|
|
@@ -70,6 +71,7 @@ const WhoHasAccess = ({
|
|
|
70
71
|
recipients={recipients}
|
|
71
72
|
recipientsToBeConfirmed={recipientsToBeConfirmed}
|
|
72
73
|
isOwner={isOwner}
|
|
74
|
+
canManageSharing={canManageSharing}
|
|
73
75
|
isSharedDrive={isSharedDrive}
|
|
74
76
|
isReadOnly={isReadOnly}
|
|
75
77
|
document={document}
|
|
@@ -86,6 +88,7 @@ const WhoHasAccess = ({
|
|
|
86
88
|
|
|
87
89
|
WhoHasAccess.propTypes = {
|
|
88
90
|
isOwner: PropTypes.bool,
|
|
91
|
+
canManageSharing: PropTypes.bool,
|
|
89
92
|
showOwner: PropTypes.bool,
|
|
90
93
|
recipients: PropTypes.array.isRequired,
|
|
91
94
|
recipientsToBeConfirmed: PropTypes.arrayOf(
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
const React = require('react')
|
|
2
|
-
|
|
3
|
-
const Icon = ({ icon, iconRef, ...props }) =>
|
|
4
|
-
React.createElement('svg', { 'data-icon': true, ...props })
|
|
5
|
-
|
|
6
|
-
const Sprite = () => null
|
|
7
|
-
|
|
8
|
-
const getFileTypeIcon = () =>
|
|
9
|
-
function FileTypeIcon() {
|
|
10
|
-
return React.createElement('svg', { 'data-filetypeicon': true })
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const proxyHandler = {
|
|
14
|
-
get: function (target, prop) {
|
|
15
|
-
if (prop in target) return target[prop]
|
|
16
|
-
if (prop === 'default') return target.Icon
|
|
17
|
-
return function IconMock({ iconRef, ...props }) {
|
|
18
|
-
return React.createElement('svg', { 'data-mock-icon': prop, ...props })
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
module.exports = new Proxy({ Icon, Sprite, getFileTypeIcon }, proxyHandler)
|