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
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,20 @@
|
|
|
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
|
+
## [40.2.1](https://github.com/cozy/cozy-libs/compare/cozy-sharing@40.2.0...cozy-sharing@40.2.1) (2026-10-28)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package cozy-sharing
|
|
9
|
+
|
|
10
|
+
# [40.2.0](https://github.com/cozy/cozy-libs/compare/cozy-sharing@40.1.9...cozy-sharing@40.2.0) (2026-10-28)
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
- **cozy-sharing:** Ignore the email case when filtering suggestions ([4057cf0](https://github.com/cozy/cozy-libs/commit/4057cf010f54c646d8518aa787e03be445b60df2))
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
- **cozy-sharing:** Suggest recipients from the stack ([8b06972](https://github.com/cozy/cozy-libs/commit/8b0697256b118c365ca9f7315aae3f00eef6ebd6)), closes [linagora/twake-workplace-private#1929](https://github.com/linagora/twake-workplace-private/issues/1929)
|
|
19
|
+
|
|
6
20
|
## [40.1.9](https://github.com/cozy/cozy-libs/compare/cozy-sharing@40.1.8...cozy-sharing@40.1.9) (2026-10-28)
|
|
7
21
|
|
|
8
22
|
### Bug Fixes
|
package/README.md
CHANGED
|
@@ -40,6 +40,7 @@ import SharingProvider from 'cozy-sharing'
|
|
|
40
40
|
| `onShared` | no | Callback fired after a share is created |
|
|
41
41
|
| `isPublic` | no | Set to `true` when rendering a public page (disables fetching) |
|
|
42
42
|
| `previewPath` | no | Custom preview path sent to the share creation |
|
|
43
|
+
| `contactsSuggestEnabled` | no | Suggest the recipients with `GET /contacts/suggest` instead of loading every contact |
|
|
43
44
|
|
|
44
45
|
### Built-in components
|
|
45
46
|
|
|
@@ -2,7 +2,7 @@ import _extends from "@babel/runtime/helpers/extends";
|
|
|
2
2
|
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
|
|
3
3
|
var _excluded = ["docId"];
|
|
4
4
|
import React from 'react';
|
|
5
|
-
import {
|
|
5
|
+
import { MemberAvatarWrapper } from './components/Avatar/MemberAvatarWrapper';
|
|
6
6
|
import SharingContext from './context';
|
|
7
7
|
import withLocales from './hoc/withLocales';
|
|
8
8
|
export var SharingOwnerAvatar = withLocales(function (_ref) {
|
|
@@ -14,7 +14,7 @@ export var SharingOwnerAvatar = withLocales(function (_ref) {
|
|
|
14
14
|
byDocId = _ref2.byDocId,
|
|
15
15
|
getOwner = _ref2.getOwner;
|
|
16
16
|
|
|
17
|
-
return !byDocId || !byDocId[docId] ? null : /*#__PURE__*/React.createElement(
|
|
17
|
+
return !byDocId || !byDocId[docId] ? null : /*#__PURE__*/React.createElement(MemberAvatarWrapper, _extends({
|
|
18
18
|
recipient: getOwner(docId)
|
|
19
19
|
}, rest));
|
|
20
20
|
});
|
package/dist/SharingProvider.js
CHANGED
|
@@ -1451,7 +1451,9 @@ export var SharingProvider = /*#__PURE__*/function (_Component) {
|
|
|
1451
1451
|
// but if we don't, consumers don't rerender when the state changes after loading the sharings,
|
|
1452
1452
|
// probably because the state object remains the same...
|
|
1453
1453
|
return /*#__PURE__*/React.createElement(SharingContext.Provider, {
|
|
1454
|
-
value: _objectSpread({}, this.state)
|
|
1454
|
+
value: _objectSpread(_objectSpread({}, this.state), {}, {
|
|
1455
|
+
contactsSuggestEnabled: this.props.contactsSuggestEnabled
|
|
1456
|
+
})
|
|
1455
1457
|
}, this.props.children);
|
|
1456
1458
|
}
|
|
1457
1459
|
}]);
|
|
@@ -6,7 +6,7 @@ import { useClient } from 'cozy-client';
|
|
|
6
6
|
import Avatar from 'cozy-ui/transpiled/react/Avatar';
|
|
7
7
|
import { ExtraAvatar } from './ExtraAvatar';
|
|
8
8
|
import { GroupAvatar } from './GroupAvatar';
|
|
9
|
-
import {
|
|
9
|
+
import { MemberAvatarWrapper } from './MemberAvatarWrapper';
|
|
10
10
|
import { getDisplayName } from '../../models';
|
|
11
11
|
var styles = {
|
|
12
12
|
"recipient": "recipient__recipient___2DmZI",
|
|
@@ -96,7 +96,7 @@ var AvatarList = function AvatarList(_ref2) {
|
|
|
96
96
|
return /*#__PURE__*/React.createElement("span", {
|
|
97
97
|
"data-testid": "AvatarList-avatar".concat(recipient.status === 'owner' ? '-owner' : ''),
|
|
98
98
|
key: recipient.index
|
|
99
|
-
}, /*#__PURE__*/React.createElement(
|
|
99
|
+
}, /*#__PURE__*/React.createElement(MemberAvatarWrapper, {
|
|
100
100
|
recipient: recipient,
|
|
101
101
|
size: size
|
|
102
102
|
}));
|
|
@@ -1,49 +1,25 @@
|
|
|
1
1
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
2
|
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
3
3
|
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
|
|
4
|
-
var _excluded = ["recipient"];
|
|
4
|
+
var _excluded = ["recipient", "avatarUrl"];
|
|
5
5
|
|
|
6
6
|
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; }
|
|
7
7
|
|
|
8
8
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
9
9
|
|
|
10
10
|
import React, { useState } from 'react';
|
|
11
|
-
import { useClient } from 'cozy-client';
|
|
12
|
-
import { getPrimaryCozy } from 'cozy-client/dist/models/contact';
|
|
13
11
|
import Avatar from 'cozy-ui/transpiled/react/Avatar';
|
|
14
12
|
import logger from '../../logger';
|
|
15
13
|
import { getInitials } from '../../models';
|
|
16
|
-
/**
|
|
17
|
-
* makeAvatarUrl derives the avatar image URL for the recipient.
|
|
18
|
-
* - If the recipient has an avatarPath (sharing context), it is
|
|
19
|
-
* used directly with a base URI prefix (unless it is already
|
|
20
|
-
* a full URL for a remote Cozy).
|
|
21
|
-
* - If the recipient has no avatarPath but has a cozy URL
|
|
22
|
-
* (contact context), it points to that Cozy's public avatar.
|
|
23
|
-
* - The status is used as a cache-buster in the URL so the
|
|
24
|
-
* browser refreshes the image when the sharing status changes.
|
|
25
|
-
* For non-sharing recipients, 'contact' is the stable default.
|
|
26
|
-
*/
|
|
27
|
-
|
|
28
|
-
var makeAvatarUrl = function makeAvatarUrl(recipient, instanceUri) {
|
|
29
|
-
var avatarPath = recipient.avatarPath;
|
|
30
|
-
var cozyUrl = !avatarPath ? getPrimaryCozy(recipient) : null;
|
|
31
|
-
if (!avatarPath && !cozyUrl) return null;
|
|
32
|
-
var finalPath = avatarPath || "".concat(cozyUrl.replace(/\/$/, ''), "/public/avatar?fallback=initials");
|
|
33
|
-
var status = recipient.status || 'contact';
|
|
34
|
-
var isFullPath = finalPath.startsWith('http');
|
|
35
|
-
var base = isFullPath ? '' : instanceUri;
|
|
36
|
-
return "".concat(base).concat(finalPath).concat(finalPath.includes('?') ? '&' : '?', "v=").concat(status);
|
|
37
|
-
};
|
|
38
14
|
|
|
39
15
|
var MemberAvatar = function MemberAvatar(_ref) {
|
|
40
16
|
var recipient = _ref.recipient,
|
|
17
|
+
avatarUrl = _ref.avatarUrl,
|
|
41
18
|
rest = _objectWithoutProperties(_ref, _excluded);
|
|
42
19
|
|
|
43
|
-
|
|
20
|
+
// Remember which image url failed to load so we can fall back to the
|
|
44
21
|
// initials. Storing the url (instead of a boolean) means a new url is
|
|
45
22
|
// retried automatically, without an effect to reset the error state.
|
|
46
|
-
|
|
47
23
|
var _useState = useState(null),
|
|
48
24
|
_useState2 = _slicedToArray(_useState, 2),
|
|
49
25
|
erroredSrc = _useState2[0],
|
|
@@ -59,19 +35,18 @@ var MemberAvatar = function MemberAvatar(_ref) {
|
|
|
59
35
|
recipient: recipient
|
|
60
36
|
}, rest));
|
|
61
37
|
return null;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
var image = makeAvatarUrl(recipient, client.options.uri); // The avatar can become unreachable (eg. the related sharing is revoked
|
|
38
|
+
} // The avatar can become unreachable (eg. the related sharing is revoked
|
|
65
39
|
// while its members are still rendered), in which case the image request
|
|
66
40
|
// fails. Without a fallback the browser shows a broken-image icon, so we
|
|
67
41
|
// render the initials instead.
|
|
68
42
|
|
|
69
|
-
|
|
43
|
+
|
|
44
|
+
return /*#__PURE__*/React.createElement(Avatar, rest, avatarUrl && erroredSrc !== avatarUrl ? /*#__PURE__*/React.createElement("img", {
|
|
70
45
|
width: "100%",
|
|
71
46
|
height: "100%",
|
|
72
|
-
src:
|
|
47
|
+
src: avatarUrl,
|
|
73
48
|
onError: function onError() {
|
|
74
|
-
return setErroredSrc(
|
|
49
|
+
return setErroredSrc(avatarUrl);
|
|
75
50
|
}
|
|
76
51
|
}) : getInitials(recipient));
|
|
77
52
|
};
|
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
import { render, fireEvent } from '@testing-library/react';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import { createMockClient } from 'cozy-client';
|
|
4
3
|
import { MemberAvatar } from './MemberAvatar';
|
|
5
4
|
import AppLike from '../../../test/AppLike';
|
|
6
5
|
describe('MemberAvatar', function () {
|
|
7
|
-
var client = createMockClient({});
|
|
8
|
-
client.options = {
|
|
9
|
-
uri: 'http://cozy.example.com'
|
|
10
|
-
};
|
|
11
|
-
|
|
12
6
|
var setup = function setup(recipient) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
var avatarUrl = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
8
|
+
return render( /*#__PURE__*/React.createElement(AppLike, null, /*#__PURE__*/React.createElement(MemberAvatar, {
|
|
9
|
+
recipient: recipient,
|
|
10
|
+
avatarUrl: avatarUrl
|
|
17
11
|
})));
|
|
18
12
|
};
|
|
19
13
|
|
|
@@ -26,92 +20,38 @@ describe('MemberAvatar', function () {
|
|
|
26
20
|
expect(container.querySelector('[class*="MuiAvatar-root"]')).toBeNull();
|
|
27
21
|
expect(container.querySelector('img')).toBeNull();
|
|
28
22
|
});
|
|
29
|
-
it('renders the avatar image
|
|
23
|
+
it('renders the avatar image', function () {
|
|
30
24
|
var _setup2 = setup({
|
|
31
25
|
public_name: 'Bob',
|
|
32
|
-
status: 'owner'
|
|
33
|
-
|
|
34
|
-
}),
|
|
26
|
+
status: 'owner'
|
|
27
|
+
}, 'http://cozy.example.com/sharings/123/recipients/0/avatar?v=owner'),
|
|
35
28
|
container = _setup2.container;
|
|
36
29
|
|
|
37
|
-
|
|
38
|
-
expect(img).toBeTruthy();
|
|
39
|
-
expect(img.getAttribute('src')).toBe('http://cozy.example.com/sharings/123/recipients/0/avatar?v=owner');
|
|
30
|
+
expect(container.querySelector('img').getAttribute('src')).toBe('http://cozy.example.com/sharings/123/recipients/0/avatar?v=owner');
|
|
40
31
|
});
|
|
41
|
-
it('
|
|
32
|
+
it('renders the initials when there is no avatar URL', function () {
|
|
42
33
|
var _setup3 = setup({
|
|
43
|
-
public_name: 'Bob',
|
|
44
|
-
status: 'owner',
|
|
45
|
-
avatarPath: '/public/avatar?fallback=initials'
|
|
46
|
-
}),
|
|
47
|
-
container = _setup3.container;
|
|
48
|
-
|
|
49
|
-
expect(container.querySelector('img').getAttribute('src')).toBe('http://cozy.example.com/public/avatar?fallback=initials&v=owner');
|
|
50
|
-
});
|
|
51
|
-
it('renders a full URL avatarPath without prefixing the local instance URI', function () {
|
|
52
|
-
var _setup4 = setup({
|
|
53
|
-
public_name: 'Jon Snow',
|
|
54
|
-
status: 'contact',
|
|
55
|
-
avatarPath: 'https://jonsnow.mycozy.cloud/public/avatar?fallback=initials'
|
|
56
|
-
}),
|
|
57
|
-
container = _setup4.container;
|
|
58
|
-
|
|
59
|
-
expect(container.querySelector('img').getAttribute('src')).toBe('https://jonsnow.mycozy.cloud/public/avatar?fallback=initials&v=contact');
|
|
60
|
-
});
|
|
61
|
-
it('derives avatarPath from cozy URL when avatarPath is not set', function () {
|
|
62
|
-
var _setup5 = setup({
|
|
63
|
-
_type: 'io.cozy.contacts',
|
|
64
|
-
name: {
|
|
65
|
-
givenName: 'Jon',
|
|
66
|
-
familyName: 'Snow'
|
|
67
|
-
},
|
|
68
|
-
cozy: [{
|
|
69
|
-
url: 'https://jonsnow.mycozy.cloud'
|
|
70
|
-
}]
|
|
71
|
-
}),
|
|
72
|
-
container = _setup5.container;
|
|
73
|
-
|
|
74
|
-
var img = container.querySelector('img');
|
|
75
|
-
expect(img).toBeTruthy();
|
|
76
|
-
expect(img.getAttribute('src')).toBe('https://jonsnow.mycozy.cloud/public/avatar?fallback=initials&v=contact');
|
|
77
|
-
});
|
|
78
|
-
it('renders initials when there is no avatarPath and no cozy URL', function () {
|
|
79
|
-
var _setup6 = setup({
|
|
80
34
|
_type: 'io.cozy.contacts',
|
|
81
35
|
name: {
|
|
82
36
|
givenName: 'Jon',
|
|
83
37
|
familyName: 'Snow'
|
|
84
38
|
}
|
|
85
39
|
}),
|
|
86
|
-
container =
|
|
87
|
-
getByText =
|
|
40
|
+
container = _setup3.container,
|
|
41
|
+
getByText = _setup3.getByText;
|
|
88
42
|
|
|
89
43
|
expect(container.querySelector('img')).toBeNull();
|
|
90
44
|
expect(getByText('JS')).toBeTruthy();
|
|
91
45
|
});
|
|
92
|
-
it('renders the initials when there is no avatarPath', function () {
|
|
93
|
-
var _setup7 = setup({
|
|
94
|
-
public_name: 'Bob',
|
|
95
|
-
status: 'owner'
|
|
96
|
-
}),
|
|
97
|
-
container = _setup7.container,
|
|
98
|
-
getByText = _setup7.getByText;
|
|
99
|
-
|
|
100
|
-
expect(container.querySelector('img')).toBeNull();
|
|
101
|
-
expect(getByText('B')).toBeTruthy();
|
|
102
|
-
});
|
|
103
46
|
it('falls back to the initials when the avatar image fails to load', function () {
|
|
104
|
-
var
|
|
47
|
+
var _setup4 = setup({
|
|
105
48
|
public_name: 'Bob',
|
|
106
|
-
status: 'owner'
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
getByText = _setup8.getByText;
|
|
49
|
+
status: 'owner'
|
|
50
|
+
}, 'http://cozy.example.com/sharings/123/recipients/0/avatar?v=owner'),
|
|
51
|
+
container = _setup4.container,
|
|
52
|
+
getByText = _setup4.getByText;
|
|
111
53
|
|
|
112
|
-
|
|
113
|
-
expect(img).toBeTruthy();
|
|
114
|
-
fireEvent.error(img);
|
|
54
|
+
fireEvent.error(container.querySelector('img'));
|
|
115
55
|
expect(container.querySelector('img')).toBeNull();
|
|
116
56
|
expect(getByText('B')).toBeTruthy();
|
|
117
57
|
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
+
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
|
|
3
|
+
var _excluded = ["recipient"];
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { useClient } from 'cozy-client';
|
|
6
|
+
import { MemberAvatar } from './MemberAvatar';
|
|
7
|
+
import { makeAvatarUrl } from '../../helpers/recipients';
|
|
8
|
+
|
|
9
|
+
var MemberAvatarWrapper = function MemberAvatarWrapper(_ref) {
|
|
10
|
+
var recipient = _ref.recipient,
|
|
11
|
+
avatarProps = _objectWithoutProperties(_ref, _excluded);
|
|
12
|
+
|
|
13
|
+
var client = useClient();
|
|
14
|
+
return /*#__PURE__*/React.createElement(MemberAvatar, _extends({
|
|
15
|
+
recipient: recipient,
|
|
16
|
+
avatarUrl: recipient ? makeAvatarUrl(recipient, client.options.uri) : null
|
|
17
|
+
}, avatarProps));
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export { MemberAvatarWrapper };
|
|
@@ -2,12 +2,14 @@ import _objectDestructuringEmpty from "@babel/runtime/helpers/objectDestructurin
|
|
|
2
2
|
import _extends from "@babel/runtime/helpers/extends";
|
|
3
3
|
import cx from 'classnames';
|
|
4
4
|
import React from 'react';
|
|
5
|
+
import { useClient } from 'cozy-client';
|
|
5
6
|
import List from 'cozy-ui/transpiled/react/List';
|
|
6
7
|
import Typography from 'cozy-ui/transpiled/react/Typography';
|
|
7
8
|
import useBreakpoints from 'cozy-ui/transpiled/react/providers/Breakpoints';
|
|
8
9
|
import { useI18n } from 'twake-i18n';
|
|
9
10
|
import MemberRecipient from './Recipient/MemberRecipient';
|
|
10
11
|
import ShareDialogTwoStepsConfirmationContainer from './ShareDialogTwoStepsConfirmationContainer';
|
|
12
|
+
import { makeAvatarUrl } from '../helpers/recipients';
|
|
11
13
|
/**
|
|
12
14
|
* Displays the sharing interface that can be used when ConfirmTrustedRecipientsDialog is in sharing state
|
|
13
15
|
*/
|
|
@@ -22,6 +24,7 @@ var SharingContent = function SharingContent(_ref) {
|
|
|
22
24
|
var _useBreakpoints = useBreakpoints(),
|
|
23
25
|
isMobile = _useBreakpoints.isMobile;
|
|
24
26
|
|
|
27
|
+
var client = useClient();
|
|
25
28
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Typography, {
|
|
26
29
|
variant: "body1",
|
|
27
30
|
className: cx('u-mb-half', isMobile ? 'u-ph-1 u-mt-1' : 'u-ph-2 u-mt-1-half')
|
|
@@ -32,7 +35,8 @@ var SharingContent = function SharingContent(_ref) {
|
|
|
32
35
|
key: "key_r_".concat(recipientConfirmationData.id),
|
|
33
36
|
isOwner: false,
|
|
34
37
|
recipientConfirmationData: recipientConfirmationData,
|
|
35
|
-
verifyRecipient: verifyRecipient
|
|
38
|
+
verifyRecipient: verifyRecipient,
|
|
39
|
+
avatarUrl: makeAvatarUrl(recipientConfirmationData, client.options.uri)
|
|
36
40
|
}));
|
|
37
41
|
})));
|
|
38
42
|
};
|
|
@@ -9,7 +9,8 @@ import { DOCTYPE_GROUPS, contactPropType, groupPropType, getDisplayName } from '
|
|
|
9
9
|
import { GroupAvatar } from './Avatar/GroupAvatar';
|
|
10
10
|
import { MemberAvatar } from './Avatar/MemberAvatar';
|
|
11
11
|
export var ContactSuggestion = function ContactSuggestion(_ref) {
|
|
12
|
-
var contactOrGroup = _ref.contactOrGroup
|
|
12
|
+
var contactOrGroup = _ref.contactOrGroup,
|
|
13
|
+
avatarUrl = _ref.avatarUrl;
|
|
13
14
|
|
|
14
15
|
var _useI18n = useI18n(),
|
|
15
16
|
t = _useI18n.t;
|
|
@@ -34,6 +35,7 @@ export var ContactSuggestion = function ContactSuggestion(_ref) {
|
|
|
34
35
|
button: true
|
|
35
36
|
}, /*#__PURE__*/React.createElement(ListItemIcon, null, /*#__PURE__*/React.createElement(MemberAvatar, {
|
|
36
37
|
recipient: contactOrGroup,
|
|
38
|
+
avatarUrl: avatarUrl,
|
|
37
39
|
size: "m"
|
|
38
40
|
})), /*#__PURE__*/React.createElement(ListItemText, {
|
|
39
41
|
primary: name,
|
|
@@ -46,6 +48,7 @@ var newUnknownContactProptypes = PropTypes.shape({
|
|
|
46
48
|
});
|
|
47
49
|
ContactSuggestion.propTypes = {
|
|
48
50
|
contactOrGroup: PropTypes.oneOfType([contactPropType, groupPropType, newUnknownContactProptypes]).isRequired,
|
|
49
|
-
contacts: PropTypes.arrayOf(contactPropType)
|
|
51
|
+
contacts: PropTypes.arrayOf(contactPropType),
|
|
52
|
+
avatarUrl: PropTypes.string
|
|
50
53
|
};
|
|
51
54
|
export default ContactSuggestion;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/extends";
|
|
2
2
|
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
|
|
3
|
-
var _excluded = ["instance", "isOwner", "status", "isCurrentUser", "recipientConfirmationData", "verifyRecipient", "fadeIn", "isOrgSharedDrive"];
|
|
3
|
+
var _excluded = ["instance", "isOwner", "status", "isCurrentUser", "recipientConfirmationData", "verifyRecipient", "fadeIn", "isOrgSharedDrive", "avatarUrl"];
|
|
4
4
|
import PropTypes from 'prop-types';
|
|
5
5
|
import React from 'react';
|
|
6
6
|
import Fade from 'cozy-ui/transpiled/react/Fade';
|
|
@@ -33,6 +33,7 @@ var MemberRecipient = function MemberRecipient(props) {
|
|
|
33
33
|
verifyRecipient = props.verifyRecipient,
|
|
34
34
|
fadeIn = props.fadeIn,
|
|
35
35
|
isOrgSharedDrive = props.isOrgSharedDrive,
|
|
36
|
+
avatarUrl = props.avatarUrl,
|
|
36
37
|
rest = _objectWithoutProperties(props, _excluded);
|
|
37
38
|
|
|
38
39
|
var isMe = isOwner && status === 'owner' || isCurrentUser;
|
|
@@ -55,7 +56,8 @@ var MemberRecipient = function MemberRecipient(props) {
|
|
|
55
56
|
size: "small"
|
|
56
57
|
}, /*#__PURE__*/React.createElement(ListItemIcon, null, /*#__PURE__*/React.createElement(MemberAvatar, {
|
|
57
58
|
size: "m",
|
|
58
|
-
recipient: props
|
|
59
|
+
recipient: props,
|
|
60
|
+
avatarUrl: avatarUrl
|
|
59
61
|
})), /*#__PURE__*/React.createElement(ListItemText, {
|
|
60
62
|
primary: /*#__PURE__*/React.createElement(Typography, {
|
|
61
63
|
variant: "body1"
|
|
@@ -78,6 +80,7 @@ MemberRecipient.propTypes = {
|
|
|
78
80
|
isCurrentUser: PropTypes.bool,
|
|
79
81
|
recipientConfirmationData: PropTypes.object,
|
|
80
82
|
verifyRecipient: PropTypes.func,
|
|
81
|
-
isOrgSharedDrive: PropTypes.bool
|
|
83
|
+
isOrgSharedDrive: PropTypes.bool,
|
|
84
|
+
avatarUrl: PropTypes.string
|
|
82
85
|
};
|
|
83
86
|
export default MemberRecipient;
|
|
@@ -2,19 +2,11 @@ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
|
2
2
|
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
3
3
|
import { render, fireEvent } from '@testing-library/react';
|
|
4
4
|
import React from 'react';
|
|
5
|
-
import { createMockClient } from 'cozy-client';
|
|
6
5
|
import MemberRecipient from './MemberRecipient';
|
|
7
6
|
import AppLike from '../../../test/AppLike';
|
|
8
7
|
describe('MemberRecipient component', function () {
|
|
9
|
-
var client = createMockClient({});
|
|
10
|
-
client.options = {
|
|
11
|
-
uri: 'foo.mycozy.cloud'
|
|
12
|
-
};
|
|
13
|
-
|
|
14
8
|
var setup = function setup(props) {
|
|
15
|
-
return render( /*#__PURE__*/React.createElement(AppLike,
|
|
16
|
-
client: client
|
|
17
|
-
}, /*#__PURE__*/React.createElement(MemberRecipient, props)));
|
|
9
|
+
return render( /*#__PURE__*/React.createElement(AppLike, null, /*#__PURE__*/React.createElement(MemberRecipient, props)));
|
|
18
10
|
};
|
|
19
11
|
|
|
20
12
|
var createRangeBackup;
|
|
@@ -13,7 +13,7 @@ import MemberRecipientStatus from './MemberRecipientStatus';
|
|
|
13
13
|
import { DEFAULT_DISPLAY_NAME } from '../../helpers/recipients';
|
|
14
14
|
import withLocales from '../../hoc/withLocales';
|
|
15
15
|
import { getDisplayName } from '../../models';
|
|
16
|
-
import {
|
|
16
|
+
import { MemberAvatarWrapper } from '../Avatar/MemberAvatarWrapper';
|
|
17
17
|
|
|
18
18
|
var MemberRecipientLite = function MemberRecipientLite(_ref) {
|
|
19
19
|
var _recipient$type;
|
|
@@ -31,7 +31,7 @@ var MemberRecipientLite = function MemberRecipientLite(_ref) {
|
|
|
31
31
|
return /*#__PURE__*/React.createElement(ListItem, {
|
|
32
32
|
size: "small",
|
|
33
33
|
ellipsis: true
|
|
34
|
-
}, /*#__PURE__*/React.createElement(ListItemIcon, null, /*#__PURE__*/React.createElement(
|
|
34
|
+
}, /*#__PURE__*/React.createElement(ListItemIcon, null, /*#__PURE__*/React.createElement(MemberAvatarWrapper, _extends({
|
|
35
35
|
size: "m",
|
|
36
36
|
recipient: recipient
|
|
37
37
|
}, props))), /*#__PURE__*/React.createElement(ListItemText, {
|
|
@@ -208,7 +208,9 @@ describe('PermissionTypeMenu component', function () {
|
|
|
208
208
|
}]
|
|
209
209
|
};
|
|
210
210
|
beforeEach(function () {
|
|
211
|
-
flag.
|
|
211
|
+
flag.mockImplementation(function (name) {
|
|
212
|
+
return name === 'drive.federated-shared-folder.enabled';
|
|
213
|
+
});
|
|
212
214
|
mockHasSharedParent.mockReturnValue(true);
|
|
213
215
|
mockGetSharingById.mockReturnValue({
|
|
214
216
|
id: 'sharing-123',
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
+
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
3
|
+
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
2
4
|
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
5
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
3
6
|
import PropTypes from 'prop-types';
|
|
4
|
-
import React, { useState, useRef } from 'react';
|
|
7
|
+
import React, { useEffect, useState, useRef } from 'react';
|
|
5
8
|
import Autosuggest from 'react-autosuggest';
|
|
6
9
|
import Chip from 'cozy-ui/transpiled/react/Chips';
|
|
7
10
|
import { Spinner } from 'cozy-ui/transpiled/react/Spinner';
|
|
@@ -10,6 +13,7 @@ import { MemberAvatar } from './Avatar/MemberAvatar';
|
|
|
10
13
|
import ContactSuggestion from './ContactSuggestion';
|
|
11
14
|
import { isContactToBeCreated } from '../helpers/contacts';
|
|
12
15
|
import { extractEmails, validateEmail } from '../helpers/email';
|
|
16
|
+
import logger from '../logger';
|
|
13
17
|
import { getDisplayName, DOCTYPE_CONTACTS, DOCTYPE_GROUPS } from '../models';
|
|
14
18
|
var styles = {
|
|
15
19
|
"container": "autosuggest__container___1Yro7",
|
|
@@ -24,6 +28,8 @@ var styles = {
|
|
|
24
28
|
"endAdornment": "autosuggest__endAdornment___2EwTN"
|
|
25
29
|
};
|
|
26
30
|
import { contactOrGroupMatch } from '../suggestionMatchers';
|
|
31
|
+
var FETCH_CONTACTS_DEBOUNCE = 300;
|
|
32
|
+
var FETCH_CONTACTS_MIN_LENGTH = 3;
|
|
27
33
|
|
|
28
34
|
var ShareAutosuggest = function ShareAutosuggest(_ref) {
|
|
29
35
|
var loading = _ref.loading,
|
|
@@ -35,7 +41,9 @@ var ShareAutosuggest = function ShareAutosuggest(_ref) {
|
|
|
35
41
|
enableCreateContact = _ref.enableCreateContact,
|
|
36
42
|
placeholder = _ref.placeholder,
|
|
37
43
|
autoFocus = _ref.autoFocus,
|
|
38
|
-
endAdornment = _ref.endAdornment
|
|
44
|
+
endAdornment = _ref.endAdornment,
|
|
45
|
+
fetchContacts = _ref.fetchContacts,
|
|
46
|
+
getAvatarUrl = _ref.getAvatarUrl;
|
|
39
47
|
|
|
40
48
|
var _useState = useState(''),
|
|
41
49
|
_useState2 = _slicedToArray(_useState, 2),
|
|
@@ -57,8 +65,20 @@ var ShareAutosuggest = function ShareAutosuggest(_ref) {
|
|
|
57
65
|
isLoadingDisplayed = _useState8[0],
|
|
58
66
|
setLoadingDisplayed = _useState8[1];
|
|
59
67
|
|
|
68
|
+
var _useState9 = useState(false),
|
|
69
|
+
_useState10 = _slicedToArray(_useState9, 2),
|
|
70
|
+
isFetching = _useState10[0],
|
|
71
|
+
setIsFetching = _useState10[1];
|
|
72
|
+
|
|
60
73
|
var autosuggestRef = useRef(null);
|
|
61
74
|
var containerRef = useRef(null);
|
|
75
|
+
var fetchTimeoutRef = useRef(null);
|
|
76
|
+
var fetchedValueRef = useRef(null);
|
|
77
|
+
useEffect(function () {
|
|
78
|
+
return function () {
|
|
79
|
+
return clearTimeout(fetchTimeoutRef.current);
|
|
80
|
+
};
|
|
81
|
+
}, []);
|
|
62
82
|
|
|
63
83
|
var computeSuggestions = function computeSuggestions(value) {
|
|
64
84
|
var inputValue = value.trim().toLowerCase();
|
|
@@ -67,10 +87,7 @@ var ShareAutosuggest = function ShareAutosuggest(_ref) {
|
|
|
67
87
|
});
|
|
68
88
|
};
|
|
69
89
|
|
|
70
|
-
var
|
|
71
|
-
var value = _ref2.value;
|
|
72
|
-
var computedSuggestions = computeSuggestions(value);
|
|
73
|
-
|
|
90
|
+
var showSuggestions = function showSuggestions(computedSuggestions, value) {
|
|
74
91
|
if (computedSuggestions.length > 0) {
|
|
75
92
|
setSuggestions(computedSuggestions);
|
|
76
93
|
} else if (enableCreateContact && validateEmail(value)) {
|
|
@@ -83,7 +100,63 @@ var ShareAutosuggest = function ShareAutosuggest(_ref) {
|
|
|
83
100
|
}
|
|
84
101
|
};
|
|
85
102
|
|
|
103
|
+
var onSuggestionsFetchRequested = function onSuggestionsFetchRequested(_ref2) {
|
|
104
|
+
var value = _ref2.value;
|
|
105
|
+
var computedSuggestions = computeSuggestions(value);
|
|
106
|
+
clearTimeout(fetchTimeoutRef.current);
|
|
107
|
+
fetchedValueRef.current = value;
|
|
108
|
+
|
|
109
|
+
if (!fetchContacts || value.trim().length < FETCH_CONTACTS_MIN_LENGTH) {
|
|
110
|
+
setIsFetching(false);
|
|
111
|
+
showSuggestions(computedSuggestions, value);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
setIsFetching(true);
|
|
116
|
+
fetchTimeoutRef.current = setTimeout( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
117
|
+
var contacts;
|
|
118
|
+
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
119
|
+
while (1) switch (_context.prev = _context.next) {
|
|
120
|
+
case 0:
|
|
121
|
+
contacts = [];
|
|
122
|
+
_context.prev = 1;
|
|
123
|
+
_context.next = 4;
|
|
124
|
+
return fetchContacts(value.trim());
|
|
125
|
+
|
|
126
|
+
case 4:
|
|
127
|
+
contacts = _context.sent;
|
|
128
|
+
_context.next = 10;
|
|
129
|
+
break;
|
|
130
|
+
|
|
131
|
+
case 7:
|
|
132
|
+
_context.prev = 7;
|
|
133
|
+
_context.t0 = _context["catch"](1);
|
|
134
|
+
logger.error('Failed to fetch contact suggestions', _context.t0);
|
|
135
|
+
|
|
136
|
+
case 10:
|
|
137
|
+
if (!(fetchedValueRef.current !== value)) {
|
|
138
|
+
_context.next = 12;
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return _context.abrupt("return");
|
|
143
|
+
|
|
144
|
+
case 12:
|
|
145
|
+
setIsFetching(false);
|
|
146
|
+
showSuggestions([].concat(_toConsumableArray(contacts), _toConsumableArray(computedSuggestions)), value);
|
|
147
|
+
|
|
148
|
+
case 14:
|
|
149
|
+
case "end":
|
|
150
|
+
return _context.stop();
|
|
151
|
+
}
|
|
152
|
+
}, _callee, null, [[1, 7]]);
|
|
153
|
+
})), FETCH_CONTACTS_DEBOUNCE);
|
|
154
|
+
};
|
|
155
|
+
|
|
86
156
|
var onSuggestionsClearRequested = function onSuggestionsClearRequested() {
|
|
157
|
+
clearTimeout(fetchTimeoutRef.current);
|
|
158
|
+
fetchedValueRef.current = null;
|
|
159
|
+
setIsFetching(false);
|
|
87
160
|
setSuggestions([]);
|
|
88
161
|
};
|
|
89
162
|
|
|
@@ -91,9 +164,9 @@ var ShareAutosuggest = function ShareAutosuggest(_ref) {
|
|
|
91
164
|
setIsPasted(true);
|
|
92
165
|
};
|
|
93
166
|
|
|
94
|
-
var onAutosuggestChange = function onAutosuggestChange(event,
|
|
95
|
-
var newValue =
|
|
96
|
-
method =
|
|
167
|
+
var onAutosuggestChange = function onAutosuggestChange(event, _ref4) {
|
|
168
|
+
var newValue = _ref4.newValue,
|
|
169
|
+
method = _ref4.method;
|
|
97
170
|
|
|
98
171
|
if (isPasted) {
|
|
99
172
|
var emails = extractEmails(newValue);
|
|
@@ -126,9 +199,9 @@ var ShareAutosuggest = function ShareAutosuggest(_ref) {
|
|
|
126
199
|
}
|
|
127
200
|
};
|
|
128
201
|
|
|
129
|
-
var onKeyUp = function onKeyUp(
|
|
130
|
-
var key =
|
|
131
|
-
keyCode =
|
|
202
|
+
var onKeyUp = function onKeyUp(_ref5) {
|
|
203
|
+
var key = _ref5.key,
|
|
204
|
+
keyCode = _ref5.keyCode;
|
|
132
205
|
|
|
133
206
|
if (recipients.length > 0 && inputValue === '' && (key === 'Backspace' || keyCode === 8 || key === 'Delete' || keyCode === 46)) {
|
|
134
207
|
document.getElementById("recipient_".concat(recipients.length - 1)).focus();
|
|
@@ -191,7 +264,8 @@ var ShareAutosuggest = function ShareAutosuggest(_ref) {
|
|
|
191
264
|
color: recipient.color
|
|
192
265
|
}) : /*#__PURE__*/React.createElement(MemberAvatar, {
|
|
193
266
|
size: "xs",
|
|
194
|
-
recipient: recipient
|
|
267
|
+
recipient: recipient,
|
|
268
|
+
avatarUrl: getAvatarUrl(recipient)
|
|
195
269
|
}),
|
|
196
270
|
label: name,
|
|
197
271
|
onDelete: function onDelete() {
|
|
@@ -202,7 +276,7 @@ var ShareAutosuggest = function ShareAutosuggest(_ref) {
|
|
|
202
276
|
}), /*#__PURE__*/React.createElement("input", _extends({}, inputProps, {
|
|
203
277
|
onKeyPress: onKeyPress,
|
|
204
278
|
onKeyUp: onKeyUp
|
|
205
|
-
})), loading && isLoadingDisplayed ? /*#__PURE__*/React.createElement(Spinner, {
|
|
279
|
+
})), (loading || isFetching) && isLoadingDisplayed ? /*#__PURE__*/React.createElement(Spinner, {
|
|
206
280
|
color: "var(--primaryColor)"
|
|
207
281
|
}) : null, endAdornment ? /*#__PURE__*/React.createElement("div", {
|
|
208
282
|
className: styles['endAdornment']
|
|
@@ -211,7 +285,8 @@ var ShareAutosuggest = function ShareAutosuggest(_ref) {
|
|
|
211
285
|
|
|
212
286
|
var renderSuggestion = function renderSuggestion(contactOrGroup) {
|
|
213
287
|
return /*#__PURE__*/React.createElement(ContactSuggestion, {
|
|
214
|
-
contactOrGroup: contactOrGroup
|
|
288
|
+
contactOrGroup: contactOrGroup,
|
|
289
|
+
avatarUrl: getAvatarUrl(contactOrGroup)
|
|
215
290
|
});
|
|
216
291
|
};
|
|
217
292
|
|
|
@@ -258,6 +333,8 @@ ShareAutosuggest.propTypes = {
|
|
|
258
333
|
enableCreateContact: PropTypes.bool,
|
|
259
334
|
placeholder: PropTypes.string,
|
|
260
335
|
autoFocus: PropTypes.bool,
|
|
261
|
-
endAdornment: PropTypes.node
|
|
336
|
+
endAdornment: PropTypes.node,
|
|
337
|
+
fetchContacts: PropTypes.func,
|
|
338
|
+
getAvatarUrl: PropTypes.func.isRequired
|
|
262
339
|
};
|
|
263
340
|
export default ShareAutosuggest;
|