cozy-sharing 40.1.9 → 40.2.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 +14 -0
- package/README.md +1 -0
- package/dist/SharingOwnerAvatar.js +2 -2
- package/dist/SharingProvider.js +3 -1
- package/dist/components/Avatar/AvatarList.js +2 -2
- package/dist/components/Avatar/MemberAvatar.js +8 -33
- package/dist/components/Avatar/MemberAvatar.spec.js +17 -77
- package/dist/components/Avatar/MemberAvatarWrapper.js +20 -0
- package/dist/components/ConfirmTrustedRecipientsDialog.js +5 -1
- package/dist/components/ContactSuggestion.js +5 -2
- package/dist/components/Recipient/MemberRecipient.js +6 -3
- package/dist/components/Recipient/MemberRecipient.spec.js +1 -9
- package/dist/components/Recipient/MemberRecipientLite.js +2 -2
- package/dist/components/Recipient/PermissionTypeMenuWrapper.spec.js +3 -1
- package/dist/components/ShareAutosuggest.js +93 -16
- package/dist/components/ShareAutosuggest.spec.js +126 -3
- package/dist/components/ShareAutosuggest.stories.js +3 -0
- package/dist/components/ShareAutosuggestWrapper.js +65 -5
- package/dist/components/ShareAutosuggestWrapper.spec.js +113 -11
- package/dist/components/WhoHasAccessWrapper.js +6 -2
- package/dist/helpers/contacts.js +75 -16
- package/dist/helpers/contacts.spec.js +150 -1
- package/dist/helpers/recipients.js +38 -0
- package/dist/helpers/recipients.spec.js +53 -1
- package/dist/hooks/useResolveRecipients.js +6 -2
- package/dist/hooks/useResolveRecipients.spec.js +11 -2
- package/dist/index.js +1 -1
- package/dist/queries/queries.js +16 -3
- package/package.json +3 -3
- package/src/SharingOwnerAvatar.jsx +2 -2
- package/src/SharingProvider.jsx +6 -1
- package/src/components/Avatar/AvatarList.jsx +2 -2
- package/src/components/Avatar/MemberAvatar.jsx +4 -34
- package/src/components/Avatar/MemberAvatar.spec.jsx +13 -73
- package/src/components/Avatar/MemberAvatarWrapper.jsx +22 -0
- package/src/components/ConfirmTrustedRecipientsDialog.jsx +7 -0
- package/src/components/ContactSuggestion.jsx +8 -3
- package/src/components/Recipient/MemberRecipient.jsx +4 -2
- package/src/components/Recipient/MemberRecipient.spec.jsx +1 -8
- package/src/components/Recipient/MemberRecipientLite.jsx +2 -2
- package/src/components/Recipient/PermissionTypeMenuWrapper.spec.jsx +3 -1
- package/src/components/ShareAutosuggest.jsx +56 -9
- package/src/components/ShareAutosuggest.spec.jsx +60 -2
- package/src/components/ShareAutosuggest.stories.jsx +1 -0
- package/src/components/ShareAutosuggestWrapper.jsx +36 -4
- package/src/components/ShareAutosuggestWrapper.spec.jsx +78 -5
- package/src/components/WhoHasAccessWrapper.jsx +14 -2
- package/src/helpers/contacts.js +31 -1
- package/src/helpers/contacts.spec.js +102 -1
- package/src/helpers/recipients.js +40 -0
- package/src/helpers/recipients.spec.js +83 -1
- package/src/hooks/useResolveRecipients.js +5 -2
- package/src/hooks/useResolveRecipients.spec.js +8 -2
- package/src/index.jsx +1 -1
- package/src/queries/queries.js +6 -3
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
2
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
3
|
+
import { act, render, fireEvent, screen } from '@testing-library/react';
|
|
2
4
|
import React from 'react';
|
|
3
5
|
import ShareAutosuggest from './ShareAutosuggest';
|
|
4
6
|
import AppLike from '../../test/AppLike';
|
|
@@ -16,7 +18,8 @@ describe('ShareAutosuggest', function () {
|
|
|
16
18
|
_ref$loading = _ref.loading,
|
|
17
19
|
loading = _ref$loading === void 0 ? false : _ref$loading,
|
|
18
20
|
_ref$enableCreateCont = _ref.enableCreateContact,
|
|
19
|
-
enableCreateContact = _ref$enableCreateCont === void 0 ? true : _ref$enableCreateCont
|
|
21
|
+
enableCreateContact = _ref$enableCreateCont === void 0 ? true : _ref$enableCreateCont,
|
|
22
|
+
fetchContacts = _ref.fetchContacts;
|
|
20
23
|
render( /*#__PURE__*/React.createElement(AppLike, null, /*#__PURE__*/React.createElement(ShareAutosuggest, {
|
|
21
24
|
loading: loading,
|
|
22
25
|
contactsAndGroups: [],
|
|
@@ -24,7 +27,11 @@ describe('ShareAutosuggest', function () {
|
|
|
24
27
|
onPick: onPick,
|
|
25
28
|
recipients: [],
|
|
26
29
|
onRemove: onRemove,
|
|
27
|
-
enableCreateContact: enableCreateContact
|
|
30
|
+
enableCreateContact: enableCreateContact,
|
|
31
|
+
fetchContacts: fetchContacts,
|
|
32
|
+
getAvatarUrl: function getAvatarUrl() {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
28
35
|
})));
|
|
29
36
|
};
|
|
30
37
|
|
|
@@ -123,4 +130,120 @@ describe('ShareAutosuggest', function () {
|
|
|
123
130
|
});
|
|
124
131
|
expect(screen.queryByText('loading')).toBeNull();
|
|
125
132
|
});
|
|
133
|
+
describe('with fetchContacts', function () {
|
|
134
|
+
beforeEach(function () {
|
|
135
|
+
jest.useFakeTimers(); // Not implemented by jsdom, called when a suggestion is highlighted
|
|
136
|
+
|
|
137
|
+
Element.prototype.scrollIntoView = jest.fn();
|
|
138
|
+
});
|
|
139
|
+
afterEach(function () {
|
|
140
|
+
jest.useRealTimers();
|
|
141
|
+
});
|
|
142
|
+
it('should suggest the fetched contacts, debounced and from 3 characters', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
143
|
+
var fetchContacts, inputNode;
|
|
144
|
+
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
145
|
+
while (1) switch (_context.prev = _context.next) {
|
|
146
|
+
case 0:
|
|
147
|
+
fetchContacts = jest.fn().mockResolvedValue([{
|
|
148
|
+
_id: 'org-member-1',
|
|
149
|
+
_type: 'io.cozy.contacts',
|
|
150
|
+
displayName: 'Jean Dupont',
|
|
151
|
+
email: [{
|
|
152
|
+
address: 'jean@org.example',
|
|
153
|
+
primary: true
|
|
154
|
+
}]
|
|
155
|
+
}]);
|
|
156
|
+
setup({
|
|
157
|
+
onPick: jest.fn(),
|
|
158
|
+
onRemove: jest.fn(),
|
|
159
|
+
fetchContacts: fetchContacts
|
|
160
|
+
});
|
|
161
|
+
inputNode = screen.getByPlaceholderText('myPlaceHolder');
|
|
162
|
+
fireEvent.change(inputNode, {
|
|
163
|
+
target: {
|
|
164
|
+
value: 'du'
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
act(function () {
|
|
168
|
+
return jest.runAllTimers();
|
|
169
|
+
});
|
|
170
|
+
expect(fetchContacts).not.toHaveBeenCalled();
|
|
171
|
+
fireEvent.change(inputNode, {
|
|
172
|
+
target: {
|
|
173
|
+
value: 'dup'
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
fireEvent.change(inputNode, {
|
|
177
|
+
target: {
|
|
178
|
+
value: 'dupo'
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
act(function () {
|
|
182
|
+
return jest.runAllTimers();
|
|
183
|
+
});
|
|
184
|
+
expect(fetchContacts).toHaveBeenCalledTimes(1);
|
|
185
|
+
expect(fetchContacts).toHaveBeenCalledWith('dupo');
|
|
186
|
+
_context.t0 = expect;
|
|
187
|
+
_context.next = 14;
|
|
188
|
+
return screen.findByText('Jean Dupont');
|
|
189
|
+
|
|
190
|
+
case 14:
|
|
191
|
+
_context.t1 = _context.sent;
|
|
192
|
+
(0, _context.t0)(_context.t1).toBeInTheDocument();
|
|
193
|
+
|
|
194
|
+
case 16:
|
|
195
|
+
case "end":
|
|
196
|
+
return _context.stop();
|
|
197
|
+
}
|
|
198
|
+
}, _callee);
|
|
199
|
+
})));
|
|
200
|
+
it('should show the loading indicator until the contacts are fetched', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
|
|
201
|
+
var resolveFetch, fetchContacts, inputNode;
|
|
202
|
+
return _regeneratorRuntime.wrap(function _callee3$(_context3) {
|
|
203
|
+
while (1) switch (_context3.prev = _context3.next) {
|
|
204
|
+
case 0:
|
|
205
|
+
fetchContacts = jest.fn(function () {
|
|
206
|
+
return new Promise(function (resolve) {
|
|
207
|
+
return resolveFetch = resolve;
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
setup({
|
|
211
|
+
onPick: jest.fn(),
|
|
212
|
+
onRemove: jest.fn(),
|
|
213
|
+
fetchContacts: fetchContacts
|
|
214
|
+
});
|
|
215
|
+
inputNode = screen.getByPlaceholderText('myPlaceHolder');
|
|
216
|
+
fireEvent.change(inputNode, {
|
|
217
|
+
target: {
|
|
218
|
+
value: 'dup'
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
expect(screen.getByText('loading')).toBeInTheDocument();
|
|
222
|
+
act(function () {
|
|
223
|
+
return jest.runAllTimers();
|
|
224
|
+
});
|
|
225
|
+
_context3.next = 8;
|
|
226
|
+
return act( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
|
|
227
|
+
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
|
|
228
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
229
|
+
case 0:
|
|
230
|
+
return _context2.abrupt("return", resolveFetch([]));
|
|
231
|
+
|
|
232
|
+
case 1:
|
|
233
|
+
case "end":
|
|
234
|
+
return _context2.stop();
|
|
235
|
+
}
|
|
236
|
+
}, _callee2);
|
|
237
|
+
})));
|
|
238
|
+
|
|
239
|
+
case 8:
|
|
240
|
+
expect(screen.queryByText('loading')).toBeNull();
|
|
241
|
+
|
|
242
|
+
case 9:
|
|
243
|
+
case "end":
|
|
244
|
+
return _context3.stop();
|
|
245
|
+
}
|
|
246
|
+
}, _callee3);
|
|
247
|
+
})));
|
|
248
|
+
});
|
|
126
249
|
});
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
1
2
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
3
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
2
4
|
|
|
3
5
|
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
4
6
|
|
|
@@ -6,18 +8,26 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
|
|
|
6
8
|
|
|
7
9
|
import PropTypes from 'prop-types';
|
|
8
10
|
import React from 'react';
|
|
9
|
-
import { useQueryAll, isQueryLoading } from 'cozy-client';
|
|
11
|
+
import { useClient, useQueryAll, isQueryLoading } from 'cozy-client';
|
|
12
|
+
import { models } from 'cozy-client';
|
|
10
13
|
import flag from 'cozy-flags';
|
|
11
14
|
import ShareAutosuggest from './ShareAutosuggest';
|
|
12
|
-
import { computeContactsAndGroups } from '../helpers/contacts';
|
|
15
|
+
import { computeContactsAndGroups, suggestContacts } from '../helpers/contacts';
|
|
16
|
+
import { makeAvatarUrl } from '../helpers/recipients';
|
|
17
|
+
import { useSharingContext } from '../hooks/useSharingContext';
|
|
18
|
+
import { DOCTYPE_GROUPS } from '../models';
|
|
13
19
|
import { buildReachableContactsQuery, buildContactGroupsQuery, buildUnreachableContactsWithGroupsQuery } from '../queries/queries';
|
|
20
|
+
var ContactModel = models.contact;
|
|
14
21
|
/**
|
|
15
22
|
* ShareAutosuggestWrapper is responsible for fetching contacts and groups.
|
|
16
23
|
* We retrieve all the contacts that are reachable and the groups they belong to.
|
|
17
24
|
* In order to display the total number of members in each group, we also retrieve the contacts that are not reachable.
|
|
25
|
+
* With contactsSuggestEnabled, the stack suggests the contacts and we only retrieve the group members.
|
|
18
26
|
*/
|
|
19
27
|
|
|
20
28
|
var ShareAutosuggestWrapper = function ShareAutosuggestWrapper(_ref) {
|
|
29
|
+
var _useSharingContext;
|
|
30
|
+
|
|
21
31
|
var currentRecipients = _ref.currentRecipients,
|
|
22
32
|
recipients = _ref.recipients,
|
|
23
33
|
placeholder = _ref.placeholder,
|
|
@@ -27,7 +37,11 @@ var ShareAutosuggestWrapper = function ShareAutosuggestWrapper(_ref) {
|
|
|
27
37
|
disabled = _ref.disabled,
|
|
28
38
|
autoFocus = _ref.autoFocus,
|
|
29
39
|
endAdornment = _ref.endAdornment;
|
|
30
|
-
var
|
|
40
|
+
var client = useClient();
|
|
41
|
+
var contactsSuggestEnabled = (_useSharingContext = useSharingContext()) === null || _useSharingContext === void 0 ? void 0 : _useSharingContext.contactsSuggestEnabled;
|
|
42
|
+
var reachableContactsQuery = buildReachableContactsQuery({
|
|
43
|
+
inGroups: contactsSuggestEnabled
|
|
44
|
+
});
|
|
31
45
|
var reachableContactsResult = useQueryAll(reachableContactsQuery.definition, reachableContactsQuery.options);
|
|
32
46
|
var unreachableContactsWithGroupsQuery = buildUnreachableContactsWithGroupsQuery();
|
|
33
47
|
var unreachableContactsWithGroupsResult = useQueryAll(unreachableContactsWithGroupsQuery.definition, _objectSpread(_objectSpread({}, unreachableContactsWithGroupsQuery.options), {}, {
|
|
@@ -36,13 +50,55 @@ var ShareAutosuggestWrapper = function ShareAutosuggestWrapper(_ref) {
|
|
|
36
50
|
var contactGroupsQuery = buildContactGroupsQuery();
|
|
37
51
|
var contactGroupsResult = useQueryAll(contactGroupsQuery.definition, contactGroupsQuery.options);
|
|
38
52
|
var isLoading = isQueryLoading(reachableContactsResult) || reachableContactsResult.hasMore || isQueryLoading(contactGroupsResult) || contactGroupsResult.hasMore || flag('sharing.show-recipient-groups') && (isQueryLoading(unreachableContactsWithGroupsResult) || unreachableContactsWithGroupsResult.hasMore);
|
|
39
|
-
var
|
|
53
|
+
var suggestedContactsAndGroups = computeContactsAndGroups({
|
|
40
54
|
reachableContacts: reachableContactsResult.data || [],
|
|
41
55
|
unreachableContactsWithGroups: unreachableContactsWithGroupsResult.data || [],
|
|
42
56
|
contactGroups: contactGroupsResult.data || [],
|
|
43
57
|
currentRecipients: currentRecipients,
|
|
44
58
|
pendingRecipients: recipients
|
|
45
59
|
});
|
|
60
|
+
var contactsAndGroups = contactsSuggestEnabled ? suggestedContactsAndGroups.filter(function (_ref2) {
|
|
61
|
+
var _type = _ref2._type;
|
|
62
|
+
return _type === DOCTYPE_GROUPS;
|
|
63
|
+
}) : suggestedContactsAndGroups; // The stack matches the emails whatever their case
|
|
64
|
+
|
|
65
|
+
var normalizeEmail = function normalizeEmail(email) {
|
|
66
|
+
return email === null || email === void 0 ? void 0 : email.trim().toLowerCase();
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
var isRecipient = function isRecipient(email) {
|
|
70
|
+
return currentRecipients.some(function (r) {
|
|
71
|
+
return normalizeEmail(r.email) === email;
|
|
72
|
+
}) || recipients.some(function (r) {
|
|
73
|
+
return normalizeEmail(ContactModel.getPrimaryEmail(r)) === email;
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
var fetchContacts = /*#__PURE__*/function () {
|
|
78
|
+
var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(q) {
|
|
79
|
+
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
80
|
+
while (1) switch (_context.prev = _context.next) {
|
|
81
|
+
case 0:
|
|
82
|
+
_context.next = 2;
|
|
83
|
+
return suggestContacts(client, q);
|
|
84
|
+
|
|
85
|
+
case 2:
|
|
86
|
+
return _context.abrupt("return", _context.sent.filter(function (contact) {
|
|
87
|
+
return !isRecipient(normalizeEmail(ContactModel.getPrimaryEmail(contact)));
|
|
88
|
+
}));
|
|
89
|
+
|
|
90
|
+
case 3:
|
|
91
|
+
case "end":
|
|
92
|
+
return _context.stop();
|
|
93
|
+
}
|
|
94
|
+
}, _callee);
|
|
95
|
+
}));
|
|
96
|
+
|
|
97
|
+
return function fetchContacts(_x) {
|
|
98
|
+
return _ref3.apply(this, arguments);
|
|
99
|
+
};
|
|
100
|
+
}();
|
|
101
|
+
|
|
46
102
|
return /*#__PURE__*/React.createElement(ShareAutosuggest, {
|
|
47
103
|
loading: isLoading,
|
|
48
104
|
disabled: disabled,
|
|
@@ -53,7 +109,11 @@ var ShareAutosuggestWrapper = function ShareAutosuggestWrapper(_ref) {
|
|
|
53
109
|
enableCreateContact: enableCreateContact,
|
|
54
110
|
placeholder: placeholder,
|
|
55
111
|
autoFocus: autoFocus,
|
|
56
|
-
endAdornment: endAdornment
|
|
112
|
+
endAdornment: endAdornment,
|
|
113
|
+
fetchContacts: contactsSuggestEnabled ? fetchContacts : undefined,
|
|
114
|
+
getAvatarUrl: function getAvatarUrl(recipient) {
|
|
115
|
+
return makeAvatarUrl(recipient, client.options.uri);
|
|
116
|
+
}
|
|
57
117
|
});
|
|
58
118
|
};
|
|
59
119
|
|
|
@@ -14,11 +14,13 @@ jest.mock('cozy-flags', function () {
|
|
|
14
14
|
})
|
|
15
15
|
};
|
|
16
16
|
});
|
|
17
|
+
var mockAutosuggestProps;
|
|
17
18
|
jest.mock('./ShareAutosuggest', function () {
|
|
18
19
|
return {
|
|
19
20
|
__esModule: true,
|
|
20
|
-
default: function _default(
|
|
21
|
-
|
|
21
|
+
default: function _default(props) {
|
|
22
|
+
mockAutosuggestProps = props;
|
|
23
|
+
var contactsAndGroups = props.contactsAndGroups;
|
|
22
24
|
return /*#__PURE__*/React.createElement("ul", null, contactsAndGroups.map(function (contactOrGroup) {
|
|
23
25
|
if (contactOrGroup._type === 'io.cozy.contacts') {
|
|
24
26
|
return /*#__PURE__*/React.createElement("li", {
|
|
@@ -34,14 +36,16 @@ jest.mock('./ShareAutosuggest', function () {
|
|
|
34
36
|
};
|
|
35
37
|
});
|
|
36
38
|
describe('ShareAutosuggestWrapper component', function () {
|
|
37
|
-
var setup = function setup(
|
|
38
|
-
var contacts =
|
|
39
|
-
contactGroups =
|
|
40
|
-
unreachableContact =
|
|
39
|
+
var setup = function setup(_ref) {
|
|
40
|
+
var contacts = _ref.contacts,
|
|
41
|
+
contactGroups = _ref.contactGroups,
|
|
42
|
+
unreachableContact = _ref.unreachableContact,
|
|
43
|
+
groupMembers = _ref.groupMembers;
|
|
41
44
|
|
|
42
|
-
var
|
|
43
|
-
currentRecipients =
|
|
44
|
-
recipients =
|
|
45
|
+
var _ref2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
|
|
46
|
+
currentRecipients = _ref2.currentRecipients,
|
|
47
|
+
recipients = _ref2.recipients,
|
|
48
|
+
contactsSuggestEnabled = _ref2.contactsSuggestEnabled;
|
|
45
49
|
|
|
46
50
|
var mockClient = createMockClient({
|
|
47
51
|
queries: {
|
|
@@ -56,11 +60,18 @@ describe('ShareAutosuggestWrapper component', function () {
|
|
|
56
60
|
'io.cozy.contacts/unreachable-with-groups': {
|
|
57
61
|
doctype: 'io.cozy.contacts',
|
|
58
62
|
data: unreachableContact
|
|
63
|
+
},
|
|
64
|
+
'io.cozy.contacts/reachable-with-groups': {
|
|
65
|
+
doctype: 'io.cozy.contacts',
|
|
66
|
+
data: groupMembers
|
|
59
67
|
}
|
|
60
68
|
}
|
|
61
69
|
});
|
|
62
70
|
render( /*#__PURE__*/React.createElement(AppLike, {
|
|
63
|
-
client: mockClient
|
|
71
|
+
client: mockClient,
|
|
72
|
+
sharingContextValue: {
|
|
73
|
+
contactsSuggestEnabled: contactsSuggestEnabled
|
|
74
|
+
}
|
|
64
75
|
}, /*#__PURE__*/React.createElement(ShareAutosuggestWrapper, {
|
|
65
76
|
onPick: function onPick() {},
|
|
66
77
|
onRemove: function onRemove() {},
|
|
@@ -68,6 +79,7 @@ describe('ShareAutosuggestWrapper component', function () {
|
|
|
68
79
|
currentRecipients: currentRecipients,
|
|
69
80
|
recipients: recipients
|
|
70
81
|
})));
|
|
82
|
+
return mockClient;
|
|
71
83
|
};
|
|
72
84
|
|
|
73
85
|
it('should include groups and contacts when are loaded', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
@@ -240,7 +252,9 @@ describe('ShareAutosuggestWrapper component', function () {
|
|
|
240
252
|
return _regeneratorRuntime.wrap(function _callee4$(_context4) {
|
|
241
253
|
while (1) switch (_context4.prev = _context4.next) {
|
|
242
254
|
case 0:
|
|
243
|
-
flag.
|
|
255
|
+
flag.mockImplementation(function (name) {
|
|
256
|
+
return name === 'sharing.show-recipient-groups';
|
|
257
|
+
});
|
|
244
258
|
contacts = [{
|
|
245
259
|
id: 'df563cc4-6440',
|
|
246
260
|
_id: 'df563cc4-6440',
|
|
@@ -307,4 +321,92 @@ describe('ShareAutosuggestWrapper component', function () {
|
|
|
307
321
|
}
|
|
308
322
|
}, _callee4);
|
|
309
323
|
})));
|
|
324
|
+
describe('with contactsSuggestEnabled', function () {
|
|
325
|
+
beforeEach(function () {
|
|
326
|
+
flag.mockReset();
|
|
327
|
+
});
|
|
328
|
+
it('should suggest only groups, with the count of their members', function () {
|
|
329
|
+
var groupMembers = [{
|
|
330
|
+
id: '5a3b4ccf-c257',
|
|
331
|
+
_id: '5a3b4ccf-c257',
|
|
332
|
+
_type: 'io.cozy.contacts',
|
|
333
|
+
name: {
|
|
334
|
+
givenName: 'Teagan',
|
|
335
|
+
familyName: 'Wolf'
|
|
336
|
+
},
|
|
337
|
+
relationships: {
|
|
338
|
+
groups: {
|
|
339
|
+
data: [{
|
|
340
|
+
_id: 'fe86af20-c6c5',
|
|
341
|
+
_type: 'io.cozy.contacts.groups'
|
|
342
|
+
}]
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}];
|
|
346
|
+
var contactGroups = [{
|
|
347
|
+
id: 'fe86af20-c6c5',
|
|
348
|
+
_id: 'fe86af20-c6c5',
|
|
349
|
+
_type: 'io.cozy.contacts.groups',
|
|
350
|
+
name: 'Friends'
|
|
351
|
+
}];
|
|
352
|
+
setup({
|
|
353
|
+
contactGroups: contactGroups,
|
|
354
|
+
groupMembers: groupMembers
|
|
355
|
+
}, {
|
|
356
|
+
contactsSuggestEnabled: true
|
|
357
|
+
});
|
|
358
|
+
expect(screen.getByText('Friends - 1 members')).toBeInTheDocument();
|
|
359
|
+
expect(screen.queryByText('Teagan Wolf')).not.toBeInTheDocument();
|
|
360
|
+
});
|
|
361
|
+
it('should fetch suggestions without the current and pending recipients, whatever the case of their email', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee5() {
|
|
362
|
+
var suggestion, mockClient, fetchJSON, contacts;
|
|
363
|
+
return _regeneratorRuntime.wrap(function _callee5$(_context5) {
|
|
364
|
+
while (1) switch (_context5.prev = _context5.next) {
|
|
365
|
+
case 0:
|
|
366
|
+
suggestion = function suggestion(email) {
|
|
367
|
+
return {
|
|
368
|
+
type: 'io.cozy.contacts',
|
|
369
|
+
attributes: {
|
|
370
|
+
fullname: email,
|
|
371
|
+
email: [{
|
|
372
|
+
address: email
|
|
373
|
+
}]
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
mockClient = setup({
|
|
379
|
+
contactGroups: [],
|
|
380
|
+
groupMembers: []
|
|
381
|
+
}, {
|
|
382
|
+
currentRecipients: [{
|
|
383
|
+
email: 'Current@Cozy.cc'
|
|
384
|
+
}],
|
|
385
|
+
recipients: [{
|
|
386
|
+
email: 'pending@cozy.cc'
|
|
387
|
+
}],
|
|
388
|
+
contactsSuggestEnabled: true
|
|
389
|
+
});
|
|
390
|
+
fetchJSON = jest.fn().mockResolvedValue({
|
|
391
|
+
data: [suggestion('current@cozy.cc'), suggestion('PENDING@cozy.cc'), suggestion('new@cozy.cc')]
|
|
392
|
+
});
|
|
393
|
+
jest.spyOn(mockClient, 'getStackClient').mockReturnValue({
|
|
394
|
+
fetchJSON: fetchJSON
|
|
395
|
+
});
|
|
396
|
+
_context5.next = 6;
|
|
397
|
+
return mockAutosuggestProps.fetchContacts('coz');
|
|
398
|
+
|
|
399
|
+
case 6:
|
|
400
|
+
contacts = _context5.sent;
|
|
401
|
+
expect(contacts.map(function (c) {
|
|
402
|
+
return c.fullname;
|
|
403
|
+
})).toEqual(['new@cozy.cc']);
|
|
404
|
+
|
|
405
|
+
case 8:
|
|
406
|
+
case "end":
|
|
407
|
+
return _context5.stop();
|
|
408
|
+
}
|
|
409
|
+
}, _callee5);
|
|
410
|
+
})));
|
|
411
|
+
});
|
|
310
412
|
});
|
|
@@ -7,7 +7,7 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
|
|
|
7
7
|
import React from 'react';
|
|
8
8
|
import { useClient, useQuery, hasQueryBeenLoaded } from 'cozy-client';
|
|
9
9
|
import WhoHasAccess from './WhoHasAccess';
|
|
10
|
-
import { hasMemberActions, markCurrentUser } from '../helpers/recipients';
|
|
10
|
+
import { addAvatarUrls, hasMemberActions, makeAvatarUrl, markCurrentUser } from '../helpers/recipients';
|
|
11
11
|
import { useMemberPermissionType } from '../hooks/useMemberPermissionType';
|
|
12
12
|
import { useSharingContext } from '../hooks/useSharingContext';
|
|
13
13
|
import { buildInstanceSettingsQuery } from '../queries/queries'; // When the owner is not part of a sharing's members (eg. the folder only has
|
|
@@ -53,7 +53,7 @@ var WhoHasAccessWrapper = function WhoHasAccessWrapper(_ref) {
|
|
|
53
53
|
revokeSelf = _useSharingContext.revokeSelf;
|
|
54
54
|
|
|
55
55
|
var instanceUri = client.options.uri;
|
|
56
|
-
var markedRecipients = markCurrentUser(recipients, instanceUri);
|
|
56
|
+
var markedRecipients = addAvatarUrls(markCurrentUser(recipients, instanceUri), instanceUri);
|
|
57
57
|
var hasMemberMenus = markedRecipients.some(function (recipient) {
|
|
58
58
|
return !recipient.members && !recipientsToBeConfirmed.some(function (user) {
|
|
59
59
|
return user.email === recipient.email;
|
|
@@ -85,6 +85,10 @@ var WhoHasAccessWrapper = function WhoHasAccessWrapper(_ref) {
|
|
|
85
85
|
status: 'owner',
|
|
86
86
|
instance: instanceUri,
|
|
87
87
|
avatarPath: OWNER_PUBLIC_AVATAR_PATH,
|
|
88
|
+
avatarUrl: makeAvatarUrl({
|
|
89
|
+
status: 'owner',
|
|
90
|
+
avatarPath: OWNER_PUBLIC_AVATAR_PATH
|
|
91
|
+
}, instanceUri),
|
|
88
92
|
public_name: (_instanceSettingsResu = instanceSettingsResult.data) === null || _instanceSettingsResu === void 0 || (_instanceSettingsResu = _instanceSettingsResu.attributes) === null || _instanceSettingsResu === void 0 ? void 0 : _instanceSettingsResu.public_name
|
|
89
93
|
} : null;
|
|
90
94
|
var owner = ownerRecipient ? _objectSpread(_objectSpread({}, ownerRecipient), {}, {
|
package/dist/helpers/contacts.js
CHANGED
|
@@ -10,16 +10,35 @@ import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
|
10
10
|
import { models } from 'cozy-client';
|
|
11
11
|
import flag from 'cozy-flags';
|
|
12
12
|
import { validateEmail } from '../helpers/email';
|
|
13
|
+
import { DOCTYPE_CONTACTS, DOCTYPE_GROUPS } from '../models';
|
|
13
14
|
var ContactModel = models.contact; // Return the contact object if present
|
|
14
15
|
// Else check if a contact exist with this email address, if yes return it
|
|
15
16
|
// if not create it
|
|
17
|
+
// With contactsSuggestEnabled, people are sent by email and the
|
|
18
|
+
// stack finds or creates the contact: an org member's id is not on this instance
|
|
16
19
|
|
|
17
20
|
export var getOrCreateFromArray = /*#__PURE__*/function () {
|
|
18
|
-
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(client, contacts, createContact) {
|
|
21
|
+
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(client, contacts, createContact, contactsSuggestEnabled) {
|
|
19
22
|
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
|
|
20
23
|
while (1) switch (_context2.prev = _context2.next) {
|
|
21
24
|
case 0:
|
|
22
|
-
|
|
25
|
+
if (!contactsSuggestEnabled) {
|
|
26
|
+
_context2.next = 2;
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return _context2.abrupt("return", contacts.map(function (contact) {
|
|
31
|
+
if (contact._type === DOCTYPE_GROUPS) return contact;
|
|
32
|
+
var email = ContactModel.getPrimaryEmail(contact);
|
|
33
|
+
if (validateEmail(email)) return {
|
|
34
|
+
_type: DOCTYPE_CONTACTS,
|
|
35
|
+
email: email
|
|
36
|
+
};
|
|
37
|
+
return contact._id ? contact : undefined;
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
case 2:
|
|
41
|
+
_context2.next = 4;
|
|
23
42
|
return Promise.all(contacts.map( /*#__PURE__*/function () {
|
|
24
43
|
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(contact) {
|
|
25
44
|
var matchedContact, resp;
|
|
@@ -83,24 +102,64 @@ export var getOrCreateFromArray = /*#__PURE__*/function () {
|
|
|
83
102
|
}, _callee);
|
|
84
103
|
}));
|
|
85
104
|
|
|
86
|
-
return function (
|
|
105
|
+
return function (_x5) {
|
|
87
106
|
return _ref2.apply(this, arguments);
|
|
88
107
|
};
|
|
89
108
|
}()));
|
|
90
109
|
|
|
91
|
-
case
|
|
110
|
+
case 4:
|
|
92
111
|
return _context2.abrupt("return", _context2.sent);
|
|
93
112
|
|
|
94
|
-
case
|
|
113
|
+
case 5:
|
|
95
114
|
case "end":
|
|
96
115
|
return _context2.stop();
|
|
97
116
|
}
|
|
98
117
|
}, _callee2);
|
|
99
118
|
}));
|
|
100
119
|
|
|
101
|
-
return function getOrCreateFromArray(_x, _x2, _x3) {
|
|
120
|
+
return function getOrCreateFromArray(_x, _x2, _x3, _x4) {
|
|
102
121
|
return _ref.apply(this, arguments);
|
|
103
122
|
};
|
|
123
|
+
}(); // A suggestion without id has no contact document, and only a fullname,
|
|
124
|
+
// which getDisplayName does not read
|
|
125
|
+
|
|
126
|
+
export var suggestContacts = /*#__PURE__*/function () {
|
|
127
|
+
var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(client, q) {
|
|
128
|
+
var _yield$client$getStac, data;
|
|
129
|
+
|
|
130
|
+
return _regeneratorRuntime.wrap(function _callee3$(_context3) {
|
|
131
|
+
while (1) switch (_context3.prev = _context3.next) {
|
|
132
|
+
case 0:
|
|
133
|
+
_context3.next = 2;
|
|
134
|
+
return client.getStackClient().fetchJSON('GET', "/contacts/suggest?q=".concat(encodeURIComponent(q)));
|
|
135
|
+
|
|
136
|
+
case 2:
|
|
137
|
+
_yield$client$getStac = _context3.sent;
|
|
138
|
+
data = _yield$client$getStac.data;
|
|
139
|
+
return _context3.abrupt("return", data.map(function (_ref4) {
|
|
140
|
+
var id = _ref4.id,
|
|
141
|
+
type = _ref4.type,
|
|
142
|
+
attributes = _ref4.attributes;
|
|
143
|
+
return _objectSpread(_objectSpread(_objectSpread({}, attributes), id ? {
|
|
144
|
+
_id: id,
|
|
145
|
+
id: id
|
|
146
|
+
} : {
|
|
147
|
+
displayName: attributes.fullname
|
|
148
|
+
}), {}, {
|
|
149
|
+
_type: type
|
|
150
|
+
});
|
|
151
|
+
}));
|
|
152
|
+
|
|
153
|
+
case 5:
|
|
154
|
+
case "end":
|
|
155
|
+
return _context3.stop();
|
|
156
|
+
}
|
|
157
|
+
}, _callee3);
|
|
158
|
+
}));
|
|
159
|
+
|
|
160
|
+
return function suggestContacts(_x6, _x7) {
|
|
161
|
+
return _ref3.apply(this, arguments);
|
|
162
|
+
};
|
|
104
163
|
}();
|
|
105
164
|
export var getContactsFromGroupId = function getContactsFromGroupId() {
|
|
106
165
|
var contacts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
@@ -144,12 +203,12 @@ var isCurrentUser = function isCurrentUser(contact) {
|
|
|
144
203
|
*/
|
|
145
204
|
|
|
146
205
|
|
|
147
|
-
export var computeContactsAndGroups = function computeContactsAndGroups(
|
|
148
|
-
var reachableContacts =
|
|
149
|
-
unreachableContactsWithGroups =
|
|
150
|
-
contactGroups =
|
|
151
|
-
currentRecipients =
|
|
152
|
-
pendingRecipients =
|
|
206
|
+
export var computeContactsAndGroups = function computeContactsAndGroups(_ref5) {
|
|
207
|
+
var reachableContacts = _ref5.reachableContacts,
|
|
208
|
+
unreachableContactsWithGroups = _ref5.unreachableContactsWithGroups,
|
|
209
|
+
contactGroups = _ref5.contactGroups,
|
|
210
|
+
currentRecipients = _ref5.currentRecipients,
|
|
211
|
+
pendingRecipients = _ref5.pendingRecipients;
|
|
153
212
|
var suggestedContacts = reachableContacts.filter(function (contact) {
|
|
154
213
|
return !isCurrentUser(contact) && // We do not want contact already in the sharing
|
|
155
214
|
!currentRecipients.find(function (r) {
|
|
@@ -162,12 +221,12 @@ export var computeContactsAndGroups = function computeContactsAndGroups(_ref3) {
|
|
|
162
221
|
var unreachableContacts = unreachableContactsWithGroups.filter(function (contact) {
|
|
163
222
|
return !isCurrentUser(contact);
|
|
164
223
|
});
|
|
165
|
-
var currentRecipientGroups = currentRecipients.map(function (
|
|
166
|
-
var id =
|
|
224
|
+
var currentRecipientGroups = currentRecipients.map(function (_ref6) {
|
|
225
|
+
var id = _ref6.id;
|
|
167
226
|
return id;
|
|
168
227
|
}).filter(Boolean);
|
|
169
|
-
var suggestedGroups = contactGroups.filter(function (
|
|
170
|
-
var _id =
|
|
228
|
+
var suggestedGroups = contactGroups.filter(function (_ref7) {
|
|
229
|
+
var _id = _ref7._id;
|
|
171
230
|
return !flag('sharing.show-recipient-groups') || !currentRecipientGroups.includes(_id);
|
|
172
231
|
}).map(function (contactGroup) {
|
|
173
232
|
var reachableMembers = getContactsFromGroupId(suggestedContacts, contactGroup.id).map(function (contact) {
|