cozy-sharing 33.0.1 → 33.0.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 +6 -0
- package/dist/components/ShareAutosuggest.js +5 -5
- package/dist/components/ShareRecipientsInput.js +9 -1
- package/dist/components/ShareRecipientsInput.spec.js +68 -5
- package/dist/suggestionMatchers.js +5 -1
- package/package.json +2 -2
- package/src/components/ShareAutosuggest.jsx +7 -16
- package/src/components/ShareRecipientsInput.jsx +12 -1
- package/src/components/ShareRecipientsInput.spec.jsx +44 -1
- package/src/suggestionMatchers.js +16 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,12 @@
|
|
|
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.0.2](https://github.com/cozy/cozy-libs/compare/cozy-sharing@33.0.1...cozy-sharing@33.0.2) (2026-06-02)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- Avoid suggesting an already added or a pending recipient ([a9f7b19](https://github.com/cozy/cozy-libs/commit/a9f7b1934ef9d666b9515fe1cf28538a466bf1ff))
|
|
11
|
+
|
|
6
12
|
## [33.0.1](https://github.com/cozy/cozy-libs/compare/cozy-sharing@33.0.0...cozy-sharing@33.0.1) (2026-06-02)
|
|
7
13
|
|
|
8
14
|
### Bug Fixes
|
|
@@ -23,9 +23,9 @@ var styles = {
|
|
|
23
23
|
"recipientChip": "autosuggest__recipientChip___d5I3R",
|
|
24
24
|
"endAdornment": "autosuggest__endAdornment___2EwTN"
|
|
25
25
|
};
|
|
26
|
-
import {
|
|
26
|
+
import { contactOrGroupMatch } from '../suggestionMatchers';
|
|
27
27
|
|
|
28
|
-
var
|
|
28
|
+
var ShareAutosuggest = function ShareAutosuggest(_ref) {
|
|
29
29
|
var loading = _ref.loading,
|
|
30
30
|
disabled = _ref.disabled,
|
|
31
31
|
contactsAndGroups = _ref.contactsAndGroups,
|
|
@@ -62,7 +62,7 @@ var ShareAutocomplete = function ShareAutocomplete(_ref) {
|
|
|
62
62
|
var computeSuggestions = function computeSuggestions(value) {
|
|
63
63
|
var inputValue = value.trim().toLowerCase();
|
|
64
64
|
return inputValue.length === 0 ? [] : contactsAndGroups.filter(function (contactOrGroup) {
|
|
65
|
-
return
|
|
65
|
+
return contactOrGroupMatch(inputValue, contactOrGroup);
|
|
66
66
|
});
|
|
67
67
|
};
|
|
68
68
|
|
|
@@ -243,7 +243,7 @@ var ShareAutocomplete = function ShareAutocomplete(_ref) {
|
|
|
243
243
|
}));
|
|
244
244
|
};
|
|
245
245
|
|
|
246
|
-
|
|
246
|
+
ShareAutosuggest.propTypes = {
|
|
247
247
|
loading: PropTypes.bool,
|
|
248
248
|
disabled: PropTypes.bool,
|
|
249
249
|
contactsAndGroups: PropTypes.array,
|
|
@@ -254,4 +254,4 @@ ShareAutocomplete.propTypes = {
|
|
|
254
254
|
placeholder: PropTypes.string,
|
|
255
255
|
endAdornment: PropTypes.node
|
|
256
256
|
};
|
|
257
|
-
export default
|
|
257
|
+
export default ShareAutosuggest;
|
|
@@ -8,10 +8,12 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
|
|
|
8
8
|
import PropTypes from 'prop-types';
|
|
9
9
|
import React from 'react';
|
|
10
10
|
import { useQueryAll, isQueryLoading } from 'cozy-client';
|
|
11
|
+
import { models } from 'cozy-client';
|
|
11
12
|
import flag from 'cozy-flags';
|
|
12
13
|
import ShareAutosuggest from './ShareAutosuggest';
|
|
13
14
|
import { getContactsFromGroupId } from '../helpers/contacts';
|
|
14
15
|
import { buildReachableContactsQuery, buildContactGroupsQuery, buildUnreachableContactsWithGroupsQuery } from '../queries/queries';
|
|
16
|
+
var ContactModel = models.contact;
|
|
15
17
|
/**
|
|
16
18
|
* ShareRecipientsInput is responsible for fetching contacts and groups.
|
|
17
19
|
* We retrieve all the contacts that are reachable and the groups they belong to.
|
|
@@ -41,7 +43,13 @@ var ShareRecipientsInput = function ShareRecipientsInput(_ref) {
|
|
|
41
43
|
var contactGroupsResult = useQueryAll(contactGroupsQuery.definition, contactGroupsQuery.options);
|
|
42
44
|
var isLoading = isQueryLoading(reachableContactsResult) || reachableContactsResult.hasMore || isQueryLoading(contactGroupsResult) || contactGroupsResult.hasMore || flag('sharing.show-recipient-groups') && (isQueryLoading(unreachableContactsWithGroupsResult) || unreachableContactsWithGroupsResult.hasMore);
|
|
43
45
|
var reachableContacts = (reachableContactsResult.data || []).filter(function (contact) {
|
|
44
|
-
return !isCurrentUser(contact)
|
|
46
|
+
return !isCurrentUser(contact) && // We do not want contact already in the sharing
|
|
47
|
+
!currentRecipients.find(function (r) {
|
|
48
|
+
return r.email === ContactModel.getPrimaryEmail(contact);
|
|
49
|
+
}) && // We do not want contact currently in pending contacts (in chips)
|
|
50
|
+
!recipients.find(function (r) {
|
|
51
|
+
return r._id === contact._id;
|
|
52
|
+
});
|
|
45
53
|
});
|
|
46
54
|
var unreachableContactsWithGroups = (unreachableContactsWithGroupsResult.data || []).filter(function (contact) {
|
|
47
55
|
return !isCurrentUser(contact);
|
|
@@ -38,6 +38,11 @@ describe('ShareRecipientsInput component', function () {
|
|
|
38
38
|
var contacts = _ref2.contacts,
|
|
39
39
|
contactGroups = _ref2.contactGroups,
|
|
40
40
|
unreachableContact = _ref2.unreachableContact;
|
|
41
|
+
|
|
42
|
+
var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
|
|
43
|
+
currentRecipients = _ref3.currentRecipients,
|
|
44
|
+
recipients = _ref3.recipients;
|
|
45
|
+
|
|
41
46
|
var mockClient = createMockClient({
|
|
42
47
|
queries: {
|
|
43
48
|
'io.cozy.contacts/reachable': {
|
|
@@ -59,7 +64,9 @@ describe('ShareRecipientsInput component', function () {
|
|
|
59
64
|
}, /*#__PURE__*/React.createElement(ShareRecipientsInput, {
|
|
60
65
|
onPick: function onPick() {},
|
|
61
66
|
onRemove: function onRemove() {},
|
|
62
|
-
placeholder: "Enter recipients here"
|
|
67
|
+
placeholder: "Enter recipients here",
|
|
68
|
+
currentRecipients: currentRecipients,
|
|
69
|
+
recipients: recipients
|
|
63
70
|
})));
|
|
64
71
|
};
|
|
65
72
|
|
|
@@ -172,10 +179,66 @@ describe('ShareRecipientsInput component', function () {
|
|
|
172
179
|
}
|
|
173
180
|
}, _callee2);
|
|
174
181
|
})));
|
|
175
|
-
it('should
|
|
176
|
-
var contacts, contactGroups,
|
|
182
|
+
it('should exclude already added recipients from suggestions', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
|
|
183
|
+
var contacts, contactGroups, currentRecipients, recipients;
|
|
177
184
|
return _regeneratorRuntime.wrap(function _callee3$(_context3) {
|
|
178
185
|
while (1) switch (_context3.prev = _context3.next) {
|
|
186
|
+
case 0:
|
|
187
|
+
contacts = [{
|
|
188
|
+
id: 'df563cc4-6440',
|
|
189
|
+
_id: 'df563cc4-6440',
|
|
190
|
+
_type: 'io.cozy.contacts',
|
|
191
|
+
name: {
|
|
192
|
+
givenName: 'Michale',
|
|
193
|
+
familyName: 'Russel'
|
|
194
|
+
},
|
|
195
|
+
email: [{
|
|
196
|
+
address: 'michale@example.com',
|
|
197
|
+
primary: true
|
|
198
|
+
}]
|
|
199
|
+
}, {
|
|
200
|
+
id: '5a3b4ccf-c257',
|
|
201
|
+
_id: '5a3b4ccf-c257',
|
|
202
|
+
_type: 'io.cozy.contacts',
|
|
203
|
+
name: {
|
|
204
|
+
givenName: 'Teagan',
|
|
205
|
+
familyName: 'Wolf'
|
|
206
|
+
},
|
|
207
|
+
email: [{
|
|
208
|
+
address: 'teagan@example.com',
|
|
209
|
+
primary: true
|
|
210
|
+
}]
|
|
211
|
+
}];
|
|
212
|
+
contactGroups = [];
|
|
213
|
+
currentRecipients = [{
|
|
214
|
+
id: 'recipient-1',
|
|
215
|
+
email: 'michale@example.com'
|
|
216
|
+
}];
|
|
217
|
+
recipients = [{
|
|
218
|
+
_id: '5a3b4ccf-c257'
|
|
219
|
+
}];
|
|
220
|
+
setup({
|
|
221
|
+
contacts: contacts,
|
|
222
|
+
contactGroups: contactGroups
|
|
223
|
+
}, {
|
|
224
|
+
currentRecipients: currentRecipients,
|
|
225
|
+
recipients: recipients
|
|
226
|
+
}); // Michale is in currentRecipients by email, should be filtered out
|
|
227
|
+
|
|
228
|
+
expect(screen.queryByText('Michale Russel')).not.toBeInTheDocument(); // Teagan is in recipients by _id, should be filtered out
|
|
229
|
+
|
|
230
|
+
expect(screen.queryByText('Teagan Wolf')).not.toBeInTheDocument();
|
|
231
|
+
|
|
232
|
+
case 7:
|
|
233
|
+
case "end":
|
|
234
|
+
return _context3.stop();
|
|
235
|
+
}
|
|
236
|
+
}, _callee3);
|
|
237
|
+
})));
|
|
238
|
+
it('should include unreachable members when flag sharing.show-recipient-groups is activated', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
|
|
239
|
+
var contacts, contactGroups, unreachableContact;
|
|
240
|
+
return _regeneratorRuntime.wrap(function _callee4$(_context4) {
|
|
241
|
+
while (1) switch (_context4.prev = _context4.next) {
|
|
179
242
|
case 0:
|
|
180
243
|
flag.mockReturnValue(true);
|
|
181
244
|
contacts = [{
|
|
@@ -240,8 +303,8 @@ describe('ShareRecipientsInput component', function () {
|
|
|
240
303
|
|
|
241
304
|
case 8:
|
|
242
305
|
case "end":
|
|
243
|
-
return
|
|
306
|
+
return _context4.stop();
|
|
244
307
|
}
|
|
245
|
-
},
|
|
308
|
+
}, _callee4);
|
|
246
309
|
})));
|
|
247
310
|
});
|
|
@@ -40,4 +40,8 @@ var fullnameMatch = function fullnameMatch(input, contact) {
|
|
|
40
40
|
return fullnameInput.test(contact.fullname);
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
var contactOrGroupMatch = function contactOrGroupMatch(input, contact) {
|
|
44
|
+
return groupNameMatch(input, contact) || fullnameMatch(input, contact) || emailMatch(input, contact) || cozyUrlMatch(input, contact);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export { emailMatch, cozyUrlMatch, groupNameMatch, fullnameMatch, contactOrGroupMatch };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cozy-sharing",
|
|
3
|
-
"version": "33.0.
|
|
3
|
+
"version": "33.0.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": "
|
|
86
|
+
"gitHead": "0a14cfca6a608f4a40d2301c370b176ecbaeee4c"
|
|
87
87
|
}
|
|
@@ -12,14 +12,9 @@ import { isContactToBeCreated } from '../helpers/contacts'
|
|
|
12
12
|
import { extractEmails, validateEmail } from '../helpers/email'
|
|
13
13
|
import { getDisplayName, getInitials, Contact, Group } from '../models'
|
|
14
14
|
import styles from '../styles/autosuggest.styl'
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
groupNameMatch,
|
|
19
|
-
fullnameMatch
|
|
20
|
-
} from '../suggestionMatchers'
|
|
21
|
-
|
|
22
|
-
const ShareAutocomplete = ({
|
|
15
|
+
import { contactOrGroupMatch } from '../suggestionMatchers'
|
|
16
|
+
|
|
17
|
+
const ShareAutosuggest = ({
|
|
23
18
|
loading,
|
|
24
19
|
disabled,
|
|
25
20
|
contactsAndGroups,
|
|
@@ -43,12 +38,8 @@ const ShareAutocomplete = ({
|
|
|
43
38
|
|
|
44
39
|
return inputValue.length === 0
|
|
45
40
|
? []
|
|
46
|
-
: contactsAndGroups.filter(
|
|
47
|
-
contactOrGroup
|
|
48
|
-
groupNameMatch(inputValue, contactOrGroup) ||
|
|
49
|
-
fullnameMatch(inputValue, contactOrGroup) ||
|
|
50
|
-
emailMatch(inputValue, contactOrGroup) ||
|
|
51
|
-
cozyUrlMatch(inputValue, contactOrGroup)
|
|
41
|
+
: contactsAndGroups.filter(contactOrGroup =>
|
|
42
|
+
contactOrGroupMatch(inputValue, contactOrGroup)
|
|
52
43
|
)
|
|
53
44
|
}
|
|
54
45
|
|
|
@@ -226,7 +217,7 @@ const ShareAutocomplete = ({
|
|
|
226
217
|
)
|
|
227
218
|
}
|
|
228
219
|
|
|
229
|
-
|
|
220
|
+
ShareAutosuggest.propTypes = {
|
|
230
221
|
loading: PropTypes.bool,
|
|
231
222
|
disabled: PropTypes.bool,
|
|
232
223
|
contactsAndGroups: PropTypes.array,
|
|
@@ -238,4 +229,4 @@ ShareAutocomplete.propTypes = {
|
|
|
238
229
|
endAdornment: PropTypes.node
|
|
239
230
|
}
|
|
240
231
|
|
|
241
|
-
export default
|
|
232
|
+
export default ShareAutosuggest
|
|
@@ -2,6 +2,7 @@ import PropTypes from 'prop-types'
|
|
|
2
2
|
import React from 'react'
|
|
3
3
|
|
|
4
4
|
import { useQueryAll, isQueryLoading } from 'cozy-client'
|
|
5
|
+
import { models } from 'cozy-client'
|
|
5
6
|
import flag from 'cozy-flags'
|
|
6
7
|
|
|
7
8
|
import ShareAutosuggest from './ShareAutosuggest'
|
|
@@ -12,6 +13,8 @@ import {
|
|
|
12
13
|
buildUnreachableContactsWithGroupsQuery
|
|
13
14
|
} from '../queries/queries'
|
|
14
15
|
|
|
16
|
+
const ContactModel = models.contact
|
|
17
|
+
|
|
15
18
|
/**
|
|
16
19
|
* ShareRecipientsInput is responsible for fetching contacts and groups.
|
|
17
20
|
* We retrieve all the contacts that are reachable and the groups they belong to.
|
|
@@ -61,8 +64,16 @@ const ShareRecipientsInput = ({
|
|
|
61
64
|
unreachableContactsWithGroupsResult.hasMore))
|
|
62
65
|
|
|
63
66
|
const reachableContacts = (reachableContactsResult.data || []).filter(
|
|
64
|
-
contact =>
|
|
67
|
+
contact =>
|
|
68
|
+
!isCurrentUser(contact) &&
|
|
69
|
+
// We do not want contact already in the sharing
|
|
70
|
+
!currentRecipients.find(
|
|
71
|
+
r => r.email === ContactModel.getPrimaryEmail(contact)
|
|
72
|
+
) &&
|
|
73
|
+
// We do not want contact currently in pending contacts (in chips)
|
|
74
|
+
!recipients.find(r => r._id === contact._id)
|
|
65
75
|
)
|
|
76
|
+
|
|
66
77
|
const unreachableContactsWithGroups = (
|
|
67
78
|
unreachableContactsWithGroupsResult.data || []
|
|
68
79
|
).filter(contact => !isCurrentUser(contact))
|
|
@@ -38,7 +38,10 @@ jest.mock('./ShareAutosuggest', () => ({
|
|
|
38
38
|
}))
|
|
39
39
|
|
|
40
40
|
describe('ShareRecipientsInput component', () => {
|
|
41
|
-
const setup = (
|
|
41
|
+
const setup = (
|
|
42
|
+
{ contacts, contactGroups, unreachableContact },
|
|
43
|
+
{ currentRecipients, recipients } = {}
|
|
44
|
+
) => {
|
|
42
45
|
const mockClient = createMockClient({
|
|
43
46
|
queries: {
|
|
44
47
|
'io.cozy.contacts/reachable': {
|
|
@@ -61,6 +64,8 @@ describe('ShareRecipientsInput component', () => {
|
|
|
61
64
|
onPick={() => {}}
|
|
62
65
|
onRemove={() => {}}
|
|
63
66
|
placeholder="Enter recipients here"
|
|
67
|
+
currentRecipients={currentRecipients}
|
|
68
|
+
recipients={recipients}
|
|
64
69
|
/>
|
|
65
70
|
</AppLike>
|
|
66
71
|
)
|
|
@@ -175,6 +180,44 @@ describe('ShareRecipientsInput component', () => {
|
|
|
175
180
|
expect(screen.getByText('Friends - 1 members')).toBeInTheDocument()
|
|
176
181
|
})
|
|
177
182
|
|
|
183
|
+
it('should exclude already added recipients from suggestions', async () => {
|
|
184
|
+
const contacts = [
|
|
185
|
+
{
|
|
186
|
+
id: 'df563cc4-6440',
|
|
187
|
+
_id: 'df563cc4-6440',
|
|
188
|
+
_type: 'io.cozy.contacts',
|
|
189
|
+
name: {
|
|
190
|
+
givenName: 'Michale',
|
|
191
|
+
familyName: 'Russel'
|
|
192
|
+
},
|
|
193
|
+
email: [{ address: 'michale@example.com', primary: true }]
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
id: '5a3b4ccf-c257',
|
|
197
|
+
_id: '5a3b4ccf-c257',
|
|
198
|
+
_type: 'io.cozy.contacts',
|
|
199
|
+
name: {
|
|
200
|
+
givenName: 'Teagan',
|
|
201
|
+
familyName: 'Wolf'
|
|
202
|
+
},
|
|
203
|
+
email: [{ address: 'teagan@example.com', primary: true }]
|
|
204
|
+
}
|
|
205
|
+
]
|
|
206
|
+
|
|
207
|
+
const contactGroups = []
|
|
208
|
+
const currentRecipients = [
|
|
209
|
+
{ id: 'recipient-1', email: 'michale@example.com' }
|
|
210
|
+
]
|
|
211
|
+
const recipients = [{ _id: '5a3b4ccf-c257' }]
|
|
212
|
+
|
|
213
|
+
setup({ contacts, contactGroups }, { currentRecipients, recipients })
|
|
214
|
+
|
|
215
|
+
// Michale is in currentRecipients by email, should be filtered out
|
|
216
|
+
expect(screen.queryByText('Michale Russel')).not.toBeInTheDocument()
|
|
217
|
+
// Teagan is in recipients by _id, should be filtered out
|
|
218
|
+
expect(screen.queryByText('Teagan Wolf')).not.toBeInTheDocument()
|
|
219
|
+
})
|
|
220
|
+
|
|
178
221
|
it('should include unreachable members when flag sharing.show-recipient-groups is activated', async () => {
|
|
179
222
|
flag.mockReturnValue(true)
|
|
180
223
|
|
|
@@ -34,4 +34,19 @@ const fullnameMatch = (input, contact) => {
|
|
|
34
34
|
return fullnameInput.test(contact.fullname)
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
const contactOrGroupMatch = (input, contact) => {
|
|
38
|
+
return (
|
|
39
|
+
groupNameMatch(input, contact) ||
|
|
40
|
+
fullnameMatch(input, contact) ||
|
|
41
|
+
emailMatch(input, contact) ||
|
|
42
|
+
cozyUrlMatch(input, contact)
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export {
|
|
47
|
+
emailMatch,
|
|
48
|
+
cozyUrlMatch,
|
|
49
|
+
groupNameMatch,
|
|
50
|
+
fullnameMatch,
|
|
51
|
+
contactOrGroupMatch
|
|
52
|
+
}
|