cozy-sharing 32.1.2 → 32.3.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/.claude/settings.local.json +27 -0
- package/AGENTS.md +7 -0
- package/CHANGELOG.md +18 -0
- package/dist/RefreshableSharings.spec.js +40 -0
- package/dist/assets/illustrations/illustration-shared-drives.svg +1 -0
- package/dist/components/EditLinkPermissionDialog.js +72 -0
- package/dist/components/EditLinkPermissionDialog.spec.js +48 -0
- package/dist/components/FederatedFolder/DumbFederatedFolderModal.js +65 -0
- package/dist/components/FederatedFolder/DumbFederatedFolderModal.spec.js +107 -0
- package/dist/components/FederatedFolder/FederatedFolderModal.js +41 -4
- package/dist/components/FederatedFolder/FederatedFolderModal.jsx.tmp.179197.1773939270471 +172 -0
- package/dist/components/FederatedFolder/FederatedFolderModal.spec.js +79 -8
- package/dist/components/Recipient/actions/revokeGroup.js +42 -0
- package/dist/components/Recipient/actions/revokeMember.js +42 -0
- package/dist/components/Recipient/actions/revokeSharedDriveMember.js +41 -0
- package/dist/components/ShareAutosuggest.js +1 -0
- package/dist/components/ShareAutosuggest.spec.js +12 -4
- package/dist/components/ShareDialogCozyToCozy.spec.js +55 -8
- package/dist/components/ShareDiscardChangesModal.js +35 -0
- package/dist/components/ShareModal/ShareModal copy.js +43 -0
- package/dist/components/ShareModal/ShareModal.spec.js +197 -0
- package/dist/components/ShareModal/ShareModalBatchContainer.js +276 -0
- package/dist/components/ShareModal/ShareModalBatchContainer.spec.js +131 -0
- package/dist/components/ShareModal/SharedDriveEditModal.js +59 -0
- package/dist/components/ShareRecipientsInput.js +13 -3
- package/dist/components/ShareRecipientsInput.spec.js +63 -4
- package/dist/components/SharedDrive/DumbSharedDriveModal.js +78 -0
- package/dist/components/SharedDrive/DumbSharedDriveModal.spec.js +126 -0
- package/dist/components/SharedDrive/SharedDriveEditModal.js +110 -0
- package/dist/components/SharedDrive/SharedDriveModal copy.js +356 -0
- package/dist/components/SharedDrive/helpers.js +102 -0
- package/dist/components/SharedDrive/helpers.spec.js +208 -0
- package/dist/components/SharedDriveEditModal.js +43 -0
- package/dist/components/SharedFolder/DumbBatchSharedFolderModal.spec.js +321 -0
- package/dist/components/SharedStatus.js +61 -0
- package/dist/components/SharedStatus.spec.js +44 -0
- package/dist/components/Sharesubmit.js +28 -0
- package/dist/components/__snapshots__/SharedStatus.spec.js.snap +94 -0
- package/dist/helpers/owner.js +14 -0
- package/dist/helpers/owner.spec.js +34 -0
- package/dist/hooks/useConfirmDiscardChanges.js +33 -0
- package/dist/hooks/useContactsAndGroups.js +65 -0
- package/dist/hooks/useSharedDrive.js +130 -0
- package/dist/hooks/useSharedDriveContactsAndGroups.js +65 -0
- package/dist/propTypes.js +26 -0
- package/dist/styles/shareddrive.styl +8 -0
- package/locales/en.json +10 -5
- package/locales/fr.json +10 -5
- package/locales/ru.json +10 -5
- package/locales/vi.json +10 -5
- package/package.json +2 -2
- package/src/components/FederatedFolder/FederatedFolderModal.jsx +184 -138
- package/src/components/FederatedFolder/FederatedFolderModal.spec.jsx +47 -0
- package/src/components/ShareAutosuggest.jsx +1 -0
- package/src/components/ShareAutosuggest.spec.jsx +10 -5
- package/src/components/ShareDialogCozyToCozy.spec.jsx +50 -4
- package/src/components/ShareDiscardChangesModal.jsx +40 -0
- package/src/components/ShareRecipientsInput.jsx +11 -6
- package/src/components/ShareRecipientsInput.spec.jsx +59 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
+
import { render } from "@testing-library/react";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import flag from "cozy-flags";
|
|
5
|
+
import { ShareModal } from "./ShareModal";
|
|
6
|
+
import { useSharingContext } from "../../hooks/useSharingContext";
|
|
7
|
+
var mockOnClose = jest.fn();
|
|
8
|
+
var mockOnShare = jest.fn();
|
|
9
|
+
var mockOnRevoke = jest.fn();
|
|
10
|
+
jest.mock("cozy-flags");
|
|
11
|
+
jest.mock("../../hooks/useSharingContext", function () {
|
|
12
|
+
return {
|
|
13
|
+
useSharingContext: jest.fn()
|
|
14
|
+
};
|
|
15
|
+
});
|
|
16
|
+
jest.mock("./EditableSharingModal", function () {
|
|
17
|
+
return {
|
|
18
|
+
__esModule: true,
|
|
19
|
+
default: function _default() {
|
|
20
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
21
|
+
"data-testid": "editable-sharing-modal"
|
|
22
|
+
}, "EditableSharingModal");
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
jest.mock("./SharingDetailsModal", function () {
|
|
27
|
+
return {
|
|
28
|
+
SharingDetailsModal: function SharingDetailsModal() {
|
|
29
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
30
|
+
"data-testid": "sharing-details-modal"
|
|
31
|
+
}, "SharingDetailsModal");
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
jest.mock("../FederatedFolder/FederatedFolderModal", function () {
|
|
36
|
+
return {
|
|
37
|
+
FederatedFolderModal: function FederatedFolderModal() {
|
|
38
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
39
|
+
"data-testid": "federated-folder-modal"
|
|
40
|
+
}, "FederatedFolderModal");
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
jest.mock("../../hoc/withLocales", function () {
|
|
45
|
+
return {
|
|
46
|
+
__esModule: true,
|
|
47
|
+
default: function _default(Component) {
|
|
48
|
+
return Component;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
describe("ShareModal", function () {
|
|
53
|
+
var defaultDocument = {
|
|
54
|
+
id: "doc-123",
|
|
55
|
+
_id: "doc-123",
|
|
56
|
+
name: "Test Document"
|
|
57
|
+
};
|
|
58
|
+
var defaultProps = {
|
|
59
|
+
document: defaultDocument,
|
|
60
|
+
onClose: mockOnClose,
|
|
61
|
+
onShare: mockOnShare,
|
|
62
|
+
onRevoke: mockOnRevoke
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
var setup = function setup() {
|
|
66
|
+
var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
67
|
+
return render( /*#__PURE__*/React.createElement(ShareModal, _extends({}, defaultProps, props)));
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
beforeEach(function () {
|
|
71
|
+
jest.clearAllMocks();
|
|
72
|
+
flag.mockImplementation(function () {
|
|
73
|
+
return false;
|
|
74
|
+
});
|
|
75
|
+
useSharingContext.mockReturnValue({
|
|
76
|
+
byDocId: {},
|
|
77
|
+
isOwner: function isOwner() {
|
|
78
|
+
return true;
|
|
79
|
+
},
|
|
80
|
+
canReshare: function canReshare() {
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
describe("federated mode", function () {
|
|
86
|
+
it("should render FederatedFolderModal when federated mode is enabled and no sharings exist", function () {
|
|
87
|
+
flag.mockImplementation(function (flagName) {
|
|
88
|
+
if (flagName === "drive.federated-shared-folder.enabled") {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return false;
|
|
93
|
+
});
|
|
94
|
+
useSharingContext.mockReturnValue({
|
|
95
|
+
byDocId: {
|
|
96
|
+
"doc-123": {
|
|
97
|
+
sharings: []
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
isOwner: function isOwner() {
|
|
101
|
+
return true;
|
|
102
|
+
},
|
|
103
|
+
canReshare: function canReshare() {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
var _setup = setup(),
|
|
109
|
+
getByTestId = _setup.getByTestId;
|
|
110
|
+
|
|
111
|
+
expect(getByTestId("federated-folder-modal")).toBeInTheDocument();
|
|
112
|
+
});
|
|
113
|
+
it("should render EditableSharingModal when federated mode is enabled but sharings exist", function () {
|
|
114
|
+
flag.mockImplementation(function (flagName) {
|
|
115
|
+
if (flagName === "drive.federated-shared-folder.enabled") {
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return false;
|
|
120
|
+
});
|
|
121
|
+
useSharingContext.mockReturnValue({
|
|
122
|
+
byDocId: {
|
|
123
|
+
"doc-123": {
|
|
124
|
+
sharings: [{
|
|
125
|
+
id: "sharing-1"
|
|
126
|
+
}]
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
isOwner: function isOwner() {
|
|
130
|
+
return true;
|
|
131
|
+
},
|
|
132
|
+
canReshare: function canReshare() {
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
var _setup2 = setup(),
|
|
138
|
+
getByTestId = _setup2.getByTestId;
|
|
139
|
+
|
|
140
|
+
expect(getByTestId("editable-sharing-modal")).toBeInTheDocument();
|
|
141
|
+
});
|
|
142
|
+
it("should render EditableSharingModal when federated mode is disabled", function () {
|
|
143
|
+
flag.mockImplementation(function () {
|
|
144
|
+
return false;
|
|
145
|
+
});
|
|
146
|
+
useSharingContext.mockReturnValue({
|
|
147
|
+
byDocId: {
|
|
148
|
+
"doc-123": {
|
|
149
|
+
sharings: []
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
isOwner: function isOwner() {
|
|
153
|
+
return true;
|
|
154
|
+
},
|
|
155
|
+
canReshare: function canReshare() {
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
var _setup3 = setup(),
|
|
161
|
+
getByTestId = _setup3.getByTestId;
|
|
162
|
+
|
|
163
|
+
expect(getByTestId("editable-sharing-modal")).toBeInTheDocument();
|
|
164
|
+
});
|
|
165
|
+
it("should render FederatedFolderModal when document has no sharings entry", function () {
|
|
166
|
+
flag.mockImplementation(function (flagName) {
|
|
167
|
+
if (flagName === "drive.federated-shared-folder.enabled") {
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return false;
|
|
172
|
+
});
|
|
173
|
+
useSharingContext.mockReturnValue({
|
|
174
|
+
byDocId: {},
|
|
175
|
+
isOwner: function isOwner() {
|
|
176
|
+
return true;
|
|
177
|
+
},
|
|
178
|
+
canReshare: function canReshare() {
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
var _setup4 = setup(),
|
|
184
|
+
getByTestId = _setup4.getByTestId;
|
|
185
|
+
|
|
186
|
+
expect(getByTestId("federated-folder-modal")).toBeInTheDocument();
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
describe("regular mode", function () {
|
|
190
|
+
it("should render EditableSharingModal by default", function () {
|
|
191
|
+
var _setup5 = setup(),
|
|
192
|
+
getByTestId = _setup5.getByTestId;
|
|
193
|
+
|
|
194
|
+
expect(getByTestId("editable-sharing-modal")).toBeInTheDocument();
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
});
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
2
|
+
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
3
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
4
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
5
|
+
import PropTypes from 'prop-types';
|
|
6
|
+
import React, { useState } from 'react';
|
|
7
|
+
import { useI18n } from 'twake-i18n';
|
|
8
|
+
import { useAlert } from 'cozy-ui/transpiled/react/providers/Alert';
|
|
9
|
+
import withLocales from '../../hoc/withLocales';
|
|
10
|
+
import { Contact } from '../../models';
|
|
11
|
+
import { ShareModal } from '../ShareModal';
|
|
12
|
+
/**
|
|
13
|
+
* Merge and deduplicate recipients arrays
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
var mergeAndDeduplicateRecipients = function mergeAndDeduplicateRecipients(arrays) {
|
|
17
|
+
var combinedArray = arrays.flat();
|
|
18
|
+
var seenIds = new Set();
|
|
19
|
+
return combinedArray.filter(function (item) {
|
|
20
|
+
if (!seenIds.has(item.id || item._id)) {
|
|
21
|
+
seenIds.add(item.id || item._id);
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return false;
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Container component that manages sharing recipients in batch mode.
|
|
30
|
+
* Instead of sharing immediately when adding recipients, it accumulates them
|
|
31
|
+
* and sends all at once when clicking the submit button.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
export var ShareModalBatchContainer = withLocales(function (_ref) {
|
|
36
|
+
var document = _ref.document,
|
|
37
|
+
documentType = _ref.documentType,
|
|
38
|
+
isOwner = _ref.isOwner,
|
|
39
|
+
link = _ref.link,
|
|
40
|
+
permissions = _ref.permissions,
|
|
41
|
+
existingRecipients = _ref.recipients,
|
|
42
|
+
sharing = _ref.sharing,
|
|
43
|
+
sharingDesc = _ref.sharingDesc,
|
|
44
|
+
onClose = _ref.onClose,
|
|
45
|
+
onRevoke = _ref.onRevoke,
|
|
46
|
+
onRevokeSelf = _ref.onRevokeSelf,
|
|
47
|
+
share = _ref.share,
|
|
48
|
+
createContact = _ref.createContact,
|
|
49
|
+
hasSharedChild = _ref.hasSharedChild,
|
|
50
|
+
hasSharedParent = _ref.hasSharedParent,
|
|
51
|
+
twoStepsConfirmationMethods = _ref.twoStepsConfirmationMethods;
|
|
52
|
+
|
|
53
|
+
var _useI18n = useI18n(),
|
|
54
|
+
t = _useI18n.t;
|
|
55
|
+
|
|
56
|
+
var _useAlert = useAlert(),
|
|
57
|
+
showAlert = _useAlert.showAlert; // State for pending recipients (not yet shared)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
var _useState = useState({
|
|
61
|
+
recipients: [],
|
|
62
|
+
readOnlyRecipients: []
|
|
63
|
+
}),
|
|
64
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
65
|
+
pendingRecipients = _useState2[0],
|
|
66
|
+
setPendingRecipients = _useState2[1]; // Accumulate recipients when added via ShareByEmail
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
var onShare = function onShare(params) {
|
|
70
|
+
setPendingRecipients(function (prev) {
|
|
71
|
+
return {
|
|
72
|
+
recipients: mergeAndDeduplicateRecipients([prev.recipients, params.recipients || []]),
|
|
73
|
+
readOnlyRecipients: mergeAndDeduplicateRecipients([prev.readOnlyRecipients, params.readOnlyRecipients || []])
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
}; // Handle changing a recipient's permission type
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
var onSetType = function onSetType(index, newType) {
|
|
80
|
+
var recipientId = index;
|
|
81
|
+
|
|
82
|
+
if (newType === 'two-way') {
|
|
83
|
+
setPendingRecipients(function (prev) {
|
|
84
|
+
var recipientToMove = prev.readOnlyRecipients.find(function (r) {
|
|
85
|
+
return (r.id || r._id) === recipientId;
|
|
86
|
+
});
|
|
87
|
+
if (!recipientToMove) return prev;
|
|
88
|
+
return {
|
|
89
|
+
recipients: [].concat(_toConsumableArray(prev.recipients), [recipientToMove]),
|
|
90
|
+
readOnlyRecipients: prev.readOnlyRecipients.filter(function (r) {
|
|
91
|
+
return (r.id || r._id) !== recipientId;
|
|
92
|
+
})
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
} else {
|
|
96
|
+
setPendingRecipients(function (prev) {
|
|
97
|
+
var recipientToMove = prev.recipients.find(function (r) {
|
|
98
|
+
return (r.id || r._id) === recipientId;
|
|
99
|
+
});
|
|
100
|
+
if (!recipientToMove) return prev;
|
|
101
|
+
return {
|
|
102
|
+
recipients: prev.recipients.filter(function (r) {
|
|
103
|
+
return (r.id || r._id) !== recipientId;
|
|
104
|
+
}),
|
|
105
|
+
readOnlyRecipients: [].concat(_toConsumableArray(prev.readOnlyRecipients), [recipientToMove])
|
|
106
|
+
};
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}; // Remove a pending recipient
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
var onRevokePending = function onRevokePending(index) {
|
|
113
|
+
var recipientId = index;
|
|
114
|
+
setPendingRecipients(function (prev) {
|
|
115
|
+
return {
|
|
116
|
+
recipients: prev.recipients.filter(function (r) {
|
|
117
|
+
return (r.id || r._id) !== recipientId;
|
|
118
|
+
}),
|
|
119
|
+
readOnlyRecipients: prev.readOnlyRecipients.filter(function (r) {
|
|
120
|
+
return (r.id || r._id) !== recipientId;
|
|
121
|
+
})
|
|
122
|
+
};
|
|
123
|
+
});
|
|
124
|
+
}; // Submit all pending recipients at once
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
var onSubmit = /*#__PURE__*/function () {
|
|
128
|
+
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
129
|
+
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
130
|
+
while (1) switch (_context.prev = _context.next) {
|
|
131
|
+
case 0:
|
|
132
|
+
if (!(pendingRecipients.recipients.length === 0 && pendingRecipients.readOnlyRecipients.length === 0)) {
|
|
133
|
+
_context.next = 2;
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return _context.abrupt("return");
|
|
138
|
+
|
|
139
|
+
case 2:
|
|
140
|
+
_context.prev = 2;
|
|
141
|
+
_context.next = 5;
|
|
142
|
+
return share({
|
|
143
|
+
document: document,
|
|
144
|
+
recipients: pendingRecipients.recipients,
|
|
145
|
+
readOnlyRecipients: pendingRecipients.readOnlyRecipients,
|
|
146
|
+
description: sharingDesc,
|
|
147
|
+
openSharing: pendingRecipients.recipients.length > 0
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
case 5:
|
|
151
|
+
showAlert({
|
|
152
|
+
message: t('Share.successNotification'),
|
|
153
|
+
severity: 'success',
|
|
154
|
+
variant: 'filled'
|
|
155
|
+
}); // Clear pending recipients after successful share
|
|
156
|
+
|
|
157
|
+
setPendingRecipients({
|
|
158
|
+
recipients: [],
|
|
159
|
+
readOnlyRecipients: []
|
|
160
|
+
});
|
|
161
|
+
_context.next = 12;
|
|
162
|
+
break;
|
|
163
|
+
|
|
164
|
+
case 9:
|
|
165
|
+
_context.prev = 9;
|
|
166
|
+
_context.t0 = _context["catch"](2);
|
|
167
|
+
showAlert({
|
|
168
|
+
message: t('Share.errorNotification'),
|
|
169
|
+
severity: 'error',
|
|
170
|
+
variant: 'filled'
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
case 12:
|
|
174
|
+
case "end":
|
|
175
|
+
return _context.stop();
|
|
176
|
+
}
|
|
177
|
+
}, _callee, null, [[2, 9]]);
|
|
178
|
+
}));
|
|
179
|
+
|
|
180
|
+
return function onSubmit() {
|
|
181
|
+
return _ref2.apply(this, arguments);
|
|
182
|
+
};
|
|
183
|
+
}(); // Combine existing and pending recipients for display
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
var allRecipients = [].concat(_toConsumableArray(existingRecipients), _toConsumableArray(pendingRecipients.recipients.map(function (r) {
|
|
187
|
+
var _Contact$getPrimaryEm;
|
|
188
|
+
|
|
189
|
+
return {
|
|
190
|
+
index: r._id || r.id,
|
|
191
|
+
email: r.email || ((_Contact$getPrimaryEm = Contact.getPrimaryEmail) === null || _Contact$getPrimaryEm === void 0 ? void 0 : _Contact$getPrimaryEm.call(Contact, r)) || r.displayName,
|
|
192
|
+
public_name: r.displayName || r.name,
|
|
193
|
+
sharingId: null,
|
|
194
|
+
memberIndex: r._id || r.id,
|
|
195
|
+
type: 'two-way',
|
|
196
|
+
isPending: true
|
|
197
|
+
};
|
|
198
|
+
})), _toConsumableArray(pendingRecipients.readOnlyRecipients.map(function (r) {
|
|
199
|
+
var _Contact$getPrimaryEm2;
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
index: r._id || r.id,
|
|
203
|
+
email: r.email || ((_Contact$getPrimaryEm2 = Contact.getPrimaryEmail) === null || _Contact$getPrimaryEm2 === void 0 ? void 0 : _Contact$getPrimaryEm2.call(Contact, r)) || r.displayName,
|
|
204
|
+
public_name: r.displayName || r.name,
|
|
205
|
+
sharingId: null,
|
|
206
|
+
memberIndex: r._id || r.id,
|
|
207
|
+
type: 'one-way',
|
|
208
|
+
isPending: true
|
|
209
|
+
};
|
|
210
|
+
})));
|
|
211
|
+
var hasPendingRecipients = pendingRecipients.recipients.length > 0 || pendingRecipients.readOnlyRecipients.length > 0; // Wrapper functions that handle both pending and existing recipients
|
|
212
|
+
|
|
213
|
+
var handleRevoke = function handleRevoke(document, sharingId, memberIndex) {
|
|
214
|
+
var recipient = allRecipients.find(function (r) {
|
|
215
|
+
return r.memberIndex === memberIndex;
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
if (recipient !== null && recipient !== void 0 && recipient.isPending) {
|
|
219
|
+
onRevokePending(memberIndex);
|
|
220
|
+
} else {
|
|
221
|
+
onRevoke(document, sharingId, memberIndex);
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
var handleSetType = function handleSetType(index, newType) {
|
|
226
|
+
var recipient = allRecipients.find(function (r) {
|
|
227
|
+
return r.index === index;
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
if (recipient !== null && recipient !== void 0 && recipient.isPending) {
|
|
231
|
+
onSetType(index, newType);
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
return /*#__PURE__*/React.createElement(ShareModal, {
|
|
236
|
+
createContact: createContact,
|
|
237
|
+
document: document,
|
|
238
|
+
documentType: documentType,
|
|
239
|
+
hasSharedChild: hasSharedChild,
|
|
240
|
+
hasSharedParent: hasSharedParent,
|
|
241
|
+
isOwner: isOwner,
|
|
242
|
+
link: link,
|
|
243
|
+
onClose: onClose,
|
|
244
|
+
onRevoke: handleRevoke,
|
|
245
|
+
onRevokeSelf: onRevokeSelf,
|
|
246
|
+
onShare: onShare,
|
|
247
|
+
onSubmit: onSubmit,
|
|
248
|
+
onSetType: handleSetType,
|
|
249
|
+
permissions: permissions,
|
|
250
|
+
recipients: allRecipients,
|
|
251
|
+
sharing: sharing,
|
|
252
|
+
sharingDesc: sharingDesc,
|
|
253
|
+
twoStepsConfirmationMethods: twoStepsConfirmationMethods,
|
|
254
|
+
batchMode: true,
|
|
255
|
+
hasPendingRecipients: hasPendingRecipients
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
ShareModalBatchContainer.propTypes = {
|
|
259
|
+
document: PropTypes.object.isRequired,
|
|
260
|
+
documentType: PropTypes.string,
|
|
261
|
+
isOwner: PropTypes.bool,
|
|
262
|
+
link: PropTypes.string,
|
|
263
|
+
permissions: PropTypes.array,
|
|
264
|
+
recipients: PropTypes.array,
|
|
265
|
+
sharing: PropTypes.object,
|
|
266
|
+
sharingDesc: PropTypes.string,
|
|
267
|
+
onClose: PropTypes.func.isRequired,
|
|
268
|
+
onRevoke: PropTypes.func.isRequired,
|
|
269
|
+
onRevokeSelf: PropTypes.func.isRequired,
|
|
270
|
+
share: PropTypes.func.isRequired,
|
|
271
|
+
createContact: PropTypes.func.isRequired,
|
|
272
|
+
hasSharedChild: PropTypes.bool,
|
|
273
|
+
hasSharedParent: PropTypes.bool,
|
|
274
|
+
twoStepsConfirmationMethods: PropTypes.object
|
|
275
|
+
};
|
|
276
|
+
export default ShareModalBatchContainer;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
+
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
3
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
4
|
+
import { render, fireEvent, waitFor, screen } from '@testing-library/react';
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import { act } from 'react-dom/test-utils';
|
|
7
|
+
import { ShareModalBatchContainer } from './ShareModalBatchContainer';
|
|
8
|
+
import AppLike from '../../../test/AppLike'; // Mock ShareModal to avoid rendering the whole sub-tree
|
|
9
|
+
|
|
10
|
+
jest.mock('../ShareModal', function () {
|
|
11
|
+
return {
|
|
12
|
+
ShareModal: function ShareModal(_ref) {
|
|
13
|
+
var onShare = _ref.onShare,
|
|
14
|
+
onSubmit = _ref.onSubmit,
|
|
15
|
+
recipients = _ref.recipients;
|
|
16
|
+
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
|
|
17
|
+
"data-testid": "recipients-count"
|
|
18
|
+
}, recipients.length), /*#__PURE__*/React.createElement("button", {
|
|
19
|
+
onClick: function onClick() {
|
|
20
|
+
return onShare({
|
|
21
|
+
recipients: [{
|
|
22
|
+
id: 'new',
|
|
23
|
+
email: 'new@cozy.cc'
|
|
24
|
+
}]
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}, "Add Recipient"), /*#__PURE__*/React.createElement("button", {
|
|
28
|
+
onClick: onSubmit
|
|
29
|
+
}, "Submit"));
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
describe('ShareModalBatchContainer', function () {
|
|
34
|
+
var defaultProps = {
|
|
35
|
+
document: {
|
|
36
|
+
_id: 'doc1',
|
|
37
|
+
name: 'Doc 1'
|
|
38
|
+
},
|
|
39
|
+
documentType: 'Files',
|
|
40
|
+
onClose: jest.fn(),
|
|
41
|
+
onRevoke: jest.fn(),
|
|
42
|
+
onRevokeSelf: jest.fn(),
|
|
43
|
+
share: jest.fn(),
|
|
44
|
+
createContact: jest.fn(),
|
|
45
|
+
recipients: []
|
|
46
|
+
};
|
|
47
|
+
beforeEach(function () {
|
|
48
|
+
jest.clearAllMocks();
|
|
49
|
+
});
|
|
50
|
+
it('should accumulate recipients and call share on submit', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
51
|
+
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
52
|
+
while (1) switch (_context.prev = _context.next) {
|
|
53
|
+
case 0:
|
|
54
|
+
render( /*#__PURE__*/React.createElement(AppLike, null, /*#__PURE__*/React.createElement(ShareModalBatchContainer, defaultProps))); // Add a recipient
|
|
55
|
+
|
|
56
|
+
act(function () {
|
|
57
|
+
fireEvent.click(screen.getByText('Add Recipient'));
|
|
58
|
+
});
|
|
59
|
+
expect(screen.getByTestId('recipients-count').textContent).toBe('1'); // Submit
|
|
60
|
+
|
|
61
|
+
act(function () {
|
|
62
|
+
fireEvent.click(screen.getByText('Submit'));
|
|
63
|
+
});
|
|
64
|
+
_context.next = 6;
|
|
65
|
+
return waitFor(function () {
|
|
66
|
+
expect(defaultProps.share).toHaveBeenCalledWith(expect.objectContaining({
|
|
67
|
+
recipients: [{
|
|
68
|
+
id: 'new',
|
|
69
|
+
email: 'new@cozy.cc'
|
|
70
|
+
}],
|
|
71
|
+
readOnlyRecipients: []
|
|
72
|
+
}));
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
case 6:
|
|
76
|
+
_context.next = 8;
|
|
77
|
+
return waitFor(function () {
|
|
78
|
+
expect(screen.getByTestId('recipients-count').textContent).toBe('0');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
case 8:
|
|
82
|
+
case "end":
|
|
83
|
+
return _context.stop();
|
|
84
|
+
}
|
|
85
|
+
}, _callee);
|
|
86
|
+
})));
|
|
87
|
+
it('should not call share if no pending recipients', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
|
|
88
|
+
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
|
|
89
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
90
|
+
case 0:
|
|
91
|
+
render( /*#__PURE__*/React.createElement(AppLike, null, /*#__PURE__*/React.createElement(ShareModalBatchContainer, defaultProps)));
|
|
92
|
+
act(function () {
|
|
93
|
+
fireEvent.click(screen.getByText('Submit'));
|
|
94
|
+
});
|
|
95
|
+
expect(defaultProps.share).not.toHaveBeenCalled();
|
|
96
|
+
|
|
97
|
+
case 3:
|
|
98
|
+
case "end":
|
|
99
|
+
return _context2.stop();
|
|
100
|
+
}
|
|
101
|
+
}, _callee2);
|
|
102
|
+
})));
|
|
103
|
+
it('should combine existing and pending recipients correctly', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
|
|
104
|
+
var existingRecipients;
|
|
105
|
+
return _regeneratorRuntime.wrap(function _callee3$(_context3) {
|
|
106
|
+
while (1) switch (_context3.prev = _context3.next) {
|
|
107
|
+
case 0:
|
|
108
|
+
existingRecipients = [{
|
|
109
|
+
index: 'old1',
|
|
110
|
+
email: 'old1@cozy.cc',
|
|
111
|
+
public_name: 'Old 1'
|
|
112
|
+
}];
|
|
113
|
+
render( /*#__PURE__*/React.createElement(AppLike, null, /*#__PURE__*/React.createElement(ShareModalBatchContainer, _extends({}, defaultProps, {
|
|
114
|
+
recipients: existingRecipients
|
|
115
|
+
})))); // Initial count should be 1 (the existing one)
|
|
116
|
+
|
|
117
|
+
expect(screen.getByTestId('recipients-count').textContent).toBe('1'); // Add a recipient
|
|
118
|
+
|
|
119
|
+
act(function () {
|
|
120
|
+
fireEvent.click(screen.getByText('Add Recipient'));
|
|
121
|
+
}); // Count should be 2
|
|
122
|
+
|
|
123
|
+
expect(screen.getByTestId('recipients-count').textContent).toBe('2');
|
|
124
|
+
|
|
125
|
+
case 5:
|
|
126
|
+
case "end":
|
|
127
|
+
return _context3.stop();
|
|
128
|
+
}
|
|
129
|
+
}, _callee3);
|
|
130
|
+
})));
|
|
131
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
+
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
|
|
3
|
+
var _excluded = ["document"];
|
|
4
|
+
import PropTypes from "prop-types";
|
|
5
|
+
import React from "react";
|
|
6
|
+
import { useClient } from "cozy-client";
|
|
7
|
+
import flag from "cozy-flags";
|
|
8
|
+
import withLocales from "../../hoc/withLocales";
|
|
9
|
+
import { useFetchDocumentPath } from "../../hooks/useFetchDocumentPath";
|
|
10
|
+
import { useSharingContext } from "../../hooks/useSharingContext";
|
|
11
|
+
import { Contact } from "../../models";
|
|
12
|
+
import { ShareModal } from "../ShareModal";
|
|
13
|
+
export var SharedDriveEditModal = withLocales(function (_ref) {
|
|
14
|
+
var document = _ref.document,
|
|
15
|
+
rest = _objectWithoutProperties(_ref, _excluded);
|
|
16
|
+
|
|
17
|
+
var client = useClient();
|
|
18
|
+
var documentPath = useFetchDocumentPath(client, document);
|
|
19
|
+
|
|
20
|
+
var _useSharingContext = useSharingContext(),
|
|
21
|
+
documentType = _useSharingContext.documentType,
|
|
22
|
+
getDocumentPermissions = _useSharingContext.getDocumentPermissions,
|
|
23
|
+
getRecipients = _useSharingContext.getRecipients,
|
|
24
|
+
getSharingForSelf = _useSharingContext.getSharingForSelf,
|
|
25
|
+
getSharingLink = _useSharingContext.getSharingLink,
|
|
26
|
+
hasSharedChild = _useSharingContext.hasSharedChild,
|
|
27
|
+
hasSharedParent = _useSharingContext.hasSharedParent,
|
|
28
|
+
isOwner = _useSharingContext.isOwner,
|
|
29
|
+
revoke = _useSharingContext.revoke,
|
|
30
|
+
revokeSelf = _useSharingContext.revokeSelf,
|
|
31
|
+
share = _useSharingContext.share; // TODO get sharing from document
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
var sharingDoc = getSharingForSelf(document._id);
|
|
35
|
+
var sharingDesc = sharingDoc.rules[0].title;
|
|
36
|
+
return /*#__PURE__*/React.createElement(ShareModal, _extends({
|
|
37
|
+
createContact: function createContact(contact) {
|
|
38
|
+
return client.create(Contact.doctype, contact);
|
|
39
|
+
},
|
|
40
|
+
document: document,
|
|
41
|
+
documentType: documentType,
|
|
42
|
+
hasSharedChild: documentPath && hasSharedChild(documentPath),
|
|
43
|
+
hasSharedParent: documentPath && hasSharedParent(documentPath),
|
|
44
|
+
isOwner: isOwner(document._id),
|
|
45
|
+
link: getSharingLink(document._id),
|
|
46
|
+
onRevoke: revoke,
|
|
47
|
+
onRevokeSelf: revokeSelf,
|
|
48
|
+
onShare: share,
|
|
49
|
+
showShareByLink: false,
|
|
50
|
+
permissions: getDocumentPermissions(document._id),
|
|
51
|
+
recipients: getRecipients(document._id),
|
|
52
|
+
sharing: getSharingForSelf(document._id),
|
|
53
|
+
sharingDesc: sharingDesc
|
|
54
|
+
}, rest));
|
|
55
|
+
});
|
|
56
|
+
SharedDriveEditModal.propTypes = {
|
|
57
|
+
document: PropTypes.object
|
|
58
|
+
};
|
|
59
|
+
export default SharedDriveEditModal;
|