cozy-sharing 30.3.0 → 31.0.0
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 +18 -0
- package/dist/components/ShareModal/EditableSharingModal.js +0 -2
- package/dist/components/ShareModal.js +0 -16
- package/dist/components/SharedDrive/SharedDriveForm.js +75 -0
- package/dist/components/SharedDrive/SharedDriveModal.js +19 -169
- package/dist/components/SharedDrive/helpers.js +2 -2
- package/dist/components/SharedDrive/helpers.spec.js +19 -0
- package/dist/components/SharedDrive/useSharedDrive.js +126 -0
- package/dist/components/SharedDrive/useSharedDrive.spec.js +252 -0
- package/dist/index.js +1 -0
- package/package.json +4 -4
- package/src/components/ShareModal/EditableSharingModal.jsx +0 -2
- package/src/components/ShareModal.jsx +0 -17
- package/src/components/SharedDrive/SharedDriveForm.jsx +81 -0
- package/src/components/SharedDrive/SharedDriveModal.jsx +12 -128
- package/src/components/SharedDrive/helpers.js +2 -2
- package/src/components/SharedDrive/helpers.spec.js +16 -0
- package/src/components/SharedDrive/useSharedDrive.js +98 -0
- package/src/components/SharedDrive/useSharedDrive.spec.js +155 -0
- package/src/index.jsx +1 -0
- package/dist/components/SharedDrive/DumbSharedDriveModal.js +0 -78
- package/dist/components/SharedDrive/SharedDriveEditModal.js +0 -110
- package/src/components/SharedDrive/DumbSharedDriveModal.jsx +0 -84
- package/src/components/SharedDrive/SharedDriveEditModal.jsx +0 -79
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
2
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
3
|
+
import { renderHook, act } from '@testing-library/react-hooks';
|
|
4
|
+
import { useSharedDrive } from './useSharedDrive';
|
|
5
|
+
var mockShowAlert = jest.fn();
|
|
6
|
+
var mockCreateSharedDrive = jest.fn();
|
|
7
|
+
var mockCollection = jest.fn(function () {
|
|
8
|
+
return {
|
|
9
|
+
createSharedDrive: mockCreateSharedDrive
|
|
10
|
+
};
|
|
11
|
+
});
|
|
12
|
+
var mockT = jest.fn(function (key) {
|
|
13
|
+
return key;
|
|
14
|
+
});
|
|
15
|
+
jest.mock('cozy-client', function () {
|
|
16
|
+
return {
|
|
17
|
+
useClient: jest.fn(function () {
|
|
18
|
+
return {
|
|
19
|
+
collection: mockCollection
|
|
20
|
+
};
|
|
21
|
+
}),
|
|
22
|
+
models: {
|
|
23
|
+
contact: {
|
|
24
|
+
getPrimaryEmail: jest.fn(function (r) {
|
|
25
|
+
return Array.isArray(r.email) && r.email[0] ? r.email[0].address : '';
|
|
26
|
+
}),
|
|
27
|
+
getDisplayName: jest.fn(function (r) {
|
|
28
|
+
return r.displayName || r.name || '';
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
jest.mock('cozy-ui/transpiled/react/providers/Alert', function () {
|
|
35
|
+
return {
|
|
36
|
+
useAlert: jest.fn(function () {
|
|
37
|
+
return {
|
|
38
|
+
showAlert: mockShowAlert
|
|
39
|
+
};
|
|
40
|
+
})
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
jest.mock('twake-i18n', function () {
|
|
44
|
+
return {
|
|
45
|
+
useI18n: jest.fn(function () {
|
|
46
|
+
return {
|
|
47
|
+
t: mockT
|
|
48
|
+
};
|
|
49
|
+
})
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
jest.mock('../../models', function () {
|
|
53
|
+
return {
|
|
54
|
+
Contact: {
|
|
55
|
+
doctype: 'io.cozy.contacts'
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
describe('useSharedDrive', function () {
|
|
60
|
+
beforeEach(function () {
|
|
61
|
+
jest.clearAllMocks();
|
|
62
|
+
});
|
|
63
|
+
it('returns empty initial state', function () {
|
|
64
|
+
var _renderHook = renderHook(function () {
|
|
65
|
+
return useSharedDrive({
|
|
66
|
+
onSuccess: jest.fn()
|
|
67
|
+
});
|
|
68
|
+
}),
|
|
69
|
+
result = _renderHook.result;
|
|
70
|
+
|
|
71
|
+
expect(result.current.sharedDriveName).toBe('');
|
|
72
|
+
expect(result.current.recipients).toEqual([]);
|
|
73
|
+
});
|
|
74
|
+
it('handleSharedDriveNameChange updates the name', function () {
|
|
75
|
+
var _renderHook2 = renderHook(function () {
|
|
76
|
+
return useSharedDrive({
|
|
77
|
+
onSuccess: jest.fn()
|
|
78
|
+
});
|
|
79
|
+
}),
|
|
80
|
+
result = _renderHook2.result;
|
|
81
|
+
|
|
82
|
+
act(function () {
|
|
83
|
+
result.current.handleSharedDriveNameChange({
|
|
84
|
+
target: {
|
|
85
|
+
value: 'My Drive'
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
expect(result.current.sharedDriveName).toBe('My Drive');
|
|
90
|
+
});
|
|
91
|
+
it('onRevoke removes a recipient from both lists', function () {
|
|
92
|
+
var _renderHook3 = renderHook(function () {
|
|
93
|
+
return useSharedDrive({
|
|
94
|
+
onSuccess: jest.fn()
|
|
95
|
+
});
|
|
96
|
+
}),
|
|
97
|
+
result = _renderHook3.result;
|
|
98
|
+
|
|
99
|
+
act(function () {
|
|
100
|
+
result.current.onShare({
|
|
101
|
+
recipients: [{
|
|
102
|
+
_id: 'abc',
|
|
103
|
+
displayName: 'Alice',
|
|
104
|
+
email: []
|
|
105
|
+
}],
|
|
106
|
+
readOnlyRecipients: []
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
act(function () {
|
|
110
|
+
result.current.onRevoke("virtual-shared-drive-sharing-abc");
|
|
111
|
+
});
|
|
112
|
+
expect(result.current.recipients).toHaveLength(0);
|
|
113
|
+
});
|
|
114
|
+
it('onSetType moves a recipient to read-only', function () {
|
|
115
|
+
var _renderHook4 = renderHook(function () {
|
|
116
|
+
return useSharedDrive({
|
|
117
|
+
onSuccess: jest.fn()
|
|
118
|
+
});
|
|
119
|
+
}),
|
|
120
|
+
result = _renderHook4.result;
|
|
121
|
+
|
|
122
|
+
act(function () {
|
|
123
|
+
result.current.onShare({
|
|
124
|
+
recipients: [{
|
|
125
|
+
_id: 'abc',
|
|
126
|
+
displayName: 'Alice',
|
|
127
|
+
email: []
|
|
128
|
+
}],
|
|
129
|
+
readOnlyRecipients: []
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
act(function () {
|
|
133
|
+
result.current.onSetType("virtual-shared-drive-sharing-abc", 'one-way');
|
|
134
|
+
});
|
|
135
|
+
expect(result.current.recipients[0].type).toBe('one-way');
|
|
136
|
+
});
|
|
137
|
+
it('onSetType moves a recipient to read-write', function () {
|
|
138
|
+
var _renderHook5 = renderHook(function () {
|
|
139
|
+
return useSharedDrive({
|
|
140
|
+
onSuccess: jest.fn()
|
|
141
|
+
});
|
|
142
|
+
}),
|
|
143
|
+
result = _renderHook5.result;
|
|
144
|
+
|
|
145
|
+
act(function () {
|
|
146
|
+
result.current.onShare({
|
|
147
|
+
recipients: [],
|
|
148
|
+
readOnlyRecipients: [{
|
|
149
|
+
_id: 'xyz',
|
|
150
|
+
displayName: 'Bob',
|
|
151
|
+
email: []
|
|
152
|
+
}]
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
act(function () {
|
|
156
|
+
result.current.onSetType("virtual-shared-drive-sharing-xyz", 'two-way');
|
|
157
|
+
});
|
|
158
|
+
expect(result.current.recipients).toHaveLength(1);
|
|
159
|
+
expect(result.current.recipients[0].type).toBe('two-way');
|
|
160
|
+
});
|
|
161
|
+
it('onCreate calls createSharedDrive, showAlert with success, and onSuccess', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
|
|
162
|
+
var onSuccess, _renderHook6, result;
|
|
163
|
+
|
|
164
|
+
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
|
|
165
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
166
|
+
case 0:
|
|
167
|
+
onSuccess = jest.fn();
|
|
168
|
+
mockCreateSharedDrive.mockResolvedValue({});
|
|
169
|
+
_renderHook6 = renderHook(function () {
|
|
170
|
+
return useSharedDrive({
|
|
171
|
+
onSuccess: onSuccess
|
|
172
|
+
});
|
|
173
|
+
}), result = _renderHook6.result;
|
|
174
|
+
act(function () {
|
|
175
|
+
result.current.handleSharedDriveNameChange({
|
|
176
|
+
target: {
|
|
177
|
+
value: 'My Drive'
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
_context2.next = 6;
|
|
182
|
+
return act( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
183
|
+
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
184
|
+
while (1) switch (_context.prev = _context.next) {
|
|
185
|
+
case 0:
|
|
186
|
+
_context.next = 2;
|
|
187
|
+
return result.current.onCreate();
|
|
188
|
+
|
|
189
|
+
case 2:
|
|
190
|
+
case "end":
|
|
191
|
+
return _context.stop();
|
|
192
|
+
}
|
|
193
|
+
}, _callee);
|
|
194
|
+
})));
|
|
195
|
+
|
|
196
|
+
case 6:
|
|
197
|
+
expect(mockCreateSharedDrive).toHaveBeenCalledWith(expect.objectContaining({
|
|
198
|
+
name: 'My Drive',
|
|
199
|
+
description: 'My Drive'
|
|
200
|
+
}));
|
|
201
|
+
expect(mockShowAlert).toHaveBeenCalledWith(expect.objectContaining({
|
|
202
|
+
severity: 'success'
|
|
203
|
+
}));
|
|
204
|
+
expect(onSuccess).toHaveBeenCalledTimes(1);
|
|
205
|
+
|
|
206
|
+
case 9:
|
|
207
|
+
case "end":
|
|
208
|
+
return _context2.stop();
|
|
209
|
+
}
|
|
210
|
+
}, _callee2);
|
|
211
|
+
})));
|
|
212
|
+
it('onCreate shows error alert and does not call onSuccess on failure', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
|
|
213
|
+
var onSuccess, _renderHook7, result;
|
|
214
|
+
|
|
215
|
+
return _regeneratorRuntime.wrap(function _callee4$(_context4) {
|
|
216
|
+
while (1) switch (_context4.prev = _context4.next) {
|
|
217
|
+
case 0:
|
|
218
|
+
onSuccess = jest.fn();
|
|
219
|
+
mockCreateSharedDrive.mockRejectedValue(new Error('network error'));
|
|
220
|
+
_renderHook7 = renderHook(function () {
|
|
221
|
+
return useSharedDrive({
|
|
222
|
+
onSuccess: onSuccess
|
|
223
|
+
});
|
|
224
|
+
}), result = _renderHook7.result;
|
|
225
|
+
_context4.next = 5;
|
|
226
|
+
return act( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
|
|
227
|
+
return _regeneratorRuntime.wrap(function _callee3$(_context3) {
|
|
228
|
+
while (1) switch (_context3.prev = _context3.next) {
|
|
229
|
+
case 0:
|
|
230
|
+
_context3.next = 2;
|
|
231
|
+
return result.current.onCreate();
|
|
232
|
+
|
|
233
|
+
case 2:
|
|
234
|
+
case "end":
|
|
235
|
+
return _context3.stop();
|
|
236
|
+
}
|
|
237
|
+
}, _callee3);
|
|
238
|
+
})));
|
|
239
|
+
|
|
240
|
+
case 5:
|
|
241
|
+
expect(mockShowAlert).toHaveBeenCalledWith(expect.objectContaining({
|
|
242
|
+
severity: 'error'
|
|
243
|
+
}));
|
|
244
|
+
expect(onSuccess).not.toHaveBeenCalled();
|
|
245
|
+
|
|
246
|
+
case 7:
|
|
247
|
+
case "end":
|
|
248
|
+
return _context4.stop();
|
|
249
|
+
}
|
|
250
|
+
}, _callee4);
|
|
251
|
+
})));
|
|
252
|
+
});
|
package/dist/index.js
CHANGED
|
@@ -16,6 +16,7 @@ export { default as OwnerRecipientDefaultLite } from './components/Recipient/Own
|
|
|
16
16
|
export { SharedRecipientsList } from './SharedRecipientsList';
|
|
17
17
|
export { ShareButton } from './ShareButton';
|
|
18
18
|
export { SharedDriveModal } from './components/SharedDrive/SharedDriveModal';
|
|
19
|
+
export { SharedDriveForm } from './components/SharedDrive/SharedDriveForm';
|
|
19
20
|
export { FederatedFolderModal } from './components/FederatedFolder/FederatedFolderModal';
|
|
20
21
|
export { ShareModal } from './components/ShareModal/ShareModal';
|
|
21
22
|
export { RefreshableSharings } from './RefreshableSharings';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cozy-sharing",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "31.0.0",
|
|
4
4
|
"description": "Provides sharing login for React applications.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"author": "Cozy",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"babel-jest": "30.3.0",
|
|
55
55
|
"babel-plugin-css-modules-transform": "1.6.2",
|
|
56
56
|
"babel-plugin-inline-react-svg": "1.1.2",
|
|
57
|
-
"cozy-client": "^60.
|
|
57
|
+
"cozy-client": "^60.24.0",
|
|
58
58
|
"cozy-device-helper": "^3.7.1",
|
|
59
59
|
"cozy-intent": "^2.31.1",
|
|
60
60
|
"cozy-minilog": "^3.10.1",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"twake-i18n": "^0.4.1"
|
|
70
70
|
},
|
|
71
71
|
"peerDependencies": {
|
|
72
|
-
"cozy-client": ">=60.
|
|
72
|
+
"cozy-client": ">=60.24.0",
|
|
73
73
|
"cozy-device-helper": ">=3.7.1",
|
|
74
74
|
"cozy-flags": ">=4.8.1",
|
|
75
75
|
"cozy-intent": ">=2.29.1",
|
|
@@ -84,5 +84,5 @@
|
|
|
84
84
|
"sideEffects": [
|
|
85
85
|
"*.css"
|
|
86
86
|
],
|
|
87
|
-
"gitHead": "
|
|
87
|
+
"gitHead": "435fe26df7f273dda07330473eb1f638f0f1277a"
|
|
88
88
|
}
|
|
@@ -21,7 +21,6 @@ export const EditableSharingModal = ({ document, ...rest }) => {
|
|
|
21
21
|
hasSharedChild,
|
|
22
22
|
hasSharedParent,
|
|
23
23
|
isOwner,
|
|
24
|
-
isSharedDrive,
|
|
25
24
|
revoke,
|
|
26
25
|
revokeSelf,
|
|
27
26
|
share
|
|
@@ -35,7 +34,6 @@ export const EditableSharingModal = ({ document, ...rest }) => {
|
|
|
35
34
|
hasSharedChild={documentPath && hasSharedChild(documentPath)}
|
|
36
35
|
hasSharedParent={documentPath && hasSharedParent(documentPath)}
|
|
37
36
|
isOwner={isOwner(document._id)}
|
|
38
|
-
isSharedDrive={isSharedDrive(document._id)}
|
|
39
37
|
link={getSharingLink(document._id)}
|
|
40
38
|
onRevoke={revoke}
|
|
41
39
|
onRevokeSelf={revokeSelf}
|
|
@@ -5,7 +5,6 @@ import flag from 'cozy-flags'
|
|
|
5
5
|
|
|
6
6
|
import ShareDialogCozyToCozy from './ShareDialogCozyToCozy'
|
|
7
7
|
import ShareDialogOnlyByLink from './ShareDialogOnlyByLink'
|
|
8
|
-
import { SharedDriveEditModal } from './SharedDrive/SharedDriveEditModal'
|
|
9
8
|
|
|
10
9
|
export const ShareModal = ({
|
|
11
10
|
autoOpenShareRestriction,
|
|
@@ -15,7 +14,6 @@ export const ShareModal = ({
|
|
|
15
14
|
hasSharedChild,
|
|
16
15
|
hasSharedParent,
|
|
17
16
|
isOwner,
|
|
18
|
-
isSharedDrive,
|
|
19
17
|
link,
|
|
20
18
|
onClose,
|
|
21
19
|
onRevoke,
|
|
@@ -28,21 +26,6 @@ export const ShareModal = ({
|
|
|
28
26
|
showGenerateLinkButton,
|
|
29
27
|
twoStepsConfirmationMethods
|
|
30
28
|
}) => {
|
|
31
|
-
if (isSharedDrive && !flag('drive.federated-shared-folder.enabled')) {
|
|
32
|
-
return (
|
|
33
|
-
<SharedDriveEditModal
|
|
34
|
-
document={document}
|
|
35
|
-
sharing={sharing}
|
|
36
|
-
recipients={recipients}
|
|
37
|
-
onShare={onShare}
|
|
38
|
-
onRevoke={onRevoke}
|
|
39
|
-
onClose={onClose}
|
|
40
|
-
autoOpenShareRestriction={autoOpenShareRestriction}
|
|
41
|
-
showGenerateLinkButton={showGenerateLinkButton}
|
|
42
|
-
/>
|
|
43
|
-
)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
29
|
const shareDialogOnlyByLink =
|
|
47
30
|
flag('cozy.hide-sharing-cozy-to-cozy') || documentType === 'Albums'
|
|
48
31
|
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import PropTypes from 'prop-types'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
import Button from 'cozy-ui/transpiled/react/Buttons'
|
|
5
|
+
import TextField from 'cozy-ui/transpiled/react/TextField'
|
|
6
|
+
import Typography from 'cozy-ui/transpiled/react/Typography'
|
|
7
|
+
import { useI18n } from 'twake-i18n'
|
|
8
|
+
|
|
9
|
+
import withLocales from '../../hoc/withLocales'
|
|
10
|
+
import { default as DumbShareByEmail } from '../ShareByEmail'
|
|
11
|
+
import WhoHasAccess from '../WhoHasAccess'
|
|
12
|
+
import { useSharedDrive } from './useSharedDrive'
|
|
13
|
+
|
|
14
|
+
export const SharedDriveForm = withLocales(({ onSuccess, onCancel }) => {
|
|
15
|
+
const { t } = useI18n()
|
|
16
|
+
const {
|
|
17
|
+
sharedDriveName,
|
|
18
|
+
recipients,
|
|
19
|
+
handleSharedDriveNameChange,
|
|
20
|
+
onShare,
|
|
21
|
+
onCreate,
|
|
22
|
+
onSetType,
|
|
23
|
+
onRevoke,
|
|
24
|
+
createContact
|
|
25
|
+
} = useSharedDrive({ onSuccess })
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<div>
|
|
29
|
+
<div className="u-ph-2">
|
|
30
|
+
<TextField
|
|
31
|
+
required
|
|
32
|
+
label={t('SharedDrive.sharedDriveModal.nameLabel')}
|
|
33
|
+
variant="outlined"
|
|
34
|
+
size="small"
|
|
35
|
+
className="u-w-100 u-mt-1-half"
|
|
36
|
+
value={sharedDriveName}
|
|
37
|
+
onChange={handleSharedDriveNameChange}
|
|
38
|
+
/>
|
|
39
|
+
<Typography variant="h6" className="u-mt-1-half u-mb-half">
|
|
40
|
+
{t('SharedDrive.sharedDriveModal.addPeople')}
|
|
41
|
+
</Typography>
|
|
42
|
+
<DumbShareByEmail
|
|
43
|
+
createContact={createContact}
|
|
44
|
+
currentRecipients={recipients}
|
|
45
|
+
documentType="Files"
|
|
46
|
+
sharedDrive
|
|
47
|
+
onShare={onShare}
|
|
48
|
+
submitLabel={t('SharedDrive.sharedDriveModal.add')}
|
|
49
|
+
showNotifications={false}
|
|
50
|
+
sharingDesc=""
|
|
51
|
+
/>
|
|
52
|
+
</div>
|
|
53
|
+
<WhoHasAccess
|
|
54
|
+
isOwner
|
|
55
|
+
isSharedDrive
|
|
56
|
+
recipients={recipients}
|
|
57
|
+
documentType="Files"
|
|
58
|
+
className="u-w-100"
|
|
59
|
+
onRevoke={onRevoke}
|
|
60
|
+
onSetType={onSetType}
|
|
61
|
+
/>
|
|
62
|
+
<div className="u-flex u-flex-justify-end u-ph-2 u-pv-1 u-column-gap-half">
|
|
63
|
+
<Button
|
|
64
|
+
variant="secondary"
|
|
65
|
+
label={t('SharedDrive.sharedDriveModal.cancel')}
|
|
66
|
+
onClick={onCancel}
|
|
67
|
+
/>
|
|
68
|
+
<Button
|
|
69
|
+
variant="primary"
|
|
70
|
+
label={t('SharedDrive.sharedDriveModal.create')}
|
|
71
|
+
onClick={onCreate}
|
|
72
|
+
/>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
)
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
SharedDriveForm.propTypes = {
|
|
79
|
+
onSuccess: PropTypes.func.isRequired,
|
|
80
|
+
onCancel: PropTypes.func.isRequired
|
|
81
|
+
}
|
|
@@ -1,141 +1,25 @@
|
|
|
1
1
|
import PropTypes from 'prop-types'
|
|
2
|
-
import React
|
|
2
|
+
import React from 'react'
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import { useAlert } from 'cozy-ui/transpiled/react/providers/Alert'
|
|
4
|
+
import { FixedDialog } from 'cozy-ui/transpiled/react/CozyDialogs'
|
|
6
5
|
import { useI18n } from 'twake-i18n'
|
|
7
6
|
|
|
8
|
-
import { DumbSharedDriveModal } from './DumbSharedDriveModal'
|
|
9
|
-
import {
|
|
10
|
-
mergeAndDeduplicateRecipients,
|
|
11
|
-
formatRecipients,
|
|
12
|
-
RECIPIENT_INDEX_PREFIX
|
|
13
|
-
} from './helpers'
|
|
14
7
|
import withLocales from '../../hoc/withLocales'
|
|
15
|
-
import {
|
|
16
|
-
import { Contact } from '../../models'
|
|
8
|
+
import { SharedDriveForm } from './SharedDriveForm'
|
|
17
9
|
|
|
18
10
|
export const SharedDriveModal = withLocales(({ onClose }) => {
|
|
19
|
-
const client = useClient()
|
|
20
11
|
const { t } = useI18n()
|
|
21
|
-
const { share } = useSharingContext()
|
|
22
|
-
const { showAlert } = useAlert()
|
|
23
|
-
|
|
24
|
-
const [sharedDriveRecipients, setSharedDriveRecipients] = useState({
|
|
25
|
-
recipients: [],
|
|
26
|
-
readOnlyRecipients: []
|
|
27
|
-
})
|
|
28
|
-
const [sharedDriveName, setSharedDriveName] = useState('')
|
|
29
|
-
|
|
30
|
-
const onShare = params => {
|
|
31
|
-
setSharedDriveRecipients({
|
|
32
|
-
recipients: mergeAndDeduplicateRecipients([
|
|
33
|
-
sharedDriveRecipients.recipients,
|
|
34
|
-
params.recipients
|
|
35
|
-
]),
|
|
36
|
-
readOnlyRecipients: mergeAndDeduplicateRecipients([
|
|
37
|
-
sharedDriveRecipients.readOnlyRecipients,
|
|
38
|
-
params.readOnlyRecipients
|
|
39
|
-
])
|
|
40
|
-
})
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const handleSharedDriveNameChange = event => {
|
|
44
|
-
setSharedDriveName(event.target.value)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const onCreate = async () => {
|
|
48
|
-
try {
|
|
49
|
-
await client
|
|
50
|
-
.collection('io.cozy.files')
|
|
51
|
-
.getOrCreateSharedDrivesDirectory()
|
|
52
|
-
const { data: sharedDriveFolder } = await client.create('io.cozy.files', {
|
|
53
|
-
name: sharedDriveName,
|
|
54
|
-
dirId: 'io.cozy.files.shared-drives-dir',
|
|
55
|
-
type: 'directory'
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
await share({
|
|
59
|
-
description: sharedDriveName,
|
|
60
|
-
document: sharedDriveFolder,
|
|
61
|
-
recipients: sharedDriveRecipients.recipients,
|
|
62
|
-
readOnlyRecipients: sharedDriveRecipients.readOnlyRecipients,
|
|
63
|
-
sharedDrive: true,
|
|
64
|
-
openSharing: false
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
showAlert({
|
|
68
|
-
message: t('SharedDrive.sharedDriveModal.successNotification'),
|
|
69
|
-
severity: 'success',
|
|
70
|
-
variant: 'filled'
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
onClose()
|
|
74
|
-
} catch (_err) {
|
|
75
|
-
showAlert({
|
|
76
|
-
message: t('SharedDrive.sharedDriveModal.errorNotification'),
|
|
77
|
-
severity: 'error',
|
|
78
|
-
variant: 'filled'
|
|
79
|
-
})
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const onSetType = (index, newType) => {
|
|
84
|
-
const _id = index.split(RECIPIENT_INDEX_PREFIX)[1]
|
|
85
|
-
|
|
86
|
-
if (newType === 'two-way') {
|
|
87
|
-
setSharedDriveRecipients(prev => {
|
|
88
|
-
const recipientToMove = prev.readOnlyRecipients.find(r => r._id === _id)
|
|
89
|
-
|
|
90
|
-
return {
|
|
91
|
-
recipients: [...prev.recipients, recipientToMove],
|
|
92
|
-
readOnlyRecipients: prev.readOnlyRecipients.filter(r => r._id !== _id)
|
|
93
|
-
}
|
|
94
|
-
})
|
|
95
|
-
} else {
|
|
96
|
-
setSharedDriveRecipients(prev => {
|
|
97
|
-
const recipientToMove = prev.recipients.find(r => r._id === _id)
|
|
98
|
-
|
|
99
|
-
return {
|
|
100
|
-
recipients: prev.recipients.filter(r => r._id !== _id),
|
|
101
|
-
readOnlyRecipients: [...prev.readOnlyRecipients, recipientToMove]
|
|
102
|
-
}
|
|
103
|
-
})
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const onRevoke = index => {
|
|
108
|
-
const _id = index.split(RECIPIENT_INDEX_PREFIX)[1]
|
|
109
|
-
|
|
110
|
-
setSharedDriveRecipients(prev => {
|
|
111
|
-
return {
|
|
112
|
-
recipients: prev.recipients.filter(r => r._id !== _id),
|
|
113
|
-
readOnlyRecipients: prev.readOnlyRecipients.filter(r => r._id !== _id)
|
|
114
|
-
}
|
|
115
|
-
})
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const createContact = contact => client.create(Contact.doctype, contact)
|
|
119
|
-
|
|
120
|
-
const recipients = formatRecipients(sharedDriveRecipients)
|
|
121
|
-
|
|
122
12
|
return (
|
|
123
|
-
<
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
handleSharedDriveNameChange={handleSharedDriveNameChange}
|
|
127
|
-
createContact={createContact}
|
|
128
|
-
recipients={recipients}
|
|
129
|
-
currentRecipients={[]}
|
|
130
|
-
onRevoke={onRevoke}
|
|
131
|
-
onSetType={onSetType}
|
|
132
|
-
onCreate={onCreate}
|
|
133
|
-
onSend={undefined}
|
|
13
|
+
<FixedDialog
|
|
14
|
+
open
|
|
15
|
+
disableGutters
|
|
134
16
|
onClose={onClose}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
17
|
+
title={t('SharedDrive.sharedDriveModal.title')}
|
|
18
|
+
classes={{ paper: 'u-ov-visible' }}
|
|
19
|
+
componentsProps={{
|
|
20
|
+
dialogContent: { className: 'u-ov-visible' }
|
|
21
|
+
}}
|
|
22
|
+
content={<SharedDriveForm onSuccess={onClose} onCancel={onClose} />}
|
|
139
23
|
/>
|
|
140
24
|
)
|
|
141
25
|
})
|
|
@@ -73,7 +73,7 @@ export const formatRecipients = sharedDriveRecipients => {
|
|
|
73
73
|
recipients.push({
|
|
74
74
|
index: `${RECIPIENT_INDEX_PREFIX}${r._id}`,
|
|
75
75
|
email: ContactModel.getPrimaryEmail(r),
|
|
76
|
-
public_name:
|
|
76
|
+
public_name: ContactModel.getDisplayName(r),
|
|
77
77
|
memberIndex: r._id,
|
|
78
78
|
type: 'two-way',
|
|
79
79
|
members: r.members
|
|
@@ -84,7 +84,7 @@ export const formatRecipients = sharedDriveRecipients => {
|
|
|
84
84
|
recipients.push({
|
|
85
85
|
index: `${RECIPIENT_INDEX_PREFIX}${r._id}`,
|
|
86
86
|
email: ContactModel.getPrimaryEmail(r),
|
|
87
|
-
public_name:
|
|
87
|
+
public_name: ContactModel.getDisplayName(r),
|
|
88
88
|
memberIndex: r._id,
|
|
89
89
|
type: 'one-way',
|
|
90
90
|
members: r.members
|
|
@@ -138,6 +138,22 @@ describe('formatRecipients', () => {
|
|
|
138
138
|
})
|
|
139
139
|
})
|
|
140
140
|
|
|
141
|
+
it('should flatten an object-shaped contact name into a string public_name', () => {
|
|
142
|
+
const input = {
|
|
143
|
+
recipients: [
|
|
144
|
+
{
|
|
145
|
+
_id: '3',
|
|
146
|
+
name: { givenName: 'Arya', familyName: 'Stark' },
|
|
147
|
+
email: [{ address: 'arya@example.com', primary: true }]
|
|
148
|
+
}
|
|
149
|
+
],
|
|
150
|
+
readOnlyRecipients: []
|
|
151
|
+
}
|
|
152
|
+
const result = formatRecipients(input)
|
|
153
|
+
expect(typeof result[0].public_name).toBe('string')
|
|
154
|
+
expect(result[0].public_name).toBe('Arya Stark')
|
|
155
|
+
})
|
|
156
|
+
|
|
141
157
|
it('should sort recipients by public_name', () => {
|
|
142
158
|
const input = {
|
|
143
159
|
recipients: [
|