cozy-sharing 28.7.0 → 28.9.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 +12 -0
- package/dist/components/FederatedFolder/FederatedFolderModal.js +48 -16
- package/dist/components/FederatedFolder/FederatedFolderModal.spec.js +106 -7
- package/dist/components/ShareModal/ShareModal.js +2 -6
- package/dist/components/SharingBanner/components/PublicBanner.js +6 -0
- package/package.json +2 -2
- package/src/components/FederatedFolder/FederatedFolderModal.jsx +23 -10
- package/src/components/FederatedFolder/FederatedFolderModal.spec.jsx +70 -1
- package/src/components/ShareModal/ShareModal.jsx +1 -7
- package/src/components/SharingBanner/components/PublicBanner.jsx +7 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,18 @@
|
|
|
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
|
+
# [28.9.0](https://github.com/cozy/cozy-libs/compare/cozy-sharing@28.8.0...cozy-sharing@28.9.0) (2026-03-12)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
- Disable Twake Creation from public sharing link ([e8e6fcf](https://github.com/cozy/cozy-libs/commit/e8e6fcfc5e659796f06378818044debb09c7c4e2))
|
|
11
|
+
|
|
12
|
+
# [28.8.0](https://github.com/cozy/cozy-libs/compare/cozy-sharing@28.7.0...cozy-sharing@28.8.0) (2026-03-12)
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
- **cozy-sharing:** Use FederatedFolderModal on existing sharings ([541de13](https://github.com/cozy/cozy-libs/commit/541de1310631170b5567694ff1366bc997fb3ea3))
|
|
17
|
+
|
|
6
18
|
# [28.7.0](https://github.com/cozy/cozy-libs/compare/cozy-sharing@28.6.0...cozy-sharing@28.7.0) (2026-03-12)
|
|
7
19
|
|
|
8
20
|
### Features
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
1
2
|
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
2
3
|
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
3
4
|
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
@@ -24,7 +25,9 @@ export var FederatedFolderModal = withLocales(function (_ref) {
|
|
|
24
25
|
getFederatedShareLink = _useSharingContext.getFederatedShareLink,
|
|
25
26
|
getDocumentPermissions = _useSharingContext.getDocumentPermissions,
|
|
26
27
|
getOwner = _useSharingContext.getOwner,
|
|
27
|
-
getSharingById = _useSharingContext.getSharingById
|
|
28
|
+
getSharingById = _useSharingContext.getSharingById,
|
|
29
|
+
getRecipients = _useSharingContext.getRecipients,
|
|
30
|
+
revoke = _useSharingContext.revoke;
|
|
28
31
|
|
|
29
32
|
var _useAlert = useAlert(),
|
|
30
33
|
showAlert = _useAlert.showAlert;
|
|
@@ -162,21 +165,50 @@ export var FederatedFolderModal = withLocales(function (_ref) {
|
|
|
162
165
|
}
|
|
163
166
|
};
|
|
164
167
|
|
|
165
|
-
var onRevoke = function
|
|
166
|
-
var
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
168
|
+
var onRevoke = /*#__PURE__*/function () {
|
|
169
|
+
var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(documentOrIndex, sharingId, memberIndex) {
|
|
170
|
+
var _id;
|
|
171
|
+
|
|
172
|
+
return _regeneratorRuntime.wrap(function _callee3$(_context3) {
|
|
173
|
+
while (1) switch (_context3.prev = _context3.next) {
|
|
174
|
+
case 0:
|
|
175
|
+
if (!(typeof documentOrIndex === 'string' && documentOrIndex.startsWith(RECIPIENT_INDEX_PREFIX))) {
|
|
176
|
+
_context3.next = 5;
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
_id = documentOrIndex.split(RECIPIENT_INDEX_PREFIX)[1];
|
|
181
|
+
setFederatedRecipients(function (prev) {
|
|
182
|
+
return {
|
|
183
|
+
recipients: prev.recipients.filter(function (r) {
|
|
184
|
+
return r._id !== _id;
|
|
185
|
+
}),
|
|
186
|
+
readOnlyRecipients: prev.readOnlyRecipients.filter(function (r) {
|
|
187
|
+
return r._id !== _id;
|
|
188
|
+
})
|
|
189
|
+
};
|
|
190
|
+
});
|
|
191
|
+
_context3.next = 7;
|
|
192
|
+
break;
|
|
193
|
+
|
|
194
|
+
case 5:
|
|
195
|
+
_context3.next = 7;
|
|
196
|
+
return revoke(documentOrIndex, sharingId, memberIndex);
|
|
197
|
+
|
|
198
|
+
case 7:
|
|
199
|
+
case "end":
|
|
200
|
+
return _context3.stop();
|
|
201
|
+
}
|
|
202
|
+
}, _callee3);
|
|
203
|
+
}));
|
|
204
|
+
|
|
205
|
+
return function onRevoke(_x, _x2, _x3) {
|
|
206
|
+
return _ref4.apply(this, arguments);
|
|
207
|
+
};
|
|
208
|
+
}();
|
|
178
209
|
|
|
179
|
-
var
|
|
210
|
+
var existingRecipients = existingDocument ? getRecipients(existingDocument._id) : [];
|
|
211
|
+
var recipients = [].concat(_toConsumableArray(existingRecipients), _toConsumableArray(formatRecipients(federatedRecipients)));
|
|
180
212
|
var modalTitle = t('FederatedFolder.shareTitle', {
|
|
181
213
|
name: folderName
|
|
182
214
|
});
|
|
@@ -189,7 +221,7 @@ export var FederatedFolderModal = withLocales(function (_ref) {
|
|
|
189
221
|
},
|
|
190
222
|
recipients: recipients,
|
|
191
223
|
readOnlyRecipients: federatedRecipients.readOnlyRecipients,
|
|
192
|
-
currentRecipients:
|
|
224
|
+
currentRecipients: existingRecipients,
|
|
193
225
|
onRevoke: onRevoke,
|
|
194
226
|
onSetType: onSetType,
|
|
195
227
|
onSend: onSend,
|
|
@@ -7,7 +7,9 @@ import { createMockClient } from 'cozy-client';
|
|
|
7
7
|
import { FederatedFolderModal } from './FederatedFolderModal';
|
|
8
8
|
import AppLike from '../SharingBanner/test/AppLike';
|
|
9
9
|
var mockShare = jest.fn();
|
|
10
|
+
var mockRevoke = jest.fn();
|
|
10
11
|
var mockGetSharingLink = jest.fn();
|
|
12
|
+
var mockGetRecipients = jest.fn().mockReturnValue([]);
|
|
11
13
|
var mockShowAlert = jest.fn();
|
|
12
14
|
var mockOnClose = jest.fn();
|
|
13
15
|
jest.mock('../../hooks/useSharingContext', function () {
|
|
@@ -15,8 +17,10 @@ jest.mock('../../hooks/useSharingContext', function () {
|
|
|
15
17
|
useSharingContext: function useSharingContext() {
|
|
16
18
|
return {
|
|
17
19
|
share: mockShare,
|
|
20
|
+
revoke: mockRevoke,
|
|
18
21
|
getSharingLink: mockGetSharingLink,
|
|
19
|
-
getDocumentPermissions: jest.fn().mockReturnValue([])
|
|
22
|
+
getDocumentPermissions: jest.fn().mockReturnValue([]),
|
|
23
|
+
getRecipients: mockGetRecipients
|
|
20
24
|
};
|
|
21
25
|
}
|
|
22
26
|
};
|
|
@@ -91,6 +95,13 @@ jest.mock('./DumbFederatedFolderModal', function () {
|
|
|
91
95
|
return onRevoke('virtual-shared-drive-sharing-r1');
|
|
92
96
|
}
|
|
93
97
|
}, "Revoke"), /*#__PURE__*/React.createElement("button", {
|
|
98
|
+
"data-testid": "btn-revoke-existing",
|
|
99
|
+
onClick: function onClick() {
|
|
100
|
+
return onRevoke({
|
|
101
|
+
_id: 'folder-123'
|
|
102
|
+
}, 'abc', 1);
|
|
103
|
+
}
|
|
104
|
+
}, "Revoke Existing"), /*#__PURE__*/React.createElement("button", {
|
|
94
105
|
"data-testid": "btn-close",
|
|
95
106
|
onClick: onClose
|
|
96
107
|
}, "Close"), /*#__PURE__*/React.createElement("button", {
|
|
@@ -150,6 +161,7 @@ describe('FederatedFolderModal', function () {
|
|
|
150
161
|
beforeEach(function () {
|
|
151
162
|
jest.clearAllMocks();
|
|
152
163
|
mockGetSharingLink.mockReturnValue('https://example.com/share/abc123');
|
|
164
|
+
mockGetRecipients.mockReturnValue([]);
|
|
153
165
|
client = createTestClient();
|
|
154
166
|
sharingContextValue = createSharingContextValue();
|
|
155
167
|
});
|
|
@@ -511,22 +523,109 @@ describe('FederatedFolderModal', function () {
|
|
|
511
523
|
}, _callee12);
|
|
512
524
|
})));
|
|
513
525
|
});
|
|
514
|
-
describe('
|
|
515
|
-
|
|
526
|
+
describe('existing recipients', function () {
|
|
527
|
+
var existingRecipients = [{
|
|
528
|
+
index: 'sharing-abc-member-0',
|
|
529
|
+
name: 'Charlie',
|
|
530
|
+
email: 'charlie@example.com',
|
|
531
|
+
status: 'owner',
|
|
532
|
+
type: 'two-way',
|
|
533
|
+
sharingId: 'abc',
|
|
534
|
+
memberIndex: 0
|
|
535
|
+
}, {
|
|
536
|
+
index: 'sharing-abc-member-1',
|
|
537
|
+
name: 'Diana',
|
|
538
|
+
email: 'diana@example.com',
|
|
539
|
+
status: 'ready',
|
|
540
|
+
type: 'one-way',
|
|
541
|
+
sharingId: 'abc',
|
|
542
|
+
memberIndex: 1
|
|
543
|
+
}];
|
|
544
|
+
it('should display existing recipients from getRecipients', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee13() {
|
|
516
545
|
var _setup13, getByTestId;
|
|
517
546
|
|
|
518
547
|
return _regeneratorRuntime.wrap(function _callee13$(_context13) {
|
|
519
548
|
while (1) switch (_context13.prev = _context13.next) {
|
|
520
549
|
case 0:
|
|
550
|
+
mockGetRecipients.mockReturnValue(existingRecipients);
|
|
521
551
|
_setup13 = setup(), getByTestId = _setup13.getByTestId;
|
|
522
|
-
_context13.next =
|
|
552
|
+
_context13.next = 4;
|
|
553
|
+
return waitFor(function () {
|
|
554
|
+
expect(getByTestId('recipients-count').textContent).toBe('2');
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
case 4:
|
|
558
|
+
case "end":
|
|
559
|
+
return _context13.stop();
|
|
560
|
+
}
|
|
561
|
+
}, _callee13);
|
|
562
|
+
})));
|
|
563
|
+
it('should pass existing recipients as currentRecipients', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee14() {
|
|
564
|
+
var _setup14, getByTestId;
|
|
565
|
+
|
|
566
|
+
return _regeneratorRuntime.wrap(function _callee14$(_context14) {
|
|
567
|
+
while (1) switch (_context14.prev = _context14.next) {
|
|
568
|
+
case 0:
|
|
569
|
+
mockGetRecipients.mockReturnValue(existingRecipients);
|
|
570
|
+
_setup14 = setup(), getByTestId = _setup14.getByTestId;
|
|
571
|
+
_context14.next = 4;
|
|
572
|
+
return waitFor(function () {
|
|
573
|
+
expect(getByTestId('recipients-count').textContent).toBe('2');
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
case 4:
|
|
577
|
+
case "end":
|
|
578
|
+
return _context14.stop();
|
|
579
|
+
}
|
|
580
|
+
}, _callee14);
|
|
581
|
+
})));
|
|
582
|
+
it('should call revoke for existing member', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee15() {
|
|
583
|
+
var _setup15, getByTestId;
|
|
584
|
+
|
|
585
|
+
return _regeneratorRuntime.wrap(function _callee15$(_context15) {
|
|
586
|
+
while (1) switch (_context15.prev = _context15.next) {
|
|
587
|
+
case 0:
|
|
588
|
+
mockGetRecipients.mockReturnValue(existingRecipients);
|
|
589
|
+
mockRevoke.mockResolvedValueOnce({});
|
|
590
|
+
_setup15 = setup(), getByTestId = _setup15.getByTestId;
|
|
591
|
+
_context15.next = 5;
|
|
592
|
+
return waitFor(function () {
|
|
593
|
+
expect(getByTestId('dumb-modal')).toBeTruthy();
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
case 5:
|
|
597
|
+
// Simulate revoke of an existing member (non-virtual-shared-drive index)
|
|
598
|
+
fireEvent.click(getByTestId('btn-revoke-existing'));
|
|
599
|
+
_context15.next = 8;
|
|
600
|
+
return waitFor(function () {
|
|
601
|
+
expect(mockRevoke).toHaveBeenCalledWith({
|
|
602
|
+
_id: 'folder-123'
|
|
603
|
+
}, 'abc', 1);
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
case 8:
|
|
607
|
+
case "end":
|
|
608
|
+
return _context15.stop();
|
|
609
|
+
}
|
|
610
|
+
}, _callee15);
|
|
611
|
+
})));
|
|
612
|
+
});
|
|
613
|
+
describe('createContact callback', function () {
|
|
614
|
+
it('should call client.create when creating a contact', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee16() {
|
|
615
|
+
var _setup16, getByTestId;
|
|
616
|
+
|
|
617
|
+
return _regeneratorRuntime.wrap(function _callee16$(_context16) {
|
|
618
|
+
while (1) switch (_context16.prev = _context16.next) {
|
|
619
|
+
case 0:
|
|
620
|
+
_setup16 = setup(), getByTestId = _setup16.getByTestId;
|
|
621
|
+
_context16.next = 3;
|
|
523
622
|
return waitFor(function () {
|
|
524
623
|
expect(getByTestId('btn-create-contact')).toBeTruthy();
|
|
525
624
|
});
|
|
526
625
|
|
|
527
626
|
case 3:
|
|
528
627
|
fireEvent.click(getByTestId('btn-create-contact'));
|
|
529
|
-
|
|
628
|
+
_context16.next = 6;
|
|
530
629
|
return waitFor(function () {
|
|
531
630
|
expect(client.create).toHaveBeenCalledWith('io.cozy.contacts', {
|
|
532
631
|
email: 'test@example.com'
|
|
@@ -535,9 +634,9 @@ describe('FederatedFolderModal', function () {
|
|
|
535
634
|
|
|
536
635
|
case 6:
|
|
537
636
|
case "end":
|
|
538
|
-
return
|
|
637
|
+
return _context16.stop();
|
|
539
638
|
}
|
|
540
|
-
},
|
|
639
|
+
}, _callee16);
|
|
541
640
|
})));
|
|
542
641
|
});
|
|
543
642
|
});
|
|
@@ -14,7 +14,7 @@ import withLocales from '../../hoc/withLocales';
|
|
|
14
14
|
import { useSharingContext } from '../../hooks/useSharingContext';
|
|
15
15
|
import { FederatedFolderModal } from '../FederatedFolder/FederatedFolderModal';
|
|
16
16
|
export var ShareModal = withLocales(function (props) {
|
|
17
|
-
var _location$state
|
|
17
|
+
var _location$state;
|
|
18
18
|
|
|
19
19
|
var location = useLocation === null || useLocation === void 0 ? void 0 : useLocation();
|
|
20
20
|
var locationProps = location === null || location === void 0 || (_location$state = location.state) === null || _location$state === void 0 ? void 0 : _location$state.modalProps;
|
|
@@ -59,12 +59,8 @@ export var ShareModal = withLocales(function (props) {
|
|
|
59
59
|
}();
|
|
60
60
|
|
|
61
61
|
var isFederatedMode = flag('drive.federated-shared-folder.enabled');
|
|
62
|
-
var hasSharings = ((_byDocId$document$id = byDocId[document.id]) === null || _byDocId$document$id === void 0 || (_byDocId$document$id = _byDocId$document$id.sharings) === null || _byDocId$document$id === void 0 ? void 0 : _byDocId$document$id.length) > 0; // In federated mode, show FederatedFolderModal for unshared documents (sharing an existing folder).
|
|
63
|
-
// When isFederatedMode && hasSharings is true, we intentionally fall through to the legacy
|
|
64
|
-
// modals (EditableSharingModal / SharingDetailsModal) because federated-shared folders are
|
|
65
|
-
// handled by those components.
|
|
66
62
|
|
|
67
|
-
if (isFederatedMode && allLoaded
|
|
63
|
+
if (isFederatedMode && allLoaded) {
|
|
68
64
|
return /*#__PURE__*/React.createElement(FederatedFolderModal, {
|
|
69
65
|
document: document,
|
|
70
66
|
onClose: rest.onClose
|
|
@@ -123,6 +123,12 @@ var SharingBannerByLink = function SharingBannerByLink(_ref3) {
|
|
|
123
123
|
t = _useI18n4.t;
|
|
124
124
|
|
|
125
125
|
var HOME_LINK_HREF = flag('signup.url');
|
|
126
|
+
var canNotCreateTwakeFromPublicSharingLink = flag('drive.twake-creation-from-public-sharing.disabled');
|
|
127
|
+
|
|
128
|
+
if (canNotCreateTwakeFromPublicSharingLink) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
|
|
126
132
|
return /*#__PURE__*/React.createElement(Banner, {
|
|
127
133
|
bgcolor: "var(--defaultBackgroundColor)",
|
|
128
134
|
text: /*#__PURE__*/React.createElement(SharingBannerByLinkText, null),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cozy-sharing",
|
|
3
|
-
"version": "28.
|
|
3
|
+
"version": "28.9.0",
|
|
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": "
|
|
86
|
+
"gitHead": "53934e510ce08e3066a3b6aad6d9bb05778dede8"
|
|
87
87
|
}
|
|
@@ -25,7 +25,9 @@ export const FederatedFolderModal = withLocales(
|
|
|
25
25
|
getFederatedShareLink,
|
|
26
26
|
getDocumentPermissions,
|
|
27
27
|
getOwner,
|
|
28
|
-
getSharingById
|
|
28
|
+
getSharingById,
|
|
29
|
+
getRecipients,
|
|
30
|
+
revoke
|
|
29
31
|
} = useSharingContext()
|
|
30
32
|
const { showAlert } = useAlert()
|
|
31
33
|
|
|
@@ -107,18 +109,29 @@ export const FederatedFolderModal = withLocales(
|
|
|
107
109
|
}
|
|
108
110
|
}
|
|
109
111
|
|
|
110
|
-
const onRevoke =
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
const onRevoke = async (documentOrIndex, sharingId, memberIndex) => {
|
|
113
|
+
if (
|
|
114
|
+
typeof documentOrIndex === 'string' &&
|
|
115
|
+
documentOrIndex.startsWith(RECIPIENT_INDEX_PREFIX)
|
|
116
|
+
) {
|
|
117
|
+
const _id = documentOrIndex.split(RECIPIENT_INDEX_PREFIX)[1]
|
|
118
|
+
setFederatedRecipients(prev => ({
|
|
115
119
|
recipients: prev.recipients.filter(r => r._id !== _id),
|
|
116
120
|
readOnlyRecipients: prev.readOnlyRecipients.filter(r => r._id !== _id)
|
|
117
|
-
}
|
|
118
|
-
}
|
|
121
|
+
}))
|
|
122
|
+
} else {
|
|
123
|
+
await revoke(documentOrIndex, sharingId, memberIndex)
|
|
124
|
+
}
|
|
119
125
|
}
|
|
120
126
|
|
|
121
|
-
const
|
|
127
|
+
const existingRecipients = existingDocument
|
|
128
|
+
? getRecipients(existingDocument._id)
|
|
129
|
+
: []
|
|
130
|
+
|
|
131
|
+
const recipients = [
|
|
132
|
+
...existingRecipients,
|
|
133
|
+
...formatRecipients(federatedRecipients)
|
|
134
|
+
]
|
|
122
135
|
|
|
123
136
|
const modalTitle = t('FederatedFolder.shareTitle', { name: folderName })
|
|
124
137
|
|
|
@@ -131,7 +144,7 @@ export const FederatedFolderModal = withLocales(
|
|
|
131
144
|
createContact={contact => client.create('io.cozy.contacts', contact)}
|
|
132
145
|
recipients={recipients}
|
|
133
146
|
readOnlyRecipients={federatedRecipients.readOnlyRecipients}
|
|
134
|
-
currentRecipients={
|
|
147
|
+
currentRecipients={existingRecipients}
|
|
135
148
|
onRevoke={onRevoke}
|
|
136
149
|
onSetType={onSetType}
|
|
137
150
|
onSend={onSend}
|
|
@@ -7,15 +7,19 @@ import { FederatedFolderModal } from './FederatedFolderModal'
|
|
|
7
7
|
import AppLike from '../SharingBanner/test/AppLike'
|
|
8
8
|
|
|
9
9
|
const mockShare = jest.fn()
|
|
10
|
+
const mockRevoke = jest.fn()
|
|
10
11
|
const mockGetSharingLink = jest.fn()
|
|
12
|
+
const mockGetRecipients = jest.fn().mockReturnValue([])
|
|
11
13
|
const mockShowAlert = jest.fn()
|
|
12
14
|
const mockOnClose = jest.fn()
|
|
13
15
|
|
|
14
16
|
jest.mock('../../hooks/useSharingContext', () => ({
|
|
15
17
|
useSharingContext: () => ({
|
|
16
18
|
share: mockShare,
|
|
19
|
+
revoke: mockRevoke,
|
|
17
20
|
getSharingLink: mockGetSharingLink,
|
|
18
|
-
getDocumentPermissions: jest.fn().mockReturnValue([])
|
|
21
|
+
getDocumentPermissions: jest.fn().mockReturnValue([]),
|
|
22
|
+
getRecipients: mockGetRecipients
|
|
19
23
|
})
|
|
20
24
|
}))
|
|
21
25
|
|
|
@@ -79,6 +83,12 @@ jest.mock('./DumbFederatedFolderModal', () => ({
|
|
|
79
83
|
>
|
|
80
84
|
Revoke
|
|
81
85
|
</button>
|
|
86
|
+
<button
|
|
87
|
+
data-testid="btn-revoke-existing"
|
|
88
|
+
onClick={() => onRevoke({ _id: 'folder-123' }, 'abc', 1)}
|
|
89
|
+
>
|
|
90
|
+
Revoke Existing
|
|
91
|
+
</button>
|
|
82
92
|
<button data-testid="btn-close" onClick={onClose}>
|
|
83
93
|
Close
|
|
84
94
|
</button>
|
|
@@ -135,6 +145,7 @@ describe('FederatedFolderModal', () => {
|
|
|
135
145
|
beforeEach(() => {
|
|
136
146
|
jest.clearAllMocks()
|
|
137
147
|
mockGetSharingLink.mockReturnValue('https://example.com/share/abc123')
|
|
148
|
+
mockGetRecipients.mockReturnValue([])
|
|
138
149
|
client = createTestClient()
|
|
139
150
|
sharingContextValue = createSharingContextValue()
|
|
140
151
|
})
|
|
@@ -356,6 +367,64 @@ describe('FederatedFolderModal', () => {
|
|
|
356
367
|
})
|
|
357
368
|
})
|
|
358
369
|
|
|
370
|
+
describe('existing recipients', () => {
|
|
371
|
+
const existingRecipients = [
|
|
372
|
+
{
|
|
373
|
+
index: 'sharing-abc-member-0',
|
|
374
|
+
name: 'Charlie',
|
|
375
|
+
email: 'charlie@example.com',
|
|
376
|
+
status: 'owner',
|
|
377
|
+
type: 'two-way',
|
|
378
|
+
sharingId: 'abc',
|
|
379
|
+
memberIndex: 0
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
index: 'sharing-abc-member-1',
|
|
383
|
+
name: 'Diana',
|
|
384
|
+
email: 'diana@example.com',
|
|
385
|
+
status: 'ready',
|
|
386
|
+
type: 'one-way',
|
|
387
|
+
sharingId: 'abc',
|
|
388
|
+
memberIndex: 1
|
|
389
|
+
}
|
|
390
|
+
]
|
|
391
|
+
|
|
392
|
+
it('should display existing recipients from getRecipients', async () => {
|
|
393
|
+
mockGetRecipients.mockReturnValue(existingRecipients)
|
|
394
|
+
const { getByTestId } = setup()
|
|
395
|
+
|
|
396
|
+
await waitFor(() => {
|
|
397
|
+
expect(getByTestId('recipients-count').textContent).toBe('2')
|
|
398
|
+
})
|
|
399
|
+
})
|
|
400
|
+
|
|
401
|
+
it('should pass existing recipients as currentRecipients', async () => {
|
|
402
|
+
mockGetRecipients.mockReturnValue(existingRecipients)
|
|
403
|
+
const { getByTestId } = setup()
|
|
404
|
+
|
|
405
|
+
await waitFor(() => {
|
|
406
|
+
expect(getByTestId('recipients-count').textContent).toBe('2')
|
|
407
|
+
})
|
|
408
|
+
})
|
|
409
|
+
|
|
410
|
+
it('should call revoke for existing member', async () => {
|
|
411
|
+
mockGetRecipients.mockReturnValue(existingRecipients)
|
|
412
|
+
mockRevoke.mockResolvedValueOnce({})
|
|
413
|
+
const { getByTestId } = setup()
|
|
414
|
+
|
|
415
|
+
await waitFor(() => {
|
|
416
|
+
expect(getByTestId('dumb-modal')).toBeTruthy()
|
|
417
|
+
})
|
|
418
|
+
|
|
419
|
+
// Simulate revoke of an existing member (non-virtual-shared-drive index)
|
|
420
|
+
fireEvent.click(getByTestId('btn-revoke-existing'))
|
|
421
|
+
|
|
422
|
+
await waitFor(() => {
|
|
423
|
+
expect(mockRevoke).toHaveBeenCalledWith({ _id: 'folder-123' }, 'abc', 1)
|
|
424
|
+
})
|
|
425
|
+
})
|
|
426
|
+
})
|
|
427
|
+
|
|
359
428
|
describe('createContact callback', () => {
|
|
360
429
|
it('should call client.create when creating a contact', async () => {
|
|
361
430
|
const { getByTestId } = setup()
|
|
@@ -35,13 +35,7 @@ export const ShareModal = withLocales(props => {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
const isFederatedMode = flag('drive.federated-shared-folder.enabled')
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
// In federated mode, show FederatedFolderModal for unshared documents (sharing an existing folder).
|
|
41
|
-
// When isFederatedMode && hasSharings is true, we intentionally fall through to the legacy
|
|
42
|
-
// modals (EditableSharingModal / SharingDetailsModal) because federated-shared folders are
|
|
43
|
-
// handled by those components.
|
|
44
|
-
if (isFederatedMode && allLoaded && !hasSharings) {
|
|
38
|
+
if (isFederatedMode && allLoaded) {
|
|
45
39
|
return <FederatedFolderModal document={document} onClose={rest.onClose} />
|
|
46
40
|
}
|
|
47
41
|
|
|
@@ -113,6 +113,13 @@ const SharingBannerByLink = ({ onClose }) => {
|
|
|
113
113
|
const { t } = useI18n()
|
|
114
114
|
|
|
115
115
|
const HOME_LINK_HREF = flag('signup.url')
|
|
116
|
+
const canNotCreateTwakeFromPublicSharingLink = flag(
|
|
117
|
+
'drive.twake-creation-from-public-sharing.disabled'
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
if (canNotCreateTwakeFromPublicSharingLink) {
|
|
121
|
+
return null
|
|
122
|
+
}
|
|
116
123
|
|
|
117
124
|
return (
|
|
118
125
|
<Banner
|