cozy-sharing 33.1.0 → 33.1.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 +13 -0
- package/dist/components/SharedDrive/SharedDriveForm.js +21 -9
- package/dist/suggestionMatchers.js +33 -12
- package/dist/suggestionMatchers.spec.js +103 -0
- package/package.json +2 -2
- package/src/components/SharedDrive/SharedDriveForm.jsx +22 -6
- package/src/suggestionMatchers.js +25 -12
- package/src/suggestionMatchers.spec.js +107 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,19 @@
|
|
|
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.1.2](https://github.com/cozy/cozy-libs/compare/cozy-sharing@33.1.1...cozy-sharing@33.1.2) (2026-06-08)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- **cozy-sharing:** Avoid regex parsing in input matchers ([ecab525](https://github.com/cozy/cozy-libs/commit/ecab525b7559710d693787fb50c6c5fe8abd55ac))
|
|
11
|
+
- **cozy-sharing:** Make matching diacritic-insensitive ([e421a5a](https://github.com/cozy/cozy-libs/commit/e421a5ac5f97f64ef27340a3b87f9f15b3efebd9))
|
|
12
|
+
|
|
13
|
+
## [33.1.1](https://github.com/cozy/cozy-libs/compare/cozy-sharing@33.1.0...cozy-sharing@33.1.1) (2026-06-04)
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
- **cozy-sharing:** Memoize ShareByEmail section in SharedDriveForm ([2ea5eb2](https://github.com/cozy/cozy-libs/commit/2ea5eb2a8d37eec582212b07b8617c36fd107930))
|
|
18
|
+
|
|
6
19
|
# [33.1.0](https://github.com/cozy/cozy-libs/compare/cozy-sharing@33.0.2...cozy-sharing@33.1.0) (2026-06-04)
|
|
7
20
|
|
|
8
21
|
### Features
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import PropTypes from 'prop-types';
|
|
2
|
-
import React from 'react';
|
|
2
|
+
import React, { memo } from 'react';
|
|
3
3
|
import Button from 'cozy-ui/transpiled/react/Buttons';
|
|
4
4
|
import TextField from 'cozy-ui/transpiled/react/TextField';
|
|
5
5
|
import Typography from 'cozy-ui/transpiled/react/Typography';
|
|
@@ -9,9 +9,23 @@ import withLocales from '../../hoc/withLocales';
|
|
|
9
9
|
import { default as DumbShareByEmail } from '../ShareByEmail';
|
|
10
10
|
import SharedDriveHeader from './SharedDriveHeader';
|
|
11
11
|
import { useSharedDrive } from './useSharedDrive';
|
|
12
|
-
|
|
13
|
-
var
|
|
14
|
-
|
|
12
|
+
var ShareByEmailSection = /*#__PURE__*/memo(function ShareByEmailSection(_ref) {
|
|
13
|
+
var pendingRecipients = _ref.pendingRecipients,
|
|
14
|
+
setPendingRecipients = _ref.setPendingRecipients,
|
|
15
|
+
selectedOption = _ref.selectedOption,
|
|
16
|
+
setSelectedOption = _ref.setSelectedOption;
|
|
17
|
+
return /*#__PURE__*/React.createElement(DumbShareByEmail, {
|
|
18
|
+
currentRecipients: [],
|
|
19
|
+
documentType: "Files",
|
|
20
|
+
pendingRecipients: pendingRecipients,
|
|
21
|
+
onPendingRecipientsChange: setPendingRecipients,
|
|
22
|
+
selectedOption: selectedOption,
|
|
23
|
+
onSelectedOptionChange: setSelectedOption
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
export var SharedDriveForm = withLocales(function (_ref2) {
|
|
27
|
+
var onSuccess = _ref2.onSuccess,
|
|
28
|
+
onCancel = _ref2.onCancel;
|
|
15
29
|
|
|
16
30
|
var _useI18n = useI18n(),
|
|
17
31
|
t = _useI18n.t;
|
|
@@ -44,13 +58,11 @@ export var SharedDriveForm = withLocales(function (_ref) {
|
|
|
44
58
|
}), /*#__PURE__*/React.createElement(Typography, {
|
|
45
59
|
variant: "h6",
|
|
46
60
|
className: "u-mb-half"
|
|
47
|
-
}, t('Share.contacts.addUsers')), /*#__PURE__*/React.createElement(
|
|
48
|
-
currentRecipients: [],
|
|
49
|
-
documentType: "Files",
|
|
61
|
+
}, t('Share.contacts.addUsers')), /*#__PURE__*/React.createElement(ShareByEmailSection, {
|
|
50
62
|
pendingRecipients: pendingRecipients,
|
|
51
|
-
|
|
63
|
+
setPendingRecipients: setPendingRecipients,
|
|
52
64
|
selectedOption: selectedOption,
|
|
53
|
-
|
|
65
|
+
setSelectedOption: setSelectedOption
|
|
54
66
|
})), /*#__PURE__*/React.createElement("div", {
|
|
55
67
|
className: "u-flex u-ph-2 u-pv-1"
|
|
56
68
|
}, /*#__PURE__*/React.createElement(Button, {
|
|
@@ -1,43 +1,64 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import { Group } from 'cozy-doctypes';
|
|
2
|
+
var removeDiacritics;
|
|
3
|
+
|
|
4
|
+
try {
|
|
5
|
+
new RegExp('\\p{Diacritic}', 'gu');
|
|
6
|
+
|
|
7
|
+
removeDiacritics = function removeDiacritics(str) {
|
|
8
|
+
return str.replace(/(?:[\^`\xA8\xAF\xB4\xB7\xB8\u02B0-\u034E\u0350-\u0357\u035D-\u0362\u0374\u0375\u037A\u0384\u0385\u0483-\u0487\u0559\u0591-\u05A1\u05A3-\u05BD\u05BF\u05C1\u05C2\u05C4\u064B-\u0652\u0657\u0658\u06DF\u06E0\u06E5\u06E6\u06EA-\u06EC\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F5\u0818\u0819\u0898-\u089F\u08C9-\u08D2\u08E3-\u08FE\u093C\u094D\u0951-\u0954\u0971\u09BC\u09CD\u0A3C\u0A4D\u0ABC\u0ACD\u0AFD-\u0AFF\u0B3C\u0B4D\u0B55\u0BCD\u0C3C\u0C4D\u0CBC\u0CCD\u0D3B\u0D3C\u0D4D\u0DCA\u0E3A\u0E47-\u0E4C\u0E4E\u0EBA\u0EC8-\u0ECC\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F82-\u0F84\u0F86\u0F87\u0FC6\u1037\u1039\u103A\u1063\u1064\u1069-\u106D\u1087-\u108D\u108F\u109A\u109B\u135D-\u135F\u1714\u1715\u1734\u17C9-\u17D3\u17DD\u1939-\u193B\u1A60\u1A75-\u1A7C\u1A7F\u1AB0-\u1ABE\u1AC1-\u1ACB\u1B34\u1B44\u1B6B-\u1B73\u1BAA\u1BAB\u1BE6\u1BF2\u1BF3\u1C36\u1C37\u1C78-\u1C7D\u1CD0-\u1CE8\u1CED\u1CF4\u1CF7-\u1CF9\u1D2C-\u1D6A\u1DC4-\u1DCF\u1DF5-\u1DFF\u1FBD\u1FBF-\u1FC1\u1FCD-\u1FCF\u1FDD-\u1FDF\u1FED-\u1FEF\u1FFD\u1FFE\u2CEF-\u2CF1\u2E2F\u302A-\u302F\u3099-\u309C\u30FC\uA66F\uA67C\uA67D\uA67F\uA69C\uA69D\uA6F0\uA6F1\uA700-\uA721\uA788-\uA78A\uA7F8\uA7F9\uA806\uA82C\uA8C4\uA8E0-\uA8F1\uA92B-\uA92E\uA953\uA9B3\uA9C0\uA9E5\uAA7B-\uAA7D\uAABF-\uAAC2\uAAF6\uAB5B-\uAB5F\uAB69-\uAB6B\uABEC\uABED\uFB1E\uFE20-\uFE2F\uFF3E\uFF40\uFF70\uFF9E\uFF9F\uFFE3]|\uD800\uDEE0|\uD801[\uDF80-\uDF85\uDF87-\uDFB0\uDFB2-\uDFBA]|\uD802[\uDE38-\uDE3A\uDE3F\uDEE5\uDEE6]|\uD803[\uDD22-\uDD27\uDD4E\uDD69-\uDD6D\uDEFD-\uDEFF\uDF46-\uDF50\uDF82-\uDF85]|\uD804[\uDC46\uDC70\uDCB9\uDCBA\uDD33\uDD34\uDD73\uDDC0\uDDCA-\uDDCC\uDE35\uDE36\uDEE9\uDEEA\uDF3B\uDF3C\uDF4D\uDF66-\uDF6C\uDF70-\uDF74\uDFCE-\uDFD0\uDFD2\uDFD3\uDFE1\uDFE2]|\uD805[\uDC42\uDC46\uDCC2\uDCC3\uDDBF\uDDC0\uDE3F\uDEB6\uDEB7\uDF2B]|\uD806[\uDC39\uDC3A\uDD3D\uDD3E\uDD43\uDDE0\uDE34\uDE47\uDE99]|\uD807[\uDC3F\uDD42\uDD44\uDD45\uDD97\uDF41\uDF42\uDF5A]|\uD80D[\uDC47-\uDC55]|\uD818\uDD2F|\uD81A[\uDEF0-\uDEF4\uDF30-\uDF36]|\uD81B[\uDD6B\uDD6C\uDF8F-\uDF9F\uDFF0\uDFF1]|\uD82B[\uDFF0-\uDFF3\uDFF5-\uDFFB\uDFFD\uDFFE]|\uD833[\uDF00-\uDF2D\uDF30-\uDF46]|\uD834[\uDD67-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD]|\uD838[\uDC30-\uDC6D\uDD30-\uDD36\uDEAE\uDEEC-\uDEEF]|\uD839[\uDDEE\uDDEF]|\uD83A[\uDCD0-\uDCD6\uDD44-\uDD46\uDD48-\uDD4A])/g, '');
|
|
9
|
+
};
|
|
10
|
+
} catch (_unused) {
|
|
11
|
+
removeDiacritics = function removeDiacritics(str) {
|
|
12
|
+
return str.replace(/[̀-ͯ]/g, '');
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
var normalize = function normalize(str) {
|
|
17
|
+
return removeDiacritics(str.normalize('NFD'));
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
var normalizeLowercase = function normalizeLowercase(str) {
|
|
21
|
+
return normalize(str).toLowerCase();
|
|
22
|
+
}; // TODO: sadly we have different versions of contacts' doctype to handle...
|
|
3
23
|
// A migration tool on the stack side is needed here
|
|
4
24
|
|
|
25
|
+
|
|
5
26
|
var emailMatch = function emailMatch(input, contact) {
|
|
6
27
|
if (!contact.email) return false;
|
|
7
|
-
var
|
|
28
|
+
var normalizedInput = normalizeLowercase(input);
|
|
8
29
|
|
|
9
30
|
if (Array.isArray(contact.email)) {
|
|
10
31
|
return contact.email.some(function (email) {
|
|
11
|
-
return
|
|
32
|
+
return normalizeLowercase(email.address).includes(normalizedInput);
|
|
12
33
|
});
|
|
13
34
|
}
|
|
14
35
|
|
|
15
|
-
return
|
|
36
|
+
return normalizeLowercase(contact.email).includes(normalizedInput);
|
|
16
37
|
};
|
|
17
38
|
|
|
18
39
|
var cozyUrlMatch = function cozyUrlMatch(input, contact) {
|
|
19
40
|
if (!contact.cozy && !contact.url) return false;
|
|
20
|
-
var
|
|
41
|
+
var normalizedInput = normalizeLowercase(input);
|
|
21
42
|
|
|
22
43
|
if (contact.cozy && Array.isArray(contact.cozy)) {
|
|
23
44
|
return contact.cozy.some(function (cozy) {
|
|
24
|
-
return
|
|
45
|
+
return normalizeLowercase(cozy.url).includes(normalizedInput);
|
|
25
46
|
});
|
|
26
47
|
}
|
|
27
48
|
|
|
28
|
-
return
|
|
49
|
+
return normalizeLowercase(contact.url).includes(normalizedInput);
|
|
29
50
|
};
|
|
30
51
|
|
|
31
52
|
var groupNameMatch = function groupNameMatch(input, contactOrGroup) {
|
|
32
53
|
if (contactOrGroup._type !== Group.doctype) return false;
|
|
33
|
-
var
|
|
34
|
-
return
|
|
54
|
+
var normalizedInput = normalizeLowercase(input);
|
|
55
|
+
return normalizeLowercase(contactOrGroup.name).includes(normalizedInput);
|
|
35
56
|
};
|
|
36
57
|
|
|
37
58
|
var fullnameMatch = function fullnameMatch(input, contact) {
|
|
38
59
|
if (!contact.fullname) return false;
|
|
39
|
-
var
|
|
40
|
-
return
|
|
60
|
+
var normalizedInput = normalizeLowercase(input);
|
|
61
|
+
return normalizeLowercase(contact.fullname).includes(normalizedInput);
|
|
41
62
|
};
|
|
42
63
|
|
|
43
64
|
var contactOrGroupMatch = function contactOrGroupMatch(input, contact) {
|
|
@@ -127,5 +127,108 @@ describe('Suggestion matchers', function () {
|
|
|
127
127
|
expect(matchers.fullnameMatch('snow', contact)).toBeTruthy();
|
|
128
128
|
expect(matchers.fullnameMatch('MARG', contact)).toBeTruthy();
|
|
129
129
|
});
|
|
130
|
+
it('should match accented fullname with unaccented input', function () {
|
|
131
|
+
expect(matchers.fullnameMatch('zoe', {
|
|
132
|
+
fullname: 'Zoé Dupont'
|
|
133
|
+
})).toBeTruthy();
|
|
134
|
+
expect(matchers.fullnameMatch('elodie', {
|
|
135
|
+
fullname: 'Élodie Martin'
|
|
136
|
+
})).toBeTruthy();
|
|
137
|
+
expect(matchers.fullnameMatch('celine', {
|
|
138
|
+
fullname: 'Céline'
|
|
139
|
+
})).toBeTruthy();
|
|
140
|
+
});
|
|
141
|
+
it('should match unaccented fullname with accented input', function () {
|
|
142
|
+
expect(matchers.fullnameMatch('zoé', {
|
|
143
|
+
fullname: 'Zoe Dupont'
|
|
144
|
+
})).toBeTruthy();
|
|
145
|
+
});
|
|
146
|
+
it('should treat regex metacharacters as plain text', function () {
|
|
147
|
+
expect(function () {
|
|
148
|
+
return matchers.fullnameMatch('(', {
|
|
149
|
+
fullname: 'Jon Snow'
|
|
150
|
+
});
|
|
151
|
+
}).not.toThrow();
|
|
152
|
+
expect(matchers.fullnameMatch('(', {
|
|
153
|
+
fullname: 'Jon Snow'
|
|
154
|
+
})).toBeFalsy();
|
|
155
|
+
expect(matchers.fullnameMatch('.', {
|
|
156
|
+
fullname: 'Jon Snow'
|
|
157
|
+
})).toBeFalsy();
|
|
158
|
+
expect(matchers.fullnameMatch('.', {
|
|
159
|
+
fullname: 'Dr. House'
|
|
160
|
+
})).toBeTruthy();
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
describe('groupNameMatch', function () {
|
|
164
|
+
it('should match accented group name with unaccented input', function () {
|
|
165
|
+
var group = {
|
|
166
|
+
_type: 'io.cozy.contacts.groups',
|
|
167
|
+
name: 'Équipe'
|
|
168
|
+
};
|
|
169
|
+
expect(matchers.groupNameMatch('equipe', group)).toBeTruthy();
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
describe('Vietnamese diacritics support', function () {
|
|
173
|
+
var vietnameseContacts = [{
|
|
174
|
+
fullname: 'Nguyễn Văn Minh',
|
|
175
|
+
email: 'minh.nguyen@email.com'
|
|
176
|
+
}, {
|
|
177
|
+
fullname: 'Trần Thị Hương',
|
|
178
|
+
email: 'huong.tran@email.com'
|
|
179
|
+
}, {
|
|
180
|
+
fullname: 'Lê Hoàng Nam',
|
|
181
|
+
email: 'nam.hoang@email.com'
|
|
182
|
+
}, {
|
|
183
|
+
fullname: 'Phạm Đức Anh',
|
|
184
|
+
email: 'anh.pham@email.com',
|
|
185
|
+
cozy: [{
|
|
186
|
+
url: 'https://anh.mycozy.cloud'
|
|
187
|
+
}]
|
|
188
|
+
}];
|
|
189
|
+
it('should match Vietnamese accented name with unaccented input', function () {
|
|
190
|
+
expect(matchers.fullnameMatch('nguyen', vietnameseContacts[0])).toBeTruthy();
|
|
191
|
+
expect(matchers.fullnameMatch('van', vietnameseContacts[0])).toBeTruthy();
|
|
192
|
+
expect(matchers.fullnameMatch('minh', vietnameseContacts[0])).toBeTruthy();
|
|
193
|
+
expect(matchers.fullnameMatch('tran', vietnameseContacts[1])).toBeTruthy();
|
|
194
|
+
expect(matchers.fullnameMatch('huong', vietnameseContacts[1])).toBeTruthy();
|
|
195
|
+
expect(matchers.fullnameMatch('le', vietnameseContacts[2])).toBeTruthy();
|
|
196
|
+
expect(matchers.fullnameMatch('nam', vietnameseContacts[2])).toBeTruthy();
|
|
197
|
+
expect(matchers.fullnameMatch('pham', vietnameseContacts[3])).toBeTruthy();
|
|
198
|
+
expect(matchers.fullnameMatch('anh', vietnameseContacts[3])).toBeTruthy();
|
|
199
|
+
});
|
|
200
|
+
it('should match unaccented input with Vietnamese accented name', function () {
|
|
201
|
+
expect(matchers.fullnameMatch('nguyễn', vietnameseContacts[0])).toBeTruthy();
|
|
202
|
+
expect(matchers.fullnameMatch('văn', vietnameseContacts[0])).toBeTruthy();
|
|
203
|
+
expect(matchers.fullnameMatch('trần', vietnameseContacts[1])).toBeTruthy();
|
|
204
|
+
expect(matchers.fullnameMatch('hương', vietnameseContacts[1])).toBeTruthy();
|
|
205
|
+
expect(matchers.fullnameMatch('lê', vietnameseContacts[2])).toBeTruthy();
|
|
206
|
+
expect(matchers.fullnameMatch('phạm', vietnameseContacts[3])).toBeTruthy();
|
|
207
|
+
});
|
|
208
|
+
it('should match Vietnamese email with partial unaccented input', function () {
|
|
209
|
+
expect(matchers.emailMatch('minh', vietnameseContacts[0])).toBeTruthy();
|
|
210
|
+
expect(matchers.emailMatch('nguyen', vietnameseContacts[0])).toBeTruthy();
|
|
211
|
+
expect(matchers.emailMatch('huong', vietnameseContacts[1])).toBeTruthy();
|
|
212
|
+
expect(matchers.emailMatch('tran', vietnameseContacts[1])).toBeTruthy();
|
|
213
|
+
});
|
|
214
|
+
it('should match Vietnamese cozy URL with unaccented input', function () {
|
|
215
|
+
var contact = {
|
|
216
|
+
fullname: 'Đặng Minh Đức',
|
|
217
|
+
cozy: [{
|
|
218
|
+
url: 'https://duc.mycozy.cloud'
|
|
219
|
+
}]
|
|
220
|
+
};
|
|
221
|
+
expect(matchers.cozyUrlMatch('duc', contact)).toBeTruthy();
|
|
222
|
+
expect(matchers.cozyUrlMatch('mycozy', contact)).toBeTruthy();
|
|
223
|
+
});
|
|
224
|
+
it('should match Vietnamese group names with diacritics', function () {
|
|
225
|
+
var vietGroup = {
|
|
226
|
+
_type: 'io.cozy.contacts.groups',
|
|
227
|
+
name: 'Nhóm Việt'
|
|
228
|
+
};
|
|
229
|
+
expect(matchers.groupNameMatch('nhom', vietGroup)).toBeTruthy();
|
|
230
|
+
expect(matchers.groupNameMatch('viet', vietGroup)).toBeTruthy();
|
|
231
|
+
expect(matchers.groupNameMatch('nhóm', vietGroup)).toBeTruthy();
|
|
232
|
+
});
|
|
130
233
|
});
|
|
131
234
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cozy-sharing",
|
|
3
|
-
"version": "33.1.
|
|
3
|
+
"version": "33.1.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": "4f63c28ae3cd8cac22487e6640006de4f5c31cfc"
|
|
87
87
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import PropTypes from 'prop-types'
|
|
2
|
-
import React from 'react'
|
|
2
|
+
import React, { memo } from 'react'
|
|
3
3
|
|
|
4
4
|
import Button from 'cozy-ui/transpiled/react/Buttons'
|
|
5
5
|
import TextField from 'cozy-ui/transpiled/react/TextField'
|
|
@@ -12,6 +12,24 @@ import { default as DumbShareByEmail } from '../ShareByEmail'
|
|
|
12
12
|
import SharedDriveHeader from './SharedDriveHeader'
|
|
13
13
|
import { useSharedDrive } from './useSharedDrive'
|
|
14
14
|
|
|
15
|
+
const ShareByEmailSection = memo(function ShareByEmailSection({
|
|
16
|
+
pendingRecipients,
|
|
17
|
+
setPendingRecipients,
|
|
18
|
+
selectedOption,
|
|
19
|
+
setSelectedOption
|
|
20
|
+
}) {
|
|
21
|
+
return (
|
|
22
|
+
<DumbShareByEmail
|
|
23
|
+
currentRecipients={[]}
|
|
24
|
+
documentType="Files"
|
|
25
|
+
pendingRecipients={pendingRecipients}
|
|
26
|
+
onPendingRecipientsChange={setPendingRecipients}
|
|
27
|
+
selectedOption={selectedOption}
|
|
28
|
+
onSelectedOptionChange={setSelectedOption}
|
|
29
|
+
/>
|
|
30
|
+
)
|
|
31
|
+
})
|
|
32
|
+
|
|
15
33
|
export const SharedDriveForm = withLocales(({ onSuccess, onCancel }) => {
|
|
16
34
|
const { t } = useI18n()
|
|
17
35
|
const {
|
|
@@ -41,13 +59,11 @@ export const SharedDriveForm = withLocales(({ onSuccess, onCancel }) => {
|
|
|
41
59
|
<Typography variant="h6" className="u-mb-half">
|
|
42
60
|
{t('Share.contacts.addUsers')}
|
|
43
61
|
</Typography>
|
|
44
|
-
<
|
|
45
|
-
currentRecipients={[]}
|
|
46
|
-
documentType="Files"
|
|
62
|
+
<ShareByEmailSection
|
|
47
63
|
pendingRecipients={pendingRecipients}
|
|
48
|
-
|
|
64
|
+
setPendingRecipients={setPendingRecipients}
|
|
49
65
|
selectedOption={selectedOption}
|
|
50
|
-
|
|
66
|
+
setSelectedOption={setSelectedOption}
|
|
51
67
|
/>
|
|
52
68
|
</div>
|
|
53
69
|
<div className="u-flex u-ph-2 u-pv-1">
|
|
@@ -1,37 +1,50 @@
|
|
|
1
|
-
import escapeRegExp from 'lodash/escapeRegExp'
|
|
2
|
-
|
|
3
1
|
import { Group } from 'cozy-doctypes'
|
|
4
2
|
|
|
3
|
+
let removeDiacritics
|
|
4
|
+
try {
|
|
5
|
+
new RegExp('\\p{Diacritic}', 'gu')
|
|
6
|
+
removeDiacritics = str => str.replace(/\p{Diacritic}/gu, '')
|
|
7
|
+
} catch {
|
|
8
|
+
removeDiacritics = str => str.replace(/[̀-ͯ]/g, '')
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const normalize = str => removeDiacritics(str.normalize('NFD'))
|
|
12
|
+
const normalizeLowercase = str => normalize(str).toLowerCase()
|
|
13
|
+
|
|
5
14
|
// TODO: sadly we have different versions of contacts' doctype to handle...
|
|
6
15
|
// A migration tool on the stack side is needed here
|
|
7
16
|
const emailMatch = (input, contact) => {
|
|
8
17
|
if (!contact.email) return false
|
|
9
|
-
const
|
|
18
|
+
const normalizedInput = normalizeLowercase(input)
|
|
10
19
|
if (Array.isArray(contact.email)) {
|
|
11
|
-
return contact.email.some(email =>
|
|
20
|
+
return contact.email.some(email =>
|
|
21
|
+
normalizeLowercase(email.address).includes(normalizedInput)
|
|
22
|
+
)
|
|
12
23
|
}
|
|
13
|
-
return
|
|
24
|
+
return normalizeLowercase(contact.email).includes(normalizedInput)
|
|
14
25
|
}
|
|
15
26
|
|
|
16
27
|
const cozyUrlMatch = (input, contact) => {
|
|
17
28
|
if (!contact.cozy && !contact.url) return false
|
|
18
|
-
const
|
|
29
|
+
const normalizedInput = normalizeLowercase(input)
|
|
19
30
|
if (contact.cozy && Array.isArray(contact.cozy)) {
|
|
20
|
-
return contact.cozy.some(cozy =>
|
|
31
|
+
return contact.cozy.some(cozy =>
|
|
32
|
+
normalizeLowercase(cozy.url).includes(normalizedInput)
|
|
33
|
+
)
|
|
21
34
|
}
|
|
22
|
-
return
|
|
35
|
+
return normalizeLowercase(contact.url).includes(normalizedInput)
|
|
23
36
|
}
|
|
24
37
|
|
|
25
38
|
const groupNameMatch = (input, contactOrGroup) => {
|
|
26
39
|
if (contactOrGroup._type !== Group.doctype) return false
|
|
27
|
-
const
|
|
28
|
-
return
|
|
40
|
+
const normalizedInput = normalizeLowercase(input)
|
|
41
|
+
return normalizeLowercase(contactOrGroup.name).includes(normalizedInput)
|
|
29
42
|
}
|
|
30
43
|
|
|
31
44
|
const fullnameMatch = (input, contact) => {
|
|
32
45
|
if (!contact.fullname) return false
|
|
33
|
-
const
|
|
34
|
-
return
|
|
46
|
+
const normalizedInput = normalizeLowercase(input)
|
|
47
|
+
return normalizeLowercase(contact.fullname).includes(normalizedInput)
|
|
35
48
|
}
|
|
36
49
|
|
|
37
50
|
const contactOrGroupMatch = (input, contact) => {
|
|
@@ -146,5 +146,112 @@ describe('Suggestion matchers', () => {
|
|
|
146
146
|
expect(matchers.fullnameMatch('snow', contact)).toBeTruthy()
|
|
147
147
|
expect(matchers.fullnameMatch('MARG', contact)).toBeTruthy()
|
|
148
148
|
})
|
|
149
|
+
|
|
150
|
+
it('should match accented fullname with unaccented input', () => {
|
|
151
|
+
expect(
|
|
152
|
+
matchers.fullnameMatch('zoe', { fullname: 'Zoé Dupont' })
|
|
153
|
+
).toBeTruthy()
|
|
154
|
+
expect(
|
|
155
|
+
matchers.fullnameMatch('elodie', { fullname: 'Élodie Martin' })
|
|
156
|
+
).toBeTruthy()
|
|
157
|
+
expect(
|
|
158
|
+
matchers.fullnameMatch('celine', { fullname: 'Céline' })
|
|
159
|
+
).toBeTruthy()
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
it('should match unaccented fullname with accented input', () => {
|
|
163
|
+
expect(
|
|
164
|
+
matchers.fullnameMatch('zoé', { fullname: 'Zoe Dupont' })
|
|
165
|
+
).toBeTruthy()
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
it('should treat regex metacharacters as plain text', () => {
|
|
169
|
+
expect(() =>
|
|
170
|
+
matchers.fullnameMatch('(', { fullname: 'Jon Snow' })
|
|
171
|
+
).not.toThrow()
|
|
172
|
+
expect(matchers.fullnameMatch('(', { fullname: 'Jon Snow' })).toBeFalsy()
|
|
173
|
+
expect(matchers.fullnameMatch('.', { fullname: 'Jon Snow' })).toBeFalsy()
|
|
174
|
+
expect(
|
|
175
|
+
matchers.fullnameMatch('.', { fullname: 'Dr. House' })
|
|
176
|
+
).toBeTruthy()
|
|
177
|
+
})
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
describe('groupNameMatch', () => {
|
|
181
|
+
it('should match accented group name with unaccented input', () => {
|
|
182
|
+
const group = {
|
|
183
|
+
_type: 'io.cozy.contacts.groups',
|
|
184
|
+
name: 'Équipe'
|
|
185
|
+
}
|
|
186
|
+
expect(matchers.groupNameMatch('equipe', group)).toBeTruthy()
|
|
187
|
+
})
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
describe('Vietnamese diacritics support', () => {
|
|
191
|
+
const vietnameseContacts = [
|
|
192
|
+
{ fullname: 'Nguyễn Văn Minh', email: 'minh.nguyen@email.com' },
|
|
193
|
+
{ fullname: 'Trần Thị Hương', email: 'huong.tran@email.com' },
|
|
194
|
+
{ fullname: 'Lê Hoàng Nam', email: 'nam.hoang@email.com' },
|
|
195
|
+
{
|
|
196
|
+
fullname: 'Phạm Đức Anh',
|
|
197
|
+
email: 'anh.pham@email.com',
|
|
198
|
+
cozy: [{ url: 'https://anh.mycozy.cloud' }]
|
|
199
|
+
}
|
|
200
|
+
]
|
|
201
|
+
|
|
202
|
+
it('should match Vietnamese accented name with unaccented input', () => {
|
|
203
|
+
expect(
|
|
204
|
+
matchers.fullnameMatch('nguyen', vietnameseContacts[0])
|
|
205
|
+
).toBeTruthy()
|
|
206
|
+
expect(matchers.fullnameMatch('van', vietnameseContacts[0])).toBeTruthy()
|
|
207
|
+
expect(matchers.fullnameMatch('minh', vietnameseContacts[0])).toBeTruthy()
|
|
208
|
+
expect(matchers.fullnameMatch('tran', vietnameseContacts[1])).toBeTruthy()
|
|
209
|
+
expect(
|
|
210
|
+
matchers.fullnameMatch('huong', vietnameseContacts[1])
|
|
211
|
+
).toBeTruthy()
|
|
212
|
+
expect(matchers.fullnameMatch('le', vietnameseContacts[2])).toBeTruthy()
|
|
213
|
+
expect(matchers.fullnameMatch('nam', vietnameseContacts[2])).toBeTruthy()
|
|
214
|
+
expect(matchers.fullnameMatch('pham', vietnameseContacts[3])).toBeTruthy()
|
|
215
|
+
expect(matchers.fullnameMatch('anh', vietnameseContacts[3])).toBeTruthy()
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
it('should match unaccented input with Vietnamese accented name', () => {
|
|
219
|
+
expect(
|
|
220
|
+
matchers.fullnameMatch('nguyễn', vietnameseContacts[0])
|
|
221
|
+
).toBeTruthy()
|
|
222
|
+
expect(matchers.fullnameMatch('văn', vietnameseContacts[0])).toBeTruthy()
|
|
223
|
+
expect(matchers.fullnameMatch('trần', vietnameseContacts[1])).toBeTruthy()
|
|
224
|
+
expect(
|
|
225
|
+
matchers.fullnameMatch('hương', vietnameseContacts[1])
|
|
226
|
+
).toBeTruthy()
|
|
227
|
+
expect(matchers.fullnameMatch('lê', vietnameseContacts[2])).toBeTruthy()
|
|
228
|
+
expect(matchers.fullnameMatch('phạm', vietnameseContacts[3])).toBeTruthy()
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
it('should match Vietnamese email with partial unaccented input', () => {
|
|
232
|
+
expect(matchers.emailMatch('minh', vietnameseContacts[0])).toBeTruthy()
|
|
233
|
+
expect(matchers.emailMatch('nguyen', vietnameseContacts[0])).toBeTruthy()
|
|
234
|
+
expect(matchers.emailMatch('huong', vietnameseContacts[1])).toBeTruthy()
|
|
235
|
+
expect(matchers.emailMatch('tran', vietnameseContacts[1])).toBeTruthy()
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
it('should match Vietnamese cozy URL with unaccented input', () => {
|
|
239
|
+
const contact = {
|
|
240
|
+
fullname: 'Đặng Minh Đức',
|
|
241
|
+
cozy: [{ url: 'https://duc.mycozy.cloud' }]
|
|
242
|
+
}
|
|
243
|
+
expect(matchers.cozyUrlMatch('duc', contact)).toBeTruthy()
|
|
244
|
+
expect(matchers.cozyUrlMatch('mycozy', contact)).toBeTruthy()
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
it('should match Vietnamese group names with diacritics', () => {
|
|
248
|
+
const vietGroup = {
|
|
249
|
+
_type: 'io.cozy.contacts.groups',
|
|
250
|
+
name: 'Nhóm Việt'
|
|
251
|
+
}
|
|
252
|
+
expect(matchers.groupNameMatch('nhom', vietGroup)).toBeTruthy()
|
|
253
|
+
expect(matchers.groupNameMatch('viet', vietGroup)).toBeTruthy()
|
|
254
|
+
expect(matchers.groupNameMatch('nhóm', vietGroup)).toBeTruthy()
|
|
255
|
+
})
|
|
149
256
|
})
|
|
150
257
|
})
|