cozy-sharing 33.2.1 → 33.2.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 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
+ ## [33.2.2](https://github.com/cozy/cozy-libs/compare/cozy-sharing@33.2.1...cozy-sharing@33.2.2) (2026-06-10)
7
+
8
+ ### Bug Fixes
9
+
10
+ - **cozy-sharing:** Allow sharing shared drive folder root by email ([5110b4f](https://github.com/cozy/cozy-libs/commit/5110b4fb306bb664f2c6b62f209ef4af1e25c293))
11
+ - **cozy-sharing:** Fix lint issue in master ([5acd30a](https://github.com/cozy/cozy-libs/commit/5acd30a31412552be6b6223e43df2b320ea07098))
12
+
6
13
  ## [33.2.1](https://github.com/cozy/cozy-libs/compare/cozy-sharing@33.2.0...cozy-sharing@33.2.1) (2026-06-09)
7
14
 
8
15
  ### Bug Fixes
@@ -38,6 +38,8 @@ import ShareByLink from '../ShareByLink';
38
38
  import WhoHasAccess from '../WhoHasAccess';
39
39
 
40
40
  var FederatedFolderModalContent = function FederatedFolderModalContent(_ref) {
41
+ var _sharedDriveSharing$a;
42
+
41
43
  var onClose = _ref.onClose,
42
44
  existingDocument = _ref.document,
43
45
  autoOpenShareRestriction = _ref.autoOpenShareRestriction,
@@ -49,6 +51,7 @@ var FederatedFolderModalContent = function FederatedFolderModalContent(_ref) {
49
51
 
50
52
  var _useSharingContext = useSharingContext(),
51
53
  share = _useSharingContext.share,
54
+ getSharingById = _useSharingContext.getSharingById,
52
55
  getSharingLink = _useSharingContext.getSharingLink,
53
56
  getFederatedShareLink = _useSharingContext.getFederatedShareLink,
54
57
  getRecipients = _useSharingContext.getRecipients,
@@ -116,7 +119,16 @@ var FederatedFolderModalContent = function FederatedFolderModalContent(_ref) {
116
119
  }, [closeConfirmDialog, onClose, pendingRecipients.length, showConfirmDialog, t]);
117
120
  var folderName = (existingDocument === null || existingDocument === void 0 ? void 0 : existingDocument.name) || '';
118
121
  var documentPath = existingDocument === null || existingDocument === void 0 ? void 0 : existingDocument.path;
119
- var hasParentRestriction = Boolean((existingDocument === null || existingDocument === void 0 ? void 0 : existingDocument.driveId) || documentPath && hasSharedParent(documentPath));
122
+ var sharedDriveSharing = existingDocument !== null && existingDocument !== void 0 && existingDocument.driveId ? getSharingById(existingDocument.driveId) : null;
123
+ var sharedDriveRootIds = (sharedDriveSharing === null || sharedDriveSharing === void 0 || (_sharedDriveSharing$a = sharedDriveSharing.attributes) === null || _sharedDriveSharing$a === void 0 || (_sharedDriveSharing$a = _sharedDriveSharing$a.rules) === null || _sharedDriveSharing$a === void 0 ? void 0 : _sharedDriveSharing$a.reduce(function (ids, rule) {
124
+ return ids.concat(rule.values || []);
125
+ }, [])) || [];
126
+ var isSharedDriveRoot = Boolean((existingDocument === null || existingDocument === void 0 ? void 0 : existingDocument.driveId) && sharedDriveRootIds.some(function (id) {
127
+ return id === (existingDocument === null || existingDocument === void 0 ? void 0 : existingDocument._id) || id === (existingDocument === null || existingDocument === void 0 ? void 0 : existingDocument.id);
128
+ }));
129
+ var isInsideSharedDrive = Boolean((existingDocument === null || existingDocument === void 0 ? void 0 : existingDocument.driveId) && !isSharedDriveRoot);
130
+ var hasSharedParentByPath = Boolean(documentPath && hasSharedParent(documentPath));
131
+ var hasParentRestriction = isInsideSharedDrive || hasSharedParentByPath;
120
132
  var hasChildRestriction = Boolean(documentPath && hasSharedChild(documentPath));
121
133
  var canShareByEmail = !hasParentRestriction && !hasChildRestriction;
122
134
 
@@ -20,6 +20,7 @@ var mockRevoke = jest.fn();
20
20
  var mockGetSharingLink = jest.fn();
21
21
  var mockGetFederatedShareLink = jest.fn();
22
22
  var mockGetRecipients = jest.fn().mockReturnValue([]);
23
+ var mockGetSharingById = jest.fn();
23
24
  var mockHasSharedChild = jest.fn();
24
25
  var mockHasSharedParent = jest.fn();
25
26
  var mockShowAlert = jest.fn();
@@ -35,8 +36,8 @@ jest.mock('../../hooks/useSharingContext', function () {
35
36
  getFederatedShareLink: mockGetFederatedShareLink,
36
37
  getDocumentPermissions: jest.fn().mockReturnValue([]),
37
38
  getOwner: jest.fn(),
38
- getSharingById: jest.fn(),
39
39
  getRecipients: mockGetRecipients,
40
+ getSharingById: mockGetSharingById,
40
41
  hasSharedChild: mockHasSharedChild,
41
42
  hasSharedParent: mockHasSharedParent
42
43
  };
@@ -120,6 +121,7 @@ describe('FederatedFolderModal', function () {
120
121
  mockGetSharingLink.mockReturnValue('https://example.com/share/abc123');
121
122
  mockGetFederatedShareLink.mockReturnValue('https://example.com/share/federated-abc123');
122
123
  mockGetRecipients.mockReturnValue([]);
124
+ mockGetSharingById.mockReturnValue(null);
123
125
  mockHasSharedChild.mockReturnValue(false);
124
126
  mockHasSharedParent.mockReturnValue(false);
125
127
  mockShareByLink.mockResolvedValue({
@@ -289,27 +291,61 @@ describe('FederatedFolderModal', function () {
289
291
  }
290
292
  }, _callee6);
291
293
  })));
294
+ it('should allow share by email when document is the federated shared folder root', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee7() {
295
+ var _setup7, findByText, queryByText;
296
+
297
+ return _regeneratorRuntime.wrap(function _callee7$(_context7) {
298
+ while (1) switch (_context7.prev = _context7.next) {
299
+ case 0:
300
+ mockGetSharingById.mockReturnValue({
301
+ attributes: {
302
+ rules: [{
303
+ values: ['another-folder-id']
304
+ }, {
305
+ values: ['yet-another-folder-id', mockDocument._id]
306
+ }]
307
+ }
308
+ });
309
+ _setup7 = setup({
310
+ document: _objectSpread(_objectSpread({}, mockDocument), {}, {
311
+ driveId: 'federated-folder-id',
312
+ type: 'directory'
313
+ })
314
+ }), findByText = _setup7.findByText, queryByText = _setup7.queryByText;
315
+ _context7.next = 4;
316
+ return findByText('Add users');
317
+
318
+ case 4:
319
+ expect(queryByText('This folder can only be shared by link, because')).toBe(null);
320
+ expect(queryByText('it has a shared parent')).toBe(null);
321
+
322
+ case 6:
323
+ case "end":
324
+ return _context7.stop();
325
+ }
326
+ }, _callee7);
327
+ })));
292
328
  });
293
329
  describe('onSend callback', function () {
294
330
  var pendingRecipient = {
295
331
  name: 'Alice',
296
332
  email: 'alice@example.com'
297
333
  };
298
- it('should call onClose and skip share when there are no pending recipients', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee7() {
299
- var _setup7, findByText, sendButton;
334
+ it('should call onClose and skip share when there are no pending recipients', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee8() {
335
+ var _setup8, findByText, sendButton;
300
336
 
301
- return _regeneratorRuntime.wrap(function _callee7$(_context7) {
302
- while (1) switch (_context7.prev = _context7.next) {
337
+ return _regeneratorRuntime.wrap(function _callee8$(_context8) {
338
+ while (1) switch (_context8.prev = _context8.next) {
303
339
  case 0:
304
340
  // pendingRecipients defaults to [] via beforeEach
305
- _setup7 = setup(), findByText = _setup7.findByText;
306
- _context7.next = 3;
341
+ _setup8 = setup(), findByText = _setup8.findByText;
342
+ _context8.next = 3;
307
343
  return findByText('Done');
308
344
 
309
345
  case 3:
310
- sendButton = _context7.sent;
346
+ sendButton = _context8.sent;
311
347
  fireEvent.click(sendButton);
312
- _context7.next = 7;
348
+ _context8.next = 7;
313
349
  return waitFor(function () {
314
350
  expect(mockOnClose).toHaveBeenCalled();
315
351
  expect(mockShare).not.toHaveBeenCalled();
@@ -317,15 +353,15 @@ describe('FederatedFolderModal', function () {
317
353
 
318
354
  case 7:
319
355
  case "end":
320
- return _context7.stop();
356
+ return _context8.stop();
321
357
  }
322
- }, _callee7);
358
+ }, _callee8);
323
359
  })));
324
- it('should call share with correct parameters', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee8() {
325
- var _setup8, findByText, sendButton;
360
+ it('should call share with correct parameters', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee9() {
361
+ var _setup9, findByText, sendButton;
326
362
 
327
- return _regeneratorRuntime.wrap(function _callee8$(_context8) {
328
- while (1) switch (_context8.prev = _context8.next) {
363
+ return _regeneratorRuntime.wrap(function _callee9$(_context9) {
364
+ while (1) switch (_context9.prev = _context9.next) {
329
365
  case 0:
330
366
  usePendingRecipients.mockReturnValue({
331
367
  pendingRecipients: [pendingRecipient],
@@ -335,14 +371,14 @@ describe('FederatedFolderModal', function () {
335
371
  });
336
372
  getOrCreateFromArray.mockResolvedValue([pendingRecipient]);
337
373
  mockShare.mockResolvedValueOnce({});
338
- _setup8 = setup(), findByText = _setup8.findByText;
339
- _context8.next = 6;
374
+ _setup9 = setup(), findByText = _setup9.findByText;
375
+ _context9.next = 6;
340
376
  return findByText('Done');
341
377
 
342
378
  case 6:
343
- sendButton = _context8.sent;
379
+ sendButton = _context9.sent;
344
380
  fireEvent.click(sendButton);
345
- _context8.next = 10;
381
+ _context9.next = 10;
346
382
  return waitFor(function () {
347
383
  expect(mockShare).toHaveBeenCalledWith({
348
384
  description: 'My Test Folder',
@@ -356,15 +392,15 @@ describe('FederatedFolderModal', function () {
356
392
 
357
393
  case 10:
358
394
  case "end":
359
- return _context8.stop();
395
+ return _context9.stop();
360
396
  }
361
- }, _callee8);
397
+ }, _callee9);
362
398
  })));
363
- it('should show success alert and close modal on successful share', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee9() {
364
- var _setup9, findByText, sendButton;
399
+ it('should show success alert and close modal on successful share', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee10() {
400
+ var _setup10, findByText, sendButton;
365
401
 
366
- return _regeneratorRuntime.wrap(function _callee9$(_context9) {
367
- while (1) switch (_context9.prev = _context9.next) {
402
+ return _regeneratorRuntime.wrap(function _callee10$(_context10) {
403
+ while (1) switch (_context10.prev = _context10.next) {
368
404
  case 0:
369
405
  usePendingRecipients.mockReturnValue({
370
406
  pendingRecipients: [pendingRecipient],
@@ -374,14 +410,14 @@ describe('FederatedFolderModal', function () {
374
410
  });
375
411
  getOrCreateFromArray.mockResolvedValue([pendingRecipient]);
376
412
  mockShare.mockResolvedValueOnce({});
377
- _setup9 = setup(), findByText = _setup9.findByText;
378
- _context9.next = 6;
413
+ _setup10 = setup(), findByText = _setup10.findByText;
414
+ _context10.next = 6;
379
415
  return findByText('Done');
380
416
 
381
417
  case 6:
382
- sendButton = _context9.sent;
418
+ sendButton = _context10.sent;
383
419
  fireEvent.click(sendButton);
384
- _context9.next = 10;
420
+ _context10.next = 10;
385
421
  return waitFor(function () {
386
422
  expect(mockShowAlert).toHaveBeenCalledWith({
387
423
  message: 'Folder has been shared',
@@ -393,15 +429,15 @@ describe('FederatedFolderModal', function () {
393
429
 
394
430
  case 10:
395
431
  case "end":
396
- return _context9.stop();
432
+ return _context10.stop();
397
433
  }
398
- }, _callee9);
434
+ }, _callee10);
399
435
  })));
400
- it('should show error alert when share fails', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee10() {
401
- var _setup10, findByText, sendButton;
436
+ it('should show error alert when share fails', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee11() {
437
+ var _setup11, findByText, sendButton;
402
438
 
403
- return _regeneratorRuntime.wrap(function _callee10$(_context10) {
404
- while (1) switch (_context10.prev = _context10.next) {
439
+ return _regeneratorRuntime.wrap(function _callee11$(_context11) {
440
+ while (1) switch (_context11.prev = _context11.next) {
405
441
  case 0:
406
442
  usePendingRecipients.mockReturnValue({
407
443
  pendingRecipients: [pendingRecipient],
@@ -411,14 +447,14 @@ describe('FederatedFolderModal', function () {
411
447
  });
412
448
  getOrCreateFromArray.mockResolvedValue([pendingRecipient]);
413
449
  mockShare.mockRejectedValueOnce(new Error('Share failed'));
414
- _setup10 = setup(), findByText = _setup10.findByText;
415
- _context10.next = 6;
450
+ _setup11 = setup(), findByText = _setup11.findByText;
451
+ _context11.next = 6;
416
452
  return findByText('Done');
417
453
 
418
454
  case 6:
419
- sendButton = _context10.sent;
455
+ sendButton = _context11.sent;
420
456
  fireEvent.click(sendButton);
421
- _context10.next = 10;
457
+ _context11.next = 10;
422
458
  return waitFor(function () {
423
459
  expect(mockShowAlert).toHaveBeenCalledWith({
424
460
  message: 'Error while sharing folder',
@@ -430,15 +466,15 @@ describe('FederatedFolderModal', function () {
430
466
 
431
467
  case 10:
432
468
  case "end":
433
- return _context10.stop();
469
+ return _context11.stop();
434
470
  }
435
- }, _callee10);
471
+ }, _callee11);
436
472
  })));
437
- it('should show progress icon on Done button while share is in progress', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee12() {
438
- var resolveShare, _setup11, findByText, getByRole, queryByRole, sendButton;
473
+ it('should show progress icon on Done button while share is in progress', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee13() {
474
+ var resolveShare, _setup12, findByText, getByRole, queryByRole, sendButton;
439
475
 
440
- return _regeneratorRuntime.wrap(function _callee12$(_context12) {
441
- while (1) switch (_context12.prev = _context12.next) {
476
+ return _regeneratorRuntime.wrap(function _callee13$(_context13) {
477
+ while (1) switch (_context13.prev = _context13.next) {
442
478
  case 0:
443
479
  usePendingRecipients.mockReturnValue({
444
480
  pendingRecipients: [pendingRecipient],
@@ -450,14 +486,14 @@ describe('FederatedFolderModal', function () {
450
486
  mockShare.mockReturnValueOnce(new Promise(function (resolve) {
451
487
  resolveShare = resolve;
452
488
  }));
453
- _setup11 = setup(), findByText = _setup11.findByText, getByRole = _setup11.getByRole, queryByRole = _setup11.queryByRole;
454
- _context12.next = 6;
489
+ _setup12 = setup(), findByText = _setup12.findByText, getByRole = _setup12.getByRole, queryByRole = _setup12.queryByRole;
490
+ _context13.next = 6;
455
491
  return findByText('Done');
456
492
 
457
493
  case 6:
458
- sendButton = _context12.sent;
494
+ sendButton = _context13.sent;
459
495
  fireEvent.click(sendButton);
460
- _context12.next = 10;
496
+ _context13.next = 10;
461
497
  return waitFor(function () {
462
498
  expect(getByRole('button', {
463
499
  name: 'Done'
@@ -466,56 +502,56 @@ describe('FederatedFolderModal', function () {
466
502
  });
467
503
 
468
504
  case 10:
469
- _context12.next = 12;
470
- return act( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee11() {
471
- return _regeneratorRuntime.wrap(function _callee11$(_context11) {
472
- while (1) switch (_context11.prev = _context11.next) {
505
+ _context13.next = 12;
506
+ return act( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee12() {
507
+ return _regeneratorRuntime.wrap(function _callee12$(_context12) {
508
+ while (1) switch (_context12.prev = _context12.next) {
473
509
  case 0:
474
510
  resolveShare({});
475
511
 
476
512
  case 1:
477
513
  case "end":
478
- return _context11.stop();
514
+ return _context12.stop();
479
515
  }
480
- }, _callee11);
516
+ }, _callee12);
481
517
  })));
482
518
 
483
519
  case 12:
484
520
  case "end":
485
- return _context12.stop();
521
+ return _context13.stop();
486
522
  }
487
- }, _callee12);
523
+ }, _callee13);
488
524
  })));
489
525
  });
490
526
  describe('onClose callback', function () {
491
- it('should call onClose when close button is clicked', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee13() {
492
- var _setup12, findByRole, closeButton;
527
+ it('should call onClose when close button is clicked', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee14() {
528
+ var _setup13, findByRole, closeButton;
493
529
 
494
- return _regeneratorRuntime.wrap(function _callee13$(_context13) {
495
- while (1) switch (_context13.prev = _context13.next) {
530
+ return _regeneratorRuntime.wrap(function _callee14$(_context14) {
531
+ while (1) switch (_context14.prev = _context14.next) {
496
532
  case 0:
497
- _setup12 = setup(), findByRole = _setup12.findByRole;
498
- _context13.next = 3;
533
+ _setup13 = setup(), findByRole = _setup13.findByRole;
534
+ _context14.next = 3;
499
535
  return findByRole('button', {
500
536
  name: /close/i
501
537
  });
502
538
 
503
539
  case 3:
504
- closeButton = _context13.sent;
540
+ closeButton = _context14.sent;
505
541
  fireEvent.click(closeButton);
506
542
  expect(mockOnClose).toHaveBeenCalled();
507
543
 
508
544
  case 6:
509
545
  case "end":
510
- return _context13.stop();
546
+ return _context14.stop();
511
547
  }
512
- }, _callee13);
548
+ }, _callee14);
513
549
  })));
514
- it('should ask confirmation when close button is clicked with pending recipients', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee14() {
515
- var _setup13, getByRole, findByRole, getByText, closeButton;
550
+ it('should ask confirmation when close button is clicked with pending recipients', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee15() {
551
+ var _setup14, getByRole, findByRole, getByText, closeButton;
516
552
 
517
- return _regeneratorRuntime.wrap(function _callee14$(_context14) {
518
- while (1) switch (_context14.prev = _context14.next) {
553
+ return _regeneratorRuntime.wrap(function _callee15$(_context15) {
554
+ while (1) switch (_context15.prev = _context15.next) {
519
555
  case 0:
520
556
  usePendingRecipients.mockReturnValue({
521
557
  pendingRecipients: [{
@@ -526,14 +562,14 @@ describe('FederatedFolderModal', function () {
526
562
  selectedOption: 'readWrite',
527
563
  setSelectedOption: jest.fn()
528
564
  });
529
- _setup13 = setup(), getByRole = _setup13.getByRole, findByRole = _setup13.findByRole, getByText = _setup13.getByText;
530
- _context14.next = 4;
565
+ _setup14 = setup(), getByRole = _setup14.getByRole, findByRole = _setup14.findByRole, getByText = _setup14.getByText;
566
+ _context15.next = 4;
531
567
  return findByRole('button', {
532
568
  name: /close/i
533
569
  });
534
570
 
535
571
  case 4:
536
- closeButton = _context14.sent;
572
+ closeButton = _context15.sent;
537
573
  fireEvent.click(closeButton);
538
574
  expect(getByText("Discard the changes you haven't saved?")).toBeTruthy();
539
575
  expect(mockOnClose).not.toHaveBeenCalled();
@@ -544,15 +580,15 @@ describe('FederatedFolderModal', function () {
544
580
 
545
581
  case 10:
546
582
  case "end":
547
- return _context14.stop();
583
+ return _context15.stop();
548
584
  }
549
- }, _callee14);
585
+ }, _callee15);
550
586
  })));
551
- it('should close after discard confirmation', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee15() {
552
- var _setup14, getByRole, findByRole, getByText, closeButton;
587
+ it('should close after discard confirmation', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee16() {
588
+ var _setup15, getByRole, findByRole, getByText, closeButton;
553
589
 
554
- return _regeneratorRuntime.wrap(function _callee15$(_context15) {
555
- while (1) switch (_context15.prev = _context15.next) {
590
+ return _regeneratorRuntime.wrap(function _callee16$(_context16) {
591
+ while (1) switch (_context16.prev = _context16.next) {
556
592
  case 0:
557
593
  usePendingRecipients.mockReturnValue({
558
594
  pendingRecipients: [{
@@ -563,14 +599,14 @@ describe('FederatedFolderModal', function () {
563
599
  selectedOption: 'readWrite',
564
600
  setSelectedOption: jest.fn()
565
601
  });
566
- _setup14 = setup(), getByRole = _setup14.getByRole, findByRole = _setup14.findByRole, getByText = _setup14.getByText;
567
- _context15.next = 4;
602
+ _setup15 = setup(), getByRole = _setup15.getByRole, findByRole = _setup15.findByRole, getByText = _setup15.getByText;
603
+ _context16.next = 4;
568
604
  return findByRole('button', {
569
605
  name: /close/i
570
606
  });
571
607
 
572
608
  case 4:
573
- closeButton = _context15.sent;
609
+ closeButton = _context16.sent;
574
610
  fireEvent.click(closeButton);
575
611
  expect(getByText("Discard the changes you haven't saved?")).toBeTruthy();
576
612
  fireEvent.click(getByRole('button', {
@@ -580,9 +616,9 @@ describe('FederatedFolderModal', function () {
580
616
 
581
617
  case 9:
582
618
  case "end":
583
- return _context15.stop();
619
+ return _context16.stop();
584
620
  }
585
- }, _callee15);
621
+ }, _callee16);
586
622
  })));
587
623
  });
588
624
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-sharing",
3
- "version": "33.2.1",
3
+ "version": "33.2.2",
4
4
  "description": "Provides sharing login for React applications.",
5
5
  "main": "dist/index.js",
6
6
  "author": "Cozy",
@@ -83,5 +83,5 @@
83
83
  "sideEffects": [
84
84
  "*.css"
85
85
  ],
86
- "gitHead": "107c14be0fb0677515062187e3fdadeab4e00350"
86
+ "gitHead": "d4513639ed420da6b9edfef7cb3230d90d0cf537"
87
87
  }
@@ -31,6 +31,7 @@ const FederatedFolderModalContent = ({
31
31
  const { t } = useI18n()
32
32
  const {
33
33
  share,
34
+ getSharingById,
34
35
  getSharingLink,
35
36
  getFederatedShareLink,
36
37
  getRecipients,
@@ -96,9 +97,27 @@ const FederatedFolderModalContent = ({
96
97
 
97
98
  const folderName = existingDocument?.name || ''
98
99
  const documentPath = existingDocument?.path
99
- const hasParentRestriction = Boolean(
100
- existingDocument?.driveId || (documentPath && hasSharedParent(documentPath))
100
+ const sharedDriveSharing = existingDocument?.driveId
101
+ ? getSharingById(existingDocument.driveId)
102
+ : null
103
+ const sharedDriveRootIds =
104
+ sharedDriveSharing?.attributes?.rules?.reduce(
105
+ (ids, rule) => ids.concat(rule.values || []),
106
+ []
107
+ ) || []
108
+ const isSharedDriveRoot = Boolean(
109
+ existingDocument?.driveId &&
110
+ sharedDriveRootIds.some(
111
+ id => id === existingDocument?._id || id === existingDocument?.id
112
+ )
101
113
  )
114
+ const isInsideSharedDrive = Boolean(
115
+ existingDocument?.driveId && !isSharedDriveRoot
116
+ )
117
+ const hasSharedParentByPath = Boolean(
118
+ documentPath && hasSharedParent(documentPath)
119
+ )
120
+ const hasParentRestriction = isInsideSharedDrive || hasSharedParentByPath
102
121
  const hasChildRestriction = Boolean(
103
122
  documentPath && hasSharedChild(documentPath)
104
123
  )
@@ -14,6 +14,7 @@ const mockRevoke = jest.fn()
14
14
  const mockGetSharingLink = jest.fn()
15
15
  const mockGetFederatedShareLink = jest.fn()
16
16
  const mockGetRecipients = jest.fn().mockReturnValue([])
17
+ const mockGetSharingById = jest.fn()
17
18
  const mockHasSharedChild = jest.fn()
18
19
  const mockHasSharedParent = jest.fn()
19
20
  const mockShowAlert = jest.fn()
@@ -28,8 +29,8 @@ jest.mock('../../hooks/useSharingContext', () => ({
28
29
  getFederatedShareLink: mockGetFederatedShareLink,
29
30
  getDocumentPermissions: jest.fn().mockReturnValue([]),
30
31
  getOwner: jest.fn(),
31
- getSharingById: jest.fn(),
32
32
  getRecipients: mockGetRecipients,
33
+ getSharingById: mockGetSharingById,
33
34
  hasSharedChild: mockHasSharedChild,
34
35
  hasSharedParent: mockHasSharedParent
35
36
  })
@@ -100,6 +101,7 @@ describe('FederatedFolderModal', () => {
100
101
  'https://example.com/share/federated-abc123'
101
102
  )
102
103
  mockGetRecipients.mockReturnValue([])
104
+ mockGetSharingById.mockReturnValue(null)
103
105
  mockHasSharedChild.mockReturnValue(false)
104
106
  mockHasSharedParent.mockReturnValue(false)
105
107
  mockShareByLink.mockResolvedValue({
@@ -197,6 +199,32 @@ describe('FederatedFolderModal', () => {
197
199
  await findByText('This folder can only be shared by link, because')
198
200
  await findByText('it has a shared parent')
199
201
  })
202
+
203
+ it('should allow share by email when document is the federated shared folder root', async () => {
204
+ mockGetSharingById.mockReturnValue({
205
+ attributes: {
206
+ rules: [
207
+ { values: ['another-folder-id'] },
208
+ { values: ['yet-another-folder-id', mockDocument._id] }
209
+ ]
210
+ }
211
+ })
212
+
213
+ const { findByText, queryByText } = setup({
214
+ document: {
215
+ ...mockDocument,
216
+ driveId: 'federated-folder-id',
217
+ type: 'directory'
218
+ }
219
+ })
220
+
221
+ await findByText('Add users')
222
+
223
+ expect(
224
+ queryByText('This folder can only be shared by link, because')
225
+ ).toBe(null)
226
+ expect(queryByText('it has a shared parent')).toBe(null)
227
+ })
200
228
  })
201
229
 
202
230
  describe('onSend callback', () => {