cozy-sharing 38.1.0 → 38.1.1
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 +7 -0
- package/dist/components/FederatedFolder/FederatedFolderModal.js +4 -3
- package/dist/components/FederatedFolder/FederatedFolderModal.spec.js +185 -153
- package/dist/components/ShareModal/ShareModal.js +2 -2
- package/dist/components/ShareModal/ShareModal.spec.js +79 -0
- package/package.json +3 -3
- package/src/components/FederatedFolder/FederatedFolderModal.jsx +7 -3
- package/src/components/FederatedFolder/FederatedFolderModal.spec.jsx +22 -0
- package/src/components/ShareModal/ShareModal.jsx +4 -2
- package/src/components/ShareModal/ShareModal.spec.jsx +66 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,13 @@
|
|
|
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
|
+
## [38.1.1](https://github.com/cozy/cozy-libs/compare/cozy-sharing@38.1.0...cozy-sharing@38.1.1) (2026-09-21)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- **sharing:** Keep full share modal for nested-folder editors ([014c848](https://github.com/cozy/cozy-libs/commit/014c848bb46699cee47eb4baf8bb7a365edaf2f1))
|
|
11
|
+
- **sharing:** Show editable share modal for members with write access ([cba3a13](https://github.com/cozy/cozy-libs/commit/cba3a13185d1fe088136c3a758ec94f0d3472b69))
|
|
12
|
+
|
|
6
13
|
# [38.1.0](https://github.com/cozy/cozy-libs/compare/cozy-sharing@38.0.0...cozy-sharing@38.1.0) (2026-09-16)
|
|
7
14
|
|
|
8
15
|
### Features
|
|
@@ -64,6 +64,7 @@ var FederatedFolderModalContent = function FederatedFolderModalContent(_ref) {
|
|
|
64
64
|
|
|
65
65
|
var _useSharingContext = useSharingContext(),
|
|
66
66
|
canReshare = _useSharingContext.canReshare,
|
|
67
|
+
hasWriteAccess = _useSharingContext.hasWriteAccess,
|
|
67
68
|
share = _useSharingContext.share,
|
|
68
69
|
getSharingById = _useSharingContext.getSharingById,
|
|
69
70
|
getSharingLink = _useSharingContext.getSharingLink,
|
|
@@ -125,7 +126,7 @@ var FederatedFolderModalContent = function FederatedFolderModalContent(_ref) {
|
|
|
125
126
|
}));
|
|
126
127
|
var isInsideSharedDrive = Boolean((existingDocument === null || existingDocument === void 0 ? void 0 : existingDocument.driveId) && !isSharedDriveRoot);
|
|
127
128
|
var isCurrentUserOwner = existingDocument !== null && existingDocument !== void 0 && existingDocument.driveId ? Boolean(sharedDriveSharing === null || sharedDriveSharing === void 0 || (_sharedDriveSharing$a2 = sharedDriveSharing.attributes) === null || _sharedDriveSharing$a2 === void 0 ? void 0 : _sharedDriveSharing$a2.owner) : documentId ? isOwner(documentId) : false;
|
|
128
|
-
var isMemberReadOnly = isInsideSharedDrive && !isCurrentUserOwner;
|
|
129
|
+
var isMemberReadOnly = isInsideSharedDrive && !isCurrentUserOwner && !hasWriteAccess(documentId, existingDocument === null || existingDocument === void 0 ? void 0 : existingDocument.driveId);
|
|
129
130
|
var canManageSharing = isCurrentUserOwner || (documentId ? canReshare(documentId) : false);
|
|
130
131
|
|
|
131
132
|
var handleRevokeSelf = /*#__PURE__*/function () {
|
|
@@ -318,7 +319,7 @@ var FederatedFolderModalContent = function FederatedFolderModalContent(_ref) {
|
|
|
318
319
|
className: "u-ph-2"
|
|
319
320
|
}, /*#__PURE__*/React.createElement(AntivirusAlert, {
|
|
320
321
|
document: isSending ? frozenDoc : existingDocument
|
|
321
|
-
}),
|
|
322
|
+
}), isMemberReadOnly ? /*#__PURE__*/React.createElement("div", {
|
|
322
323
|
className: styles['share-byemail-onlybylink']
|
|
323
324
|
}, t('Files.share.shareByEmail.onlyByLink', {
|
|
324
325
|
type: t("Files.share.shareByEmail.type.".concat((existingDocument === null || existingDocument === void 0 ? void 0 : existingDocument.type) === 'file' ? 'file' : 'folder'))
|
|
@@ -354,7 +355,7 @@ var FederatedFolderModalContent = function FederatedFolderModalContent(_ref) {
|
|
|
354
355
|
documentType: "Files",
|
|
355
356
|
showGenerateLinkButton: showGenerateLinkButton,
|
|
356
357
|
autoOpenShareRestriction: autoOpenShareRestriction
|
|
357
|
-
}), !
|
|
358
|
+
}), !isMemberReadOnly && /*#__PURE__*/React.createElement(Button, {
|
|
358
359
|
variant: "primary",
|
|
359
360
|
label: t('FederatedFolder.share'),
|
|
360
361
|
busy: isSending,
|
|
@@ -20,6 +20,7 @@ var mockRevoke = jest.fn();
|
|
|
20
20
|
var mockRevokeSelf = jest.fn();
|
|
21
21
|
var mockIsOwner = jest.fn();
|
|
22
22
|
var mockCanReshare = jest.fn();
|
|
23
|
+
var mockHasWriteAccess = jest.fn();
|
|
23
24
|
var mockGetSharingLink = jest.fn();
|
|
24
25
|
var mockGetFederatedShareLink = jest.fn();
|
|
25
26
|
var mockGetSharingById = jest.fn();
|
|
@@ -42,6 +43,7 @@ jest.mock('../../hooks/useSharingContext', function () {
|
|
|
42
43
|
revokeSelf: mockRevokeSelf,
|
|
43
44
|
isOwner: mockIsOwner,
|
|
44
45
|
canReshare: mockCanReshare,
|
|
46
|
+
hasWriteAccess: mockHasWriteAccess,
|
|
45
47
|
getSharingLink: mockGetSharingLink,
|
|
46
48
|
getFederatedShareLink: mockGetFederatedShareLink,
|
|
47
49
|
getDocumentPermissions: mockGetDocumentPermissions,
|
|
@@ -142,6 +144,7 @@ describe('FederatedFolderModal', function () {
|
|
|
142
144
|
mockRevokeSelf.mockResolvedValue();
|
|
143
145
|
mockIsOwner.mockReturnValue(false);
|
|
144
146
|
mockCanReshare.mockReturnValue(false);
|
|
147
|
+
mockHasWriteAccess.mockReturnValue(false);
|
|
145
148
|
mockGetDocumentPermissions.mockReturnValue([]);
|
|
146
149
|
mockFetchSharedDriveSharingLinks.mockResolvedValue([]);
|
|
147
150
|
mockGetSharingLink.mockReturnValue('https://example.com/share/abc123');
|
|
@@ -319,11 +322,40 @@ describe('FederatedFolderModal', function () {
|
|
|
319
322
|
}
|
|
320
323
|
}, _callee6);
|
|
321
324
|
})));
|
|
322
|
-
it('should allow share by email when
|
|
325
|
+
it('should allow share by email when the current user has write access, even inside a federated shared folder', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee7() {
|
|
323
326
|
var _setup7, findByText, queryByText;
|
|
324
327
|
|
|
325
328
|
return _regeneratorRuntime.wrap(function _callee7$(_context7) {
|
|
326
329
|
while (1) switch (_context7.prev = _context7.next) {
|
|
330
|
+
case 0:
|
|
331
|
+
mockHasWriteAccess.mockReturnValue(true);
|
|
332
|
+
_setup7 = setup({
|
|
333
|
+
document: _objectSpread(_objectSpread({}, mockDocument), {}, {
|
|
334
|
+
driveId: 'federated-folder-id',
|
|
335
|
+
type: 'directory'
|
|
336
|
+
})
|
|
337
|
+
}), findByText = _setup7.findByText, queryByText = _setup7.queryByText;
|
|
338
|
+
_context7.next = 4;
|
|
339
|
+
return findByText('Add users');
|
|
340
|
+
|
|
341
|
+
case 4:
|
|
342
|
+
_context7.next = 6;
|
|
343
|
+
return findByText('Done');
|
|
344
|
+
|
|
345
|
+
case 6:
|
|
346
|
+
expect(queryByText('This folder can only be shared by link, because')).toBe(null);
|
|
347
|
+
|
|
348
|
+
case 7:
|
|
349
|
+
case "end":
|
|
350
|
+
return _context7.stop();
|
|
351
|
+
}
|
|
352
|
+
}, _callee7);
|
|
353
|
+
})));
|
|
354
|
+
it('should allow share by email when document is the federated shared folder root', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee8() {
|
|
355
|
+
var _setup8, findByText, queryByText;
|
|
356
|
+
|
|
357
|
+
return _regeneratorRuntime.wrap(function _callee8$(_context8) {
|
|
358
|
+
while (1) switch (_context8.prev = _context8.next) {
|
|
327
359
|
case 0:
|
|
328
360
|
mockGetSharingById.mockReturnValue({
|
|
329
361
|
attributes: {
|
|
@@ -334,13 +366,13 @@ describe('FederatedFolderModal', function () {
|
|
|
334
366
|
}]
|
|
335
367
|
}
|
|
336
368
|
});
|
|
337
|
-
|
|
369
|
+
_setup8 = setup({
|
|
338
370
|
document: _objectSpread(_objectSpread({}, mockDocument), {}, {
|
|
339
371
|
driveId: 'federated-folder-id',
|
|
340
372
|
type: 'directory'
|
|
341
373
|
})
|
|
342
|
-
}), findByText =
|
|
343
|
-
|
|
374
|
+
}), findByText = _setup8.findByText, queryByText = _setup8.queryByText;
|
|
375
|
+
_context8.next = 4;
|
|
344
376
|
return findByText('Add users');
|
|
345
377
|
|
|
346
378
|
case 4:
|
|
@@ -349,15 +381,15 @@ describe('FederatedFolderModal', function () {
|
|
|
349
381
|
|
|
350
382
|
case 6:
|
|
351
383
|
case "end":
|
|
352
|
-
return
|
|
384
|
+
return _context8.stop();
|
|
353
385
|
}
|
|
354
|
-
},
|
|
386
|
+
}, _callee8);
|
|
355
387
|
})));
|
|
356
388
|
});
|
|
357
389
|
describe('shared drive link fetch on mount', function () {
|
|
358
|
-
it('should fetch shared drive sharing links when document has a driveId and no permissions yet', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function
|
|
359
|
-
return _regeneratorRuntime.wrap(function
|
|
360
|
-
while (1) switch (
|
|
390
|
+
it('should fetch shared drive sharing links when document has a driveId and no permissions yet', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee9() {
|
|
391
|
+
return _regeneratorRuntime.wrap(function _callee9$(_context9) {
|
|
392
|
+
while (1) switch (_context9.prev = _context9.next) {
|
|
361
393
|
case 0:
|
|
362
394
|
mockGetDocumentPermissions.mockReturnValue([]);
|
|
363
395
|
setup({
|
|
@@ -365,7 +397,7 @@ describe('FederatedFolderModal', function () {
|
|
|
365
397
|
driveId: 'federated-folder-id'
|
|
366
398
|
})
|
|
367
399
|
});
|
|
368
|
-
|
|
400
|
+
_context9.next = 4;
|
|
369
401
|
return waitFor(function () {
|
|
370
402
|
expect(mockFetchSharedDriveSharingLinks).toHaveBeenCalledTimes(1);
|
|
371
403
|
});
|
|
@@ -378,14 +410,14 @@ describe('FederatedFolderModal', function () {
|
|
|
378
410
|
|
|
379
411
|
case 5:
|
|
380
412
|
case "end":
|
|
381
|
-
return
|
|
413
|
+
return _context9.stop();
|
|
382
414
|
}
|
|
383
|
-
},
|
|
415
|
+
}, _callee9);
|
|
384
416
|
})));
|
|
385
|
-
it('should use document.id when _id is missing', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function
|
|
417
|
+
it('should use document.id when _id is missing', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee10() {
|
|
386
418
|
var document;
|
|
387
|
-
return _regeneratorRuntime.wrap(function
|
|
388
|
-
while (1) switch (
|
|
419
|
+
return _regeneratorRuntime.wrap(function _callee10$(_context10) {
|
|
420
|
+
while (1) switch (_context10.prev = _context10.next) {
|
|
389
421
|
case 0:
|
|
390
422
|
document = {
|
|
391
423
|
id: 'folder-id-only',
|
|
@@ -396,7 +428,7 @@ describe('FederatedFolderModal', function () {
|
|
|
396
428
|
setup({
|
|
397
429
|
document: document
|
|
398
430
|
});
|
|
399
|
-
|
|
431
|
+
_context10.next = 4;
|
|
400
432
|
return waitFor(function () {
|
|
401
433
|
expect(mockFetchSharedDriveSharingLinks).toHaveBeenCalledWith(document);
|
|
402
434
|
});
|
|
@@ -406,20 +438,20 @@ describe('FederatedFolderModal', function () {
|
|
|
406
438
|
|
|
407
439
|
case 5:
|
|
408
440
|
case "end":
|
|
409
|
-
return
|
|
441
|
+
return _context10.stop();
|
|
410
442
|
}
|
|
411
|
-
},
|
|
443
|
+
}, _callee10);
|
|
412
444
|
})));
|
|
413
|
-
it('should not fetch shared drive sharing links when document has no driveId', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function
|
|
414
|
-
var
|
|
445
|
+
it('should not fetch shared drive sharing links when document has no driveId', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee11() {
|
|
446
|
+
var _setup9, findByText;
|
|
415
447
|
|
|
416
|
-
return _regeneratorRuntime.wrap(function
|
|
417
|
-
while (1) switch (
|
|
448
|
+
return _regeneratorRuntime.wrap(function _callee11$(_context11) {
|
|
449
|
+
while (1) switch (_context11.prev = _context11.next) {
|
|
418
450
|
case 0:
|
|
419
|
-
|
|
451
|
+
_setup9 = setup({
|
|
420
452
|
document: mockDocument
|
|
421
|
-
}), findByText =
|
|
422
|
-
|
|
453
|
+
}), findByText = _setup9.findByText;
|
|
454
|
+
_context11.next = 3;
|
|
423
455
|
return findByText('Copy link');
|
|
424
456
|
|
|
425
457
|
case 3:
|
|
@@ -427,23 +459,23 @@ describe('FederatedFolderModal', function () {
|
|
|
427
459
|
|
|
428
460
|
case 4:
|
|
429
461
|
case "end":
|
|
430
|
-
return
|
|
462
|
+
return _context11.stop();
|
|
431
463
|
}
|
|
432
|
-
},
|
|
464
|
+
}, _callee11);
|
|
433
465
|
})));
|
|
434
|
-
it('should not refetch after one attempt when permissions stay empty', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function
|
|
435
|
-
var document,
|
|
466
|
+
it('should not refetch after one attempt when permissions stay empty', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee12() {
|
|
467
|
+
var document, _setup10, rerender;
|
|
436
468
|
|
|
437
|
-
return _regeneratorRuntime.wrap(function
|
|
438
|
-
while (1) switch (
|
|
469
|
+
return _regeneratorRuntime.wrap(function _callee12$(_context12) {
|
|
470
|
+
while (1) switch (_context12.prev = _context12.next) {
|
|
439
471
|
case 0:
|
|
440
472
|
document = _objectSpread(_objectSpread({}, mockDocument), {}, {
|
|
441
473
|
driveId: 'federated-folder-id'
|
|
442
474
|
});
|
|
443
|
-
|
|
475
|
+
_setup10 = setup({
|
|
444
476
|
document: document
|
|
445
|
-
}), rerender =
|
|
446
|
-
|
|
477
|
+
}), rerender = _setup10.rerender;
|
|
478
|
+
_context12.next = 4;
|
|
447
479
|
return waitFor(function () {
|
|
448
480
|
expect(mockFetchSharedDriveSharingLinks).toHaveBeenCalledTimes(1);
|
|
449
481
|
});
|
|
@@ -460,15 +492,15 @@ describe('FederatedFolderModal', function () {
|
|
|
460
492
|
|
|
461
493
|
case 6:
|
|
462
494
|
case "end":
|
|
463
|
-
return
|
|
495
|
+
return _context12.stop();
|
|
464
496
|
}
|
|
465
|
-
},
|
|
497
|
+
}, _callee12);
|
|
466
498
|
})));
|
|
467
|
-
it('should not fetch shared drive sharing links when permissions are already loaded', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function
|
|
468
|
-
var
|
|
499
|
+
it('should not fetch shared drive sharing links when permissions are already loaded', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee13() {
|
|
500
|
+
var _setup11, findByText;
|
|
469
501
|
|
|
470
|
-
return _regeneratorRuntime.wrap(function
|
|
471
|
-
while (1) switch (
|
|
502
|
+
return _regeneratorRuntime.wrap(function _callee13$(_context13) {
|
|
503
|
+
while (1) switch (_context13.prev = _context13.next) {
|
|
472
504
|
case 0:
|
|
473
505
|
mockGetDocumentPermissions.mockReturnValue([{
|
|
474
506
|
id: 'perm-1',
|
|
@@ -479,12 +511,12 @@ describe('FederatedFolderModal', function () {
|
|
|
479
511
|
}
|
|
480
512
|
}
|
|
481
513
|
}]);
|
|
482
|
-
|
|
514
|
+
_setup11 = setup({
|
|
483
515
|
document: _objectSpread(_objectSpread({}, mockDocument), {}, {
|
|
484
516
|
driveId: 'federated-folder-id'
|
|
485
517
|
})
|
|
486
|
-
}), findByText =
|
|
487
|
-
|
|
518
|
+
}), findByText = _setup11.findByText;
|
|
519
|
+
_context13.next = 4;
|
|
488
520
|
return findByText('Copy link');
|
|
489
521
|
|
|
490
522
|
case 4:
|
|
@@ -492,9 +524,9 @@ describe('FederatedFolderModal', function () {
|
|
|
492
524
|
|
|
493
525
|
case 5:
|
|
494
526
|
case "end":
|
|
495
|
-
return
|
|
527
|
+
return _context13.stop();
|
|
496
528
|
}
|
|
497
|
-
},
|
|
529
|
+
}, _callee13);
|
|
498
530
|
})));
|
|
499
531
|
});
|
|
500
532
|
describe('onSend callback', function () {
|
|
@@ -502,21 +534,21 @@ describe('FederatedFolderModal', function () {
|
|
|
502
534
|
name: 'Alice',
|
|
503
535
|
email: 'alice@example.com'
|
|
504
536
|
};
|
|
505
|
-
it('should call onClose and skip share when there are no pending recipients', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function
|
|
506
|
-
var
|
|
537
|
+
it('should call onClose and skip share when there are no pending recipients', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee14() {
|
|
538
|
+
var _setup12, findByText, sendButton;
|
|
507
539
|
|
|
508
|
-
return _regeneratorRuntime.wrap(function
|
|
509
|
-
while (1) switch (
|
|
540
|
+
return _regeneratorRuntime.wrap(function _callee14$(_context14) {
|
|
541
|
+
while (1) switch (_context14.prev = _context14.next) {
|
|
510
542
|
case 0:
|
|
511
543
|
// pendingRecipients defaults to [] via beforeEach
|
|
512
|
-
|
|
513
|
-
|
|
544
|
+
_setup12 = setup(), findByText = _setup12.findByText;
|
|
545
|
+
_context14.next = 3;
|
|
514
546
|
return findByText('Done');
|
|
515
547
|
|
|
516
548
|
case 3:
|
|
517
|
-
sendButton =
|
|
549
|
+
sendButton = _context14.sent;
|
|
518
550
|
fireEvent.click(sendButton);
|
|
519
|
-
|
|
551
|
+
_context14.next = 7;
|
|
520
552
|
return waitFor(function () {
|
|
521
553
|
expect(mockOnClose).toHaveBeenCalled();
|
|
522
554
|
expect(mockShare).not.toHaveBeenCalled();
|
|
@@ -524,15 +556,15 @@ describe('FederatedFolderModal', function () {
|
|
|
524
556
|
|
|
525
557
|
case 7:
|
|
526
558
|
case "end":
|
|
527
|
-
return
|
|
559
|
+
return _context14.stop();
|
|
528
560
|
}
|
|
529
|
-
},
|
|
561
|
+
}, _callee14);
|
|
530
562
|
})));
|
|
531
|
-
it('should call share with correct parameters', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function
|
|
532
|
-
var
|
|
563
|
+
it('should call share with correct parameters', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee15() {
|
|
564
|
+
var _setup13, findByText, sendButton;
|
|
533
565
|
|
|
534
|
-
return _regeneratorRuntime.wrap(function
|
|
535
|
-
while (1) switch (
|
|
566
|
+
return _regeneratorRuntime.wrap(function _callee15$(_context15) {
|
|
567
|
+
while (1) switch (_context15.prev = _context15.next) {
|
|
536
568
|
case 0:
|
|
537
569
|
usePendingRecipients.mockReturnValue({
|
|
538
570
|
pendingRecipients: [pendingRecipient],
|
|
@@ -542,14 +574,14 @@ describe('FederatedFolderModal', function () {
|
|
|
542
574
|
});
|
|
543
575
|
getOrCreateFromArray.mockResolvedValue([pendingRecipient]);
|
|
544
576
|
mockShare.mockResolvedValueOnce({});
|
|
545
|
-
|
|
546
|
-
|
|
577
|
+
_setup13 = setup(), findByText = _setup13.findByText;
|
|
578
|
+
_context15.next = 6;
|
|
547
579
|
return findByText('Done');
|
|
548
580
|
|
|
549
581
|
case 6:
|
|
550
|
-
sendButton =
|
|
582
|
+
sendButton = _context15.sent;
|
|
551
583
|
fireEvent.click(sendButton);
|
|
552
|
-
|
|
584
|
+
_context15.next = 10;
|
|
553
585
|
return waitFor(function () {
|
|
554
586
|
expect(mockShare).toHaveBeenCalledWith({
|
|
555
587
|
description: 'My Test Folder',
|
|
@@ -563,15 +595,15 @@ describe('FederatedFolderModal', function () {
|
|
|
563
595
|
|
|
564
596
|
case 10:
|
|
565
597
|
case "end":
|
|
566
|
-
return
|
|
598
|
+
return _context15.stop();
|
|
567
599
|
}
|
|
568
|
-
},
|
|
600
|
+
}, _callee15);
|
|
569
601
|
})));
|
|
570
|
-
it('should show success alert and close modal on successful share', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function
|
|
571
|
-
var
|
|
602
|
+
it('should show success alert and close modal on successful share', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee16() {
|
|
603
|
+
var _setup14, findByText, sendButton;
|
|
572
604
|
|
|
573
|
-
return _regeneratorRuntime.wrap(function
|
|
574
|
-
while (1) switch (
|
|
605
|
+
return _regeneratorRuntime.wrap(function _callee16$(_context16) {
|
|
606
|
+
while (1) switch (_context16.prev = _context16.next) {
|
|
575
607
|
case 0:
|
|
576
608
|
usePendingRecipients.mockReturnValue({
|
|
577
609
|
pendingRecipients: [pendingRecipient],
|
|
@@ -581,14 +613,14 @@ describe('FederatedFolderModal', function () {
|
|
|
581
613
|
});
|
|
582
614
|
getOrCreateFromArray.mockResolvedValue([pendingRecipient]);
|
|
583
615
|
mockShare.mockResolvedValueOnce({});
|
|
584
|
-
|
|
585
|
-
|
|
616
|
+
_setup14 = setup(), findByText = _setup14.findByText;
|
|
617
|
+
_context16.next = 6;
|
|
586
618
|
return findByText('Done');
|
|
587
619
|
|
|
588
620
|
case 6:
|
|
589
|
-
sendButton =
|
|
621
|
+
sendButton = _context16.sent;
|
|
590
622
|
fireEvent.click(sendButton);
|
|
591
|
-
|
|
623
|
+
_context16.next = 10;
|
|
592
624
|
return waitFor(function () {
|
|
593
625
|
expect(mockShowAlert).toHaveBeenCalledWith({
|
|
594
626
|
message: 'Folder has been shared',
|
|
@@ -600,15 +632,15 @@ describe('FederatedFolderModal', function () {
|
|
|
600
632
|
|
|
601
633
|
case 10:
|
|
602
634
|
case "end":
|
|
603
|
-
return
|
|
635
|
+
return _context16.stop();
|
|
604
636
|
}
|
|
605
|
-
},
|
|
637
|
+
}, _callee16);
|
|
606
638
|
})));
|
|
607
|
-
it('should show error alert when share fails', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function
|
|
608
|
-
var
|
|
639
|
+
it('should show error alert when share fails', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee17() {
|
|
640
|
+
var _setup15, findByText, sendButton;
|
|
609
641
|
|
|
610
|
-
return _regeneratorRuntime.wrap(function
|
|
611
|
-
while (1) switch (
|
|
642
|
+
return _regeneratorRuntime.wrap(function _callee17$(_context17) {
|
|
643
|
+
while (1) switch (_context17.prev = _context17.next) {
|
|
612
644
|
case 0:
|
|
613
645
|
usePendingRecipients.mockReturnValue({
|
|
614
646
|
pendingRecipients: [pendingRecipient],
|
|
@@ -618,14 +650,14 @@ describe('FederatedFolderModal', function () {
|
|
|
618
650
|
});
|
|
619
651
|
getOrCreateFromArray.mockResolvedValue([pendingRecipient]);
|
|
620
652
|
mockShare.mockRejectedValueOnce(new Error('Share failed'));
|
|
621
|
-
|
|
622
|
-
|
|
653
|
+
_setup15 = setup(), findByText = _setup15.findByText;
|
|
654
|
+
_context17.next = 6;
|
|
623
655
|
return findByText('Done');
|
|
624
656
|
|
|
625
657
|
case 6:
|
|
626
|
-
sendButton =
|
|
658
|
+
sendButton = _context17.sent;
|
|
627
659
|
fireEvent.click(sendButton);
|
|
628
|
-
|
|
660
|
+
_context17.next = 10;
|
|
629
661
|
return waitFor(function () {
|
|
630
662
|
expect(mockShowAlert).toHaveBeenCalledWith({
|
|
631
663
|
message: 'Error while sharing folder',
|
|
@@ -637,15 +669,15 @@ describe('FederatedFolderModal', function () {
|
|
|
637
669
|
|
|
638
670
|
case 10:
|
|
639
671
|
case "end":
|
|
640
|
-
return
|
|
672
|
+
return _context17.stop();
|
|
641
673
|
}
|
|
642
|
-
},
|
|
674
|
+
}, _callee17);
|
|
643
675
|
})));
|
|
644
|
-
it('should show progress icon on Done button while share is in progress', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function
|
|
645
|
-
var resolveShare,
|
|
676
|
+
it('should show progress icon on Done button while share is in progress', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee19() {
|
|
677
|
+
var resolveShare, _setup16, findByText, getByRole, queryByRole, sendButton;
|
|
646
678
|
|
|
647
|
-
return _regeneratorRuntime.wrap(function
|
|
648
|
-
while (1) switch (
|
|
679
|
+
return _regeneratorRuntime.wrap(function _callee19$(_context19) {
|
|
680
|
+
while (1) switch (_context19.prev = _context19.next) {
|
|
649
681
|
case 0:
|
|
650
682
|
usePendingRecipients.mockReturnValue({
|
|
651
683
|
pendingRecipients: [pendingRecipient],
|
|
@@ -657,14 +689,14 @@ describe('FederatedFolderModal', function () {
|
|
|
657
689
|
mockShare.mockReturnValueOnce(new Promise(function (resolve) {
|
|
658
690
|
resolveShare = resolve;
|
|
659
691
|
}));
|
|
660
|
-
|
|
661
|
-
|
|
692
|
+
_setup16 = setup(), findByText = _setup16.findByText, getByRole = _setup16.getByRole, queryByRole = _setup16.queryByRole;
|
|
693
|
+
_context19.next = 6;
|
|
662
694
|
return findByText('Done');
|
|
663
695
|
|
|
664
696
|
case 6:
|
|
665
|
-
sendButton =
|
|
697
|
+
sendButton = _context19.sent;
|
|
666
698
|
fireEvent.click(sendButton);
|
|
667
|
-
|
|
699
|
+
_context19.next = 10;
|
|
668
700
|
return waitFor(function () {
|
|
669
701
|
expect(getByRole('button', {
|
|
670
702
|
name: 'Done'
|
|
@@ -673,25 +705,25 @@ describe('FederatedFolderModal', function () {
|
|
|
673
705
|
});
|
|
674
706
|
|
|
675
707
|
case 10:
|
|
676
|
-
|
|
677
|
-
return act( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function
|
|
678
|
-
return _regeneratorRuntime.wrap(function
|
|
679
|
-
while (1) switch (
|
|
708
|
+
_context19.next = 12;
|
|
709
|
+
return act( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee18() {
|
|
710
|
+
return _regeneratorRuntime.wrap(function _callee18$(_context18) {
|
|
711
|
+
while (1) switch (_context18.prev = _context18.next) {
|
|
680
712
|
case 0:
|
|
681
713
|
resolveShare({});
|
|
682
714
|
|
|
683
715
|
case 1:
|
|
684
716
|
case "end":
|
|
685
|
-
return
|
|
717
|
+
return _context18.stop();
|
|
686
718
|
}
|
|
687
|
-
},
|
|
719
|
+
}, _callee18);
|
|
688
720
|
})));
|
|
689
721
|
|
|
690
722
|
case 12:
|
|
691
723
|
case "end":
|
|
692
|
-
return
|
|
724
|
+
return _context19.stop();
|
|
693
725
|
}
|
|
694
|
-
},
|
|
726
|
+
}, _callee19);
|
|
695
727
|
})));
|
|
696
728
|
});
|
|
697
729
|
describe('onRevoke callback', function () {
|
|
@@ -704,27 +736,27 @@ describe('FederatedFolderModal', function () {
|
|
|
704
736
|
name: 'Me',
|
|
705
737
|
email: 'me@test.com'
|
|
706
738
|
};
|
|
707
|
-
it('should call onRevokeSelf and onRevokeSuccess when the current user is revoked', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function
|
|
708
|
-
var onRevokeSuccess,
|
|
739
|
+
it('should call onRevokeSelf and onRevokeSuccess when the current user is revoked', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee20() {
|
|
740
|
+
var onRevokeSuccess, _setup17, findByLabelText;
|
|
709
741
|
|
|
710
|
-
return _regeneratorRuntime.wrap(function
|
|
711
|
-
while (1) switch (
|
|
742
|
+
return _regeneratorRuntime.wrap(function _callee20$(_context20) {
|
|
743
|
+
while (1) switch (_context20.prev = _context20.next) {
|
|
712
744
|
case 0:
|
|
713
745
|
onRevokeSuccess = jest.fn();
|
|
714
746
|
mockGetEffectiveRecipients.mockReturnValue([currentUserRecipient]);
|
|
715
|
-
|
|
747
|
+
_setup17 = setup({
|
|
716
748
|
onRevokeSuccess: onRevokeSuccess
|
|
717
|
-
}), findByLabelText =
|
|
718
|
-
|
|
719
|
-
|
|
749
|
+
}), findByLabelText = _setup17.findByLabelText;
|
|
750
|
+
_context20.t0 = fireEvent;
|
|
751
|
+
_context20.next = 6;
|
|
720
752
|
return findByLabelText('Remove from sharing');
|
|
721
753
|
|
|
722
754
|
case 6:
|
|
723
|
-
|
|
755
|
+
_context20.t1 = _context20.sent;
|
|
724
756
|
|
|
725
|
-
|
|
757
|
+
_context20.t0.click.call(_context20.t0, _context20.t1);
|
|
726
758
|
|
|
727
|
-
|
|
759
|
+
_context20.next = 10;
|
|
728
760
|
return waitFor(function () {
|
|
729
761
|
expect(mockRevokeSelf).toHaveBeenCalledWith(mockDocument);
|
|
730
762
|
expect(mockRevoke).not.toHaveBeenCalled();
|
|
@@ -733,15 +765,15 @@ describe('FederatedFolderModal', function () {
|
|
|
733
765
|
|
|
734
766
|
case 10:
|
|
735
767
|
case "end":
|
|
736
|
-
return
|
|
768
|
+
return _context20.stop();
|
|
737
769
|
}
|
|
738
|
-
},
|
|
770
|
+
}, _callee20);
|
|
739
771
|
})));
|
|
740
|
-
it('should allow a write recipient to revoke another recipient', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function
|
|
741
|
-
var otherRecipient,
|
|
772
|
+
it('should allow a write recipient to revoke another recipient', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee21() {
|
|
773
|
+
var otherRecipient, _setup18, findByLabelText;
|
|
742
774
|
|
|
743
|
-
return _regeneratorRuntime.wrap(function
|
|
744
|
-
while (1) switch (
|
|
775
|
+
return _regeneratorRuntime.wrap(function _callee21$(_context21) {
|
|
776
|
+
while (1) switch (_context21.prev = _context21.next) {
|
|
745
777
|
case 0:
|
|
746
778
|
otherRecipient = {
|
|
747
779
|
instance: 'https://other.mycozy.cloud',
|
|
@@ -754,17 +786,17 @@ describe('FederatedFolderModal', function () {
|
|
|
754
786
|
};
|
|
755
787
|
mockCanReshare.mockReturnValue(true);
|
|
756
788
|
mockGetEffectiveRecipients.mockReturnValue([otherRecipient]);
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
789
|
+
_setup18 = setup(), findByLabelText = _setup18.findByLabelText;
|
|
790
|
+
_context21.t0 = fireEvent;
|
|
791
|
+
_context21.next = 7;
|
|
760
792
|
return findByLabelText('Remove from sharing');
|
|
761
793
|
|
|
762
794
|
case 7:
|
|
763
|
-
|
|
795
|
+
_context21.t1 = _context21.sent;
|
|
764
796
|
|
|
765
|
-
|
|
797
|
+
_context21.t0.click.call(_context21.t0, _context21.t1);
|
|
766
798
|
|
|
767
|
-
|
|
799
|
+
_context21.next = 11;
|
|
768
800
|
return waitFor(function () {
|
|
769
801
|
expect(mockCanReshare).toHaveBeenCalledWith(mockDocument._id);
|
|
770
802
|
expect(mockRevoke).toHaveBeenCalledWith(mockDocument, otherRecipient.sharingId, otherRecipient.memberIndex);
|
|
@@ -773,40 +805,40 @@ describe('FederatedFolderModal', function () {
|
|
|
773
805
|
|
|
774
806
|
case 11:
|
|
775
807
|
case "end":
|
|
776
|
-
return
|
|
808
|
+
return _context21.stop();
|
|
777
809
|
}
|
|
778
|
-
},
|
|
810
|
+
}, _callee21);
|
|
779
811
|
})));
|
|
780
812
|
});
|
|
781
813
|
describe('onClose callback', function () {
|
|
782
|
-
it('should call onClose when close button is clicked', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function
|
|
783
|
-
var
|
|
814
|
+
it('should call onClose when close button is clicked', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee22() {
|
|
815
|
+
var _setup19, findByRole, closeButton;
|
|
784
816
|
|
|
785
|
-
return _regeneratorRuntime.wrap(function
|
|
786
|
-
while (1) switch (
|
|
817
|
+
return _regeneratorRuntime.wrap(function _callee22$(_context22) {
|
|
818
|
+
while (1) switch (_context22.prev = _context22.next) {
|
|
787
819
|
case 0:
|
|
788
|
-
|
|
789
|
-
|
|
820
|
+
_setup19 = setup(), findByRole = _setup19.findByRole;
|
|
821
|
+
_context22.next = 3;
|
|
790
822
|
return findByRole('button', {
|
|
791
823
|
name: /close/i
|
|
792
824
|
});
|
|
793
825
|
|
|
794
826
|
case 3:
|
|
795
|
-
closeButton =
|
|
827
|
+
closeButton = _context22.sent;
|
|
796
828
|
fireEvent.click(closeButton);
|
|
797
829
|
expect(mockOnClose).toHaveBeenCalled();
|
|
798
830
|
|
|
799
831
|
case 6:
|
|
800
832
|
case "end":
|
|
801
|
-
return
|
|
833
|
+
return _context22.stop();
|
|
802
834
|
}
|
|
803
|
-
},
|
|
835
|
+
}, _callee22);
|
|
804
836
|
})));
|
|
805
|
-
it('should ask confirmation when close button is clicked with pending recipients', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function
|
|
806
|
-
var
|
|
837
|
+
it('should ask confirmation when close button is clicked with pending recipients', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee23() {
|
|
838
|
+
var _setup20, getByRole, findByRole, getByText, closeButton;
|
|
807
839
|
|
|
808
|
-
return _regeneratorRuntime.wrap(function
|
|
809
|
-
while (1) switch (
|
|
840
|
+
return _regeneratorRuntime.wrap(function _callee23$(_context23) {
|
|
841
|
+
while (1) switch (_context23.prev = _context23.next) {
|
|
810
842
|
case 0:
|
|
811
843
|
usePendingRecipients.mockReturnValue({
|
|
812
844
|
pendingRecipients: [{
|
|
@@ -817,14 +849,14 @@ describe('FederatedFolderModal', function () {
|
|
|
817
849
|
selectedOption: 'readWrite',
|
|
818
850
|
setSelectedOption: jest.fn()
|
|
819
851
|
});
|
|
820
|
-
|
|
821
|
-
|
|
852
|
+
_setup20 = setup(), getByRole = _setup20.getByRole, findByRole = _setup20.findByRole, getByText = _setup20.getByText;
|
|
853
|
+
_context23.next = 4;
|
|
822
854
|
return findByRole('button', {
|
|
823
855
|
name: /close/i
|
|
824
856
|
});
|
|
825
857
|
|
|
826
858
|
case 4:
|
|
827
|
-
closeButton =
|
|
859
|
+
closeButton = _context23.sent;
|
|
828
860
|
fireEvent.click(closeButton);
|
|
829
861
|
expect(getByText("Discard the changes you haven't saved?")).toBeTruthy();
|
|
830
862
|
expect(mockOnClose).not.toHaveBeenCalled();
|
|
@@ -835,15 +867,15 @@ describe('FederatedFolderModal', function () {
|
|
|
835
867
|
|
|
836
868
|
case 10:
|
|
837
869
|
case "end":
|
|
838
|
-
return
|
|
870
|
+
return _context23.stop();
|
|
839
871
|
}
|
|
840
|
-
},
|
|
872
|
+
}, _callee23);
|
|
841
873
|
})));
|
|
842
|
-
it('should close after discard confirmation', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function
|
|
843
|
-
var
|
|
874
|
+
it('should close after discard confirmation', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee24() {
|
|
875
|
+
var _setup21, getByRole, findByRole, getByText, closeButton;
|
|
844
876
|
|
|
845
|
-
return _regeneratorRuntime.wrap(function
|
|
846
|
-
while (1) switch (
|
|
877
|
+
return _regeneratorRuntime.wrap(function _callee24$(_context24) {
|
|
878
|
+
while (1) switch (_context24.prev = _context24.next) {
|
|
847
879
|
case 0:
|
|
848
880
|
usePendingRecipients.mockReturnValue({
|
|
849
881
|
pendingRecipients: [{
|
|
@@ -854,14 +886,14 @@ describe('FederatedFolderModal', function () {
|
|
|
854
886
|
selectedOption: 'readWrite',
|
|
855
887
|
setSelectedOption: jest.fn()
|
|
856
888
|
});
|
|
857
|
-
|
|
858
|
-
|
|
889
|
+
_setup21 = setup(), getByRole = _setup21.getByRole, findByRole = _setup21.findByRole, getByText = _setup21.getByText;
|
|
890
|
+
_context24.next = 4;
|
|
859
891
|
return findByRole('button', {
|
|
860
892
|
name: /close/i
|
|
861
893
|
});
|
|
862
894
|
|
|
863
895
|
case 4:
|
|
864
|
-
closeButton =
|
|
896
|
+
closeButton = _context24.sent;
|
|
865
897
|
fireEvent.click(closeButton);
|
|
866
898
|
expect(getByText("Discard the changes you haven't saved?")).toBeTruthy();
|
|
867
899
|
fireEvent.click(getByRole('button', {
|
|
@@ -871,9 +903,9 @@ describe('FederatedFolderModal', function () {
|
|
|
871
903
|
|
|
872
904
|
case 9:
|
|
873
905
|
case "end":
|
|
874
|
-
return
|
|
906
|
+
return _context24.stop();
|
|
875
907
|
}
|
|
876
|
-
},
|
|
908
|
+
}, _callee24);
|
|
877
909
|
})));
|
|
878
910
|
});
|
|
879
911
|
});
|
|
@@ -27,7 +27,7 @@ export var ShareModal = withLocales(function (props) {
|
|
|
27
27
|
var _useSharingContext = useSharingContext(),
|
|
28
28
|
byDocId = _useSharingContext.byDocId,
|
|
29
29
|
isOwner = _useSharingContext.isOwner,
|
|
30
|
-
|
|
30
|
+
hasWriteAccess = _useSharingContext.hasWriteAccess,
|
|
31
31
|
documentType = _useSharingContext.documentType,
|
|
32
32
|
getRecipients = _useSharingContext.getRecipients,
|
|
33
33
|
revokeSelf = _useSharingContext.revokeSelf,
|
|
@@ -56,7 +56,7 @@ export var ShareModal = withLocales(function (props) {
|
|
|
56
56
|
};
|
|
57
57
|
}();
|
|
58
58
|
|
|
59
|
-
var isEditable = !byDocId[document.id] || isOwner(document.id) ||
|
|
59
|
+
var isEditable = !byDocId[document.id] || isOwner(document.id) || hasWriteAccess(document.id, document.driveId);
|
|
60
60
|
|
|
61
61
|
if (isEditable) {
|
|
62
62
|
var isFederatedMode = flag('drive.federated-shared-folder.enabled');
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { render } from '@testing-library/react';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { MemoryRouter } from 'react-router';
|
|
4
|
+
import { ShareModal } from './ShareModal';
|
|
5
|
+
var mockIsOwner = jest.fn();
|
|
6
|
+
var mockHasWriteAccess = jest.fn();
|
|
7
|
+
jest.mock('cozy-flags');
|
|
8
|
+
jest.mock('../../hoc/withLocales', function () {
|
|
9
|
+
return function (Component) {
|
|
10
|
+
return Component;
|
|
11
|
+
};
|
|
12
|
+
});
|
|
13
|
+
jest.mock('../../hooks/useSharingContext', function () {
|
|
14
|
+
return {
|
|
15
|
+
useSharingContext: function useSharingContext() {
|
|
16
|
+
return {
|
|
17
|
+
byDocId: {
|
|
18
|
+
'doc-1': {
|
|
19
|
+
sharings: ['sharing-1']
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
isOwner: mockIsOwner,
|
|
23
|
+
hasWriteAccess: mockHasWriteAccess,
|
|
24
|
+
documentType: 'Files',
|
|
25
|
+
getRecipients: jest.fn().mockReturnValue([]),
|
|
26
|
+
revokeSelf: jest.fn(),
|
|
27
|
+
allLoaded: false
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
jest.mock('./EditableSharingModal', function () {
|
|
33
|
+
return function () {
|
|
34
|
+
return /*#__PURE__*/React.createElement("div", null, "editable-modal");
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
jest.mock('./SharingDetailsModal', function () {
|
|
38
|
+
return function () {
|
|
39
|
+
return /*#__PURE__*/React.createElement("div", null, "details-modal");
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
jest.mock('../FederatedFolder/FederatedFolderModal', function () {
|
|
43
|
+
return function () {
|
|
44
|
+
return /*#__PURE__*/React.createElement("div", null, "federated-modal");
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
var mockDocument = {
|
|
48
|
+
id: 'doc-1',
|
|
49
|
+
driveId: undefined
|
|
50
|
+
};
|
|
51
|
+
describe('ShareModal dispatcher', function () {
|
|
52
|
+
beforeEach(function () {
|
|
53
|
+
mockIsOwner.mockReset();
|
|
54
|
+
mockHasWriteAccess.mockReset();
|
|
55
|
+
});
|
|
56
|
+
it('renders the editable modal when the current user has write access, even without reshare rights', function () {
|
|
57
|
+
mockIsOwner.mockReturnValue(false);
|
|
58
|
+
mockHasWriteAccess.mockReturnValue(true);
|
|
59
|
+
|
|
60
|
+
var _render = render( /*#__PURE__*/React.createElement(MemoryRouter, null, /*#__PURE__*/React.createElement(ShareModal, {
|
|
61
|
+
document: mockDocument
|
|
62
|
+
}))),
|
|
63
|
+
getByText = _render.getByText;
|
|
64
|
+
|
|
65
|
+
expect(getByText('editable-modal')).toBeTruthy();
|
|
66
|
+
expect(mockHasWriteAccess).toHaveBeenCalledWith('doc-1', undefined);
|
|
67
|
+
});
|
|
68
|
+
it('renders the restricted details modal when the current user has read-only access', function () {
|
|
69
|
+
mockIsOwner.mockReturnValue(false);
|
|
70
|
+
mockHasWriteAccess.mockReturnValue(false);
|
|
71
|
+
|
|
72
|
+
var _render2 = render( /*#__PURE__*/React.createElement(MemoryRouter, null, /*#__PURE__*/React.createElement(ShareModal, {
|
|
73
|
+
document: mockDocument
|
|
74
|
+
}))),
|
|
75
|
+
getByText = _render2.getByText;
|
|
76
|
+
|
|
77
|
+
expect(getByText('details-modal')).toBeTruthy();
|
|
78
|
+
});
|
|
79
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cozy-sharing",
|
|
3
|
-
"version": "38.1.
|
|
3
|
+
"version": "38.1.1",
|
|
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": "^13.0.
|
|
62
|
+
"cozy-ui-plus": "^13.0.5",
|
|
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": "368b1e85eb1f6a6a0731681ef2a38a7bbc3fe779"
|
|
89
89
|
}
|
|
@@ -42,6 +42,7 @@ const FederatedFolderModalContent = ({
|
|
|
42
42
|
const { t } = useI18n()
|
|
43
43
|
const {
|
|
44
44
|
canReshare,
|
|
45
|
+
hasWriteAccess,
|
|
45
46
|
share,
|
|
46
47
|
getSharingById,
|
|
47
48
|
getSharingLink,
|
|
@@ -99,7 +100,10 @@ const FederatedFolderModalContent = ({
|
|
|
99
100
|
: documentId
|
|
100
101
|
? isOwner(documentId)
|
|
101
102
|
: false
|
|
102
|
-
const isMemberReadOnly =
|
|
103
|
+
const isMemberReadOnly =
|
|
104
|
+
isInsideSharedDrive &&
|
|
105
|
+
!isCurrentUserOwner &&
|
|
106
|
+
!hasWriteAccess(documentId, existingDocument?.driveId)
|
|
103
107
|
const canManageSharing =
|
|
104
108
|
isCurrentUserOwner || (documentId ? canReshare(documentId) : false)
|
|
105
109
|
|
|
@@ -239,7 +243,7 @@ const FederatedFolderModalContent = ({
|
|
|
239
243
|
<AntivirusAlert
|
|
240
244
|
document={isSending ? frozenDoc : existingDocument}
|
|
241
245
|
/>
|
|
242
|
-
{
|
|
246
|
+
{isMemberReadOnly ? (
|
|
243
247
|
<div className={styles['share-byemail-onlybylink']}>
|
|
244
248
|
{t('Files.share.shareByEmail.onlyByLink', {
|
|
245
249
|
type: t(
|
|
@@ -293,7 +297,7 @@ const FederatedFolderModalContent = ({
|
|
|
293
297
|
showGenerateLinkButton={showGenerateLinkButton}
|
|
294
298
|
autoOpenShareRestriction={autoOpenShareRestriction}
|
|
295
299
|
/>
|
|
296
|
-
{!
|
|
300
|
+
{!isMemberReadOnly && (
|
|
297
301
|
<Button
|
|
298
302
|
variant="primary"
|
|
299
303
|
label={t('FederatedFolder.share')}
|
|
@@ -14,6 +14,7 @@ const mockRevoke = jest.fn()
|
|
|
14
14
|
const mockRevokeSelf = jest.fn()
|
|
15
15
|
const mockIsOwner = jest.fn()
|
|
16
16
|
const mockCanReshare = jest.fn()
|
|
17
|
+
const mockHasWriteAccess = jest.fn()
|
|
17
18
|
const mockGetSharingLink = jest.fn()
|
|
18
19
|
const mockGetFederatedShareLink = jest.fn()
|
|
19
20
|
const mockGetSharingById = jest.fn()
|
|
@@ -34,6 +35,7 @@ jest.mock('../../hooks/useSharingContext', () => ({
|
|
|
34
35
|
revokeSelf: mockRevokeSelf,
|
|
35
36
|
isOwner: mockIsOwner,
|
|
36
37
|
canReshare: mockCanReshare,
|
|
38
|
+
hasWriteAccess: mockHasWriteAccess,
|
|
37
39
|
getSharingLink: mockGetSharingLink,
|
|
38
40
|
getFederatedShareLink: mockGetFederatedShareLink,
|
|
39
41
|
getDocumentPermissions: mockGetDocumentPermissions,
|
|
@@ -115,6 +117,7 @@ describe('FederatedFolderModal', () => {
|
|
|
115
117
|
mockRevokeSelf.mockResolvedValue()
|
|
116
118
|
mockIsOwner.mockReturnValue(false)
|
|
117
119
|
mockCanReshare.mockReturnValue(false)
|
|
120
|
+
mockHasWriteAccess.mockReturnValue(false)
|
|
118
121
|
mockGetDocumentPermissions.mockReturnValue([])
|
|
119
122
|
mockFetchSharedDriveSharingLinks.mockResolvedValue([])
|
|
120
123
|
mockGetSharingLink.mockReturnValue('https://example.com/share/abc123')
|
|
@@ -224,6 +227,25 @@ describe('FederatedFolderModal', () => {
|
|
|
224
227
|
await findByText('it has a shared parent')
|
|
225
228
|
})
|
|
226
229
|
|
|
230
|
+
it('should allow share by email when the current user has write access, even inside a federated shared folder', async () => {
|
|
231
|
+
mockHasWriteAccess.mockReturnValue(true)
|
|
232
|
+
|
|
233
|
+
const { findByText, queryByText } = setup({
|
|
234
|
+
document: {
|
|
235
|
+
...mockDocument,
|
|
236
|
+
driveId: 'federated-folder-id',
|
|
237
|
+
type: 'directory'
|
|
238
|
+
}
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
await findByText('Add users')
|
|
242
|
+
await findByText('Done')
|
|
243
|
+
|
|
244
|
+
expect(
|
|
245
|
+
queryByText('This folder can only be shared by link, because')
|
|
246
|
+
).toBe(null)
|
|
247
|
+
})
|
|
248
|
+
|
|
227
249
|
it('should allow share by email when document is the federated shared folder root', async () => {
|
|
228
250
|
mockGetSharingById.mockReturnValue({
|
|
229
251
|
attributes: {
|
|
@@ -20,7 +20,7 @@ export const ShareModal = withLocales(props => {
|
|
|
20
20
|
const {
|
|
21
21
|
byDocId,
|
|
22
22
|
isOwner,
|
|
23
|
-
|
|
23
|
+
hasWriteAccess,
|
|
24
24
|
documentType,
|
|
25
25
|
getRecipients,
|
|
26
26
|
revokeSelf,
|
|
@@ -33,7 +33,9 @@ export const ShareModal = withLocales(props => {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
const isEditable =
|
|
36
|
-
!byDocId[document.id] ||
|
|
36
|
+
!byDocId[document.id] ||
|
|
37
|
+
isOwner(document.id) ||
|
|
38
|
+
hasWriteAccess(document.id, document.driveId)
|
|
37
39
|
|
|
38
40
|
if (isEditable) {
|
|
39
41
|
const isFederatedMode = flag('drive.federated-shared-folder.enabled')
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { render } from '@testing-library/react'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { MemoryRouter } from 'react-router'
|
|
4
|
+
|
|
5
|
+
import { ShareModal } from './ShareModal'
|
|
6
|
+
|
|
7
|
+
const mockIsOwner = jest.fn()
|
|
8
|
+
const mockHasWriteAccess = jest.fn()
|
|
9
|
+
|
|
10
|
+
jest.mock('cozy-flags')
|
|
11
|
+
|
|
12
|
+
jest.mock('../../hoc/withLocales', () => Component => Component)
|
|
13
|
+
|
|
14
|
+
jest.mock('../../hooks/useSharingContext', () => ({
|
|
15
|
+
useSharingContext: () => ({
|
|
16
|
+
byDocId: { 'doc-1': { sharings: ['sharing-1'] } },
|
|
17
|
+
isOwner: mockIsOwner,
|
|
18
|
+
hasWriteAccess: mockHasWriteAccess,
|
|
19
|
+
documentType: 'Files',
|
|
20
|
+
getRecipients: jest.fn().mockReturnValue([]),
|
|
21
|
+
revokeSelf: jest.fn(),
|
|
22
|
+
allLoaded: false
|
|
23
|
+
})
|
|
24
|
+
}))
|
|
25
|
+
|
|
26
|
+
jest.mock('./EditableSharingModal', () => () => <div>editable-modal</div>)
|
|
27
|
+
jest.mock('./SharingDetailsModal', () => () => <div>details-modal</div>)
|
|
28
|
+
jest.mock('../FederatedFolder/FederatedFolderModal', () => () => (
|
|
29
|
+
<div>federated-modal</div>
|
|
30
|
+
))
|
|
31
|
+
|
|
32
|
+
const mockDocument = { id: 'doc-1', driveId: undefined }
|
|
33
|
+
|
|
34
|
+
describe('ShareModal dispatcher', () => {
|
|
35
|
+
beforeEach(() => {
|
|
36
|
+
mockIsOwner.mockReset()
|
|
37
|
+
mockHasWriteAccess.mockReset()
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('renders the editable modal when the current user has write access, even without reshare rights', () => {
|
|
41
|
+
mockIsOwner.mockReturnValue(false)
|
|
42
|
+
mockHasWriteAccess.mockReturnValue(true)
|
|
43
|
+
|
|
44
|
+
const { getByText } = render(
|
|
45
|
+
<MemoryRouter>
|
|
46
|
+
<ShareModal document={mockDocument} />
|
|
47
|
+
</MemoryRouter>
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
expect(getByText('editable-modal')).toBeTruthy()
|
|
51
|
+
expect(mockHasWriteAccess).toHaveBeenCalledWith('doc-1', undefined)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('renders the restricted details modal when the current user has read-only access', () => {
|
|
55
|
+
mockIsOwner.mockReturnValue(false)
|
|
56
|
+
mockHasWriteAccess.mockReturnValue(false)
|
|
57
|
+
|
|
58
|
+
const { getByText } = render(
|
|
59
|
+
<MemoryRouter>
|
|
60
|
+
<ShareModal document={mockDocument} />
|
|
61
|
+
</MemoryRouter>
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
expect(getByText('details-modal')).toBeTruthy()
|
|
65
|
+
})
|
|
66
|
+
})
|