cozy-harvest-lib 8.2.0 → 8.3.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 +33 -0
- package/dist/components/AccountForm/index.js +3 -3
- package/dist/components/AccountForm/index.spec.js +47 -0
- package/dist/components/Routes.js +8 -1
- package/dist/datacards/FileDataCard.js +25 -90
- package/dist/datacards/ViewerModal.js +40 -0
- package/dist/datacards/useDataCardFiles.js +63 -0
- package/dist/datacards/useDataCardFiles.spec.js +242 -0
- package/package.json +3 -3
- package/src/components/AccountForm/index.jsx +3 -3
- package/src/components/AccountForm/index.spec.jsx +49 -0
- package/src/components/Routes.jsx +14 -5
- package/src/datacards/FileDataCard.jsx +24 -90
- package/src/datacards/ViewerModal.jsx +43 -0
- package/src/datacards/useDataCardFiles.js +84 -0
- package/src/datacards/useDataCardFiles.spec.js +135 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,39 @@
|
|
|
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
|
+
## [8.3.1](https://github.com/cozy/cozy-libs/compare/cozy-harvest-lib@8.3.0...cozy-harvest-lib@8.3.1) (2022-04-15)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* Avoid to have not sanitized fields as identifier fields ([c6ed9ec](https://github.com/cozy/cozy-libs/commit/c6ed9ec194685e5eeb9f81e5c620d17beabf0289))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# [8.3.0](https://github.com/cozy/cozy-libs/compare/cozy-harvest-lib@8.2.1...cozy-harvest-lib@8.3.0) (2022-04-15)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
* Implement ViewerModal as Route ([bdb6e88](https://github.com/cozy/cozy-libs/commit/bdb6e88e4c70217654f3b72828dee964aa2a4d1b))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
## [8.2.1](https://github.com/cozy/cozy-libs/compare/cozy-harvest-lib@8.2.0...cozy-harvest-lib@8.2.1) (2022-04-13)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
### Bug Fixes
|
|
32
|
+
|
|
33
|
+
* Get correct bi mapping for bnp_es and cic_es ([f304f89](https://github.com/cozy/cozy-libs/commit/f304f8978f1857f3f1d1e74c0c19385ab96dde24))
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
6
39
|
# [8.2.0](https://github.com/cozy/cozy-libs/compare/cozy-harvest-lib@8.1.1...cozy-harvest-lib@8.2.0) (2022-04-13)
|
|
7
40
|
|
|
8
41
|
|
|
@@ -191,7 +191,7 @@ export var AccountForm = /*#__PURE__*/function (_PureComponent) {
|
|
|
191
191
|
var _this$props = this.props,
|
|
192
192
|
account = _this$props.account,
|
|
193
193
|
konnector = _this$props.konnector;
|
|
194
|
-
var identifier = manifest.getIdentifier(konnector.fields);
|
|
194
|
+
var identifier = manifest.getIdentifier(manifest.sanitizeFields(konnector.fields));
|
|
195
195
|
|
|
196
196
|
if (account && account.auth[identifier] && account.auth[identifier] !== values[identifier]) {
|
|
197
197
|
this.showConfirmationModal();
|
|
@@ -272,7 +272,7 @@ export var AccountForm = /*#__PURE__*/function (_PureComponent) {
|
|
|
272
272
|
var isReadOnlyIdentifier = Boolean(get(account, 'relationships.vaultCipher')) && this.props.readOnlyIdentifier;
|
|
273
273
|
|
|
274
274
|
if (isReadOnlyIdentifier) {
|
|
275
|
-
var identifier = manifest.getIdentifier(
|
|
275
|
+
var identifier = manifest.getIdentifier(sanitizedFields);
|
|
276
276
|
sanitizedFields[identifier].type = 'hidden';
|
|
277
277
|
}
|
|
278
278
|
|
|
@@ -308,7 +308,7 @@ export var AccountForm = /*#__PURE__*/function (_PureComponent) {
|
|
|
308
308
|
className: "u-mb-1",
|
|
309
309
|
onClick: onBack,
|
|
310
310
|
konnector: konnector,
|
|
311
|
-
identifier: get(account, "auth.".concat(manifest.getIdentifier(
|
|
311
|
+
identifier: get(account, "auth.".concat(manifest.getIdentifier(sanitizedFields)))
|
|
312
312
|
}), isRunnable({
|
|
313
313
|
win: window,
|
|
314
314
|
konnector: konnector
|
|
@@ -51,6 +51,19 @@ var fixtures = {
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
},
|
|
54
|
+
konnectorWithAdvancedField: {
|
|
55
|
+
fields: {
|
|
56
|
+
advancedFields: {
|
|
57
|
+
folderPath: {
|
|
58
|
+
advanced: true,
|
|
59
|
+
isRequired: false
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
username: {
|
|
63
|
+
type: 'text'
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
54
67
|
account: {
|
|
55
68
|
auth: {
|
|
56
69
|
username: 'Toto',
|
|
@@ -434,6 +447,40 @@ describe('AccountForm', function () {
|
|
|
434
447
|
var hiddenInput = wrapper.find('input[type="hidden"][name="username"]');
|
|
435
448
|
expect(hiddenInput).toHaveLength(1);
|
|
436
449
|
});
|
|
450
|
+
it('should render a read-only identifier field even with advancedFields field in the manifest', function () {
|
|
451
|
+
var accountWithCipher = _objectSpread(_objectSpread({}, fixtures.account), {}, {
|
|
452
|
+
relationships: {
|
|
453
|
+
vaultCipher: {
|
|
454
|
+
_id: 'fake-cipher-id',
|
|
455
|
+
_type: 'com.bitwarden.ciphers',
|
|
456
|
+
_protocol: 'bitwarden'
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
var flowState = {};
|
|
462
|
+
var wrapper = mount( /*#__PURE__*/React.createElement(I18n, {
|
|
463
|
+
lang: "en",
|
|
464
|
+
dictRequire: function dictRequire() {}
|
|
465
|
+
}, /*#__PURE__*/React.createElement(AccountForm, {
|
|
466
|
+
flowState: flowState,
|
|
467
|
+
t: t,
|
|
468
|
+
konnector: fixtures.konnectorWithAdvancedField,
|
|
469
|
+
onSubmit: onSubmit,
|
|
470
|
+
account: accountWithCipher,
|
|
471
|
+
readOnlyIdentifier: true,
|
|
472
|
+
fieldOptions: {}
|
|
473
|
+
})), {
|
|
474
|
+
context: {
|
|
475
|
+
t: t
|
|
476
|
+
},
|
|
477
|
+
childContextTypes: {
|
|
478
|
+
t: PropTypes.func
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
var hiddenInput = wrapper.find('input[type="hidden"][name="username"]');
|
|
482
|
+
expect(hiddenInput).toHaveLength(1);
|
|
483
|
+
});
|
|
437
484
|
});
|
|
438
485
|
describe('fieldOptions', function () {
|
|
439
486
|
var setup = function setup(fieldOptions) {
|
|
@@ -4,6 +4,7 @@ import { Switch, Route, Redirect } from 'react-router';
|
|
|
4
4
|
import { withStyles } from '@material-ui/core/styles';
|
|
5
5
|
import Dialog from 'cozy-ui/transpiled/react/Dialog';
|
|
6
6
|
import { DialogCloseButton, useCozyDialog } from 'cozy-ui/transpiled/react/CozyDialogs';
|
|
7
|
+
import { useVaultUnlockContext, VaultUnlockProvider, VaultUnlockPlaceholder } from 'cozy-keys-lib';
|
|
7
8
|
import KonnectorAccounts from './KonnectorAccounts';
|
|
8
9
|
import AccountModal from './AccountModal';
|
|
9
10
|
import NewAccountModal from './NewAccountModal';
|
|
@@ -14,7 +15,7 @@ import HarvestVaultProvider from './HarvestVaultProvider';
|
|
|
14
15
|
import { MountPointProvider } from './MountPointContext';
|
|
15
16
|
import DialogContext from './DialogContext';
|
|
16
17
|
import { DatacardOptions } from './Datacards/DatacardOptionsContext';
|
|
17
|
-
import {
|
|
18
|
+
import { ViewerModal } from '../datacards/ViewerModal';
|
|
18
19
|
/**
|
|
19
20
|
* Dialog will not be centered vertically since we need the modal to "stay in place"
|
|
20
21
|
* when changing tabs. Since tabs content's height is not the same between the data
|
|
@@ -98,6 +99,12 @@ var Routes = function Routes(_ref) {
|
|
|
98
99
|
accounts: accountsAndTriggers
|
|
99
100
|
});
|
|
100
101
|
}
|
|
102
|
+
}), /*#__PURE__*/React.createElement(Route, {
|
|
103
|
+
path: "".concat(konnectorRoot, "/viewer/:accountId/:folderToSaveId/:fileIndex"),
|
|
104
|
+
exact: true,
|
|
105
|
+
render: function render(routeComponentProps) {
|
|
106
|
+
return /*#__PURE__*/React.createElement(ViewerModal, routeComponentProps);
|
|
107
|
+
}
|
|
101
108
|
}), /*#__PURE__*/React.createElement(Route, {
|
|
102
109
|
path: "".concat(konnectorRoot, "/new"),
|
|
103
110
|
exact: true,
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
2
1
|
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
3
|
-
import React, {
|
|
2
|
+
import React, { useContext, useState } from 'react';
|
|
4
3
|
import PropTypes from 'prop-types';
|
|
5
4
|
import get from 'lodash/get';
|
|
6
|
-
import sortBy from 'lodash/sortBy';
|
|
7
|
-
import uniq from 'lodash/uniq';
|
|
8
5
|
import keyBy from 'lodash/keyBy';
|
|
9
6
|
import 'leaflet/dist/leaflet.css';
|
|
10
7
|
import Skeleton from '@material-ui/lab/Skeleton';
|
|
@@ -12,13 +9,11 @@ import List from '@material-ui/core/List';
|
|
|
12
9
|
import ListItem from '@material-ui/core/ListItem';
|
|
13
10
|
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
|
14
11
|
import Slide from '@material-ui/core/Slide';
|
|
15
|
-
import Modal from '@material-ui/core/Modal';
|
|
16
12
|
import ListItemText from 'cozy-ui/transpiled/react/ListItemText';
|
|
13
|
+
import { RealTimeQueries } from 'cozy-client';
|
|
17
14
|
import palette from 'cozy-ui/transpiled/react/palette';
|
|
18
15
|
import { Media, Bd, Img } from 'cozy-ui/transpiled/react/Media';
|
|
19
16
|
import Circle from 'cozy-ui/transpiled/react/Circle';
|
|
20
|
-
import Portal from 'cozy-ui/transpiled/react/Portal';
|
|
21
|
-
import Viewer from 'cozy-ui/transpiled/react/Viewer';
|
|
22
17
|
import Card from 'cozy-ui/transpiled/react/Card';
|
|
23
18
|
import Icon from 'cozy-ui/transpiled/react/Icon';
|
|
24
19
|
import FileIcon from 'cozy-ui/transpiled/react/Icons/File';
|
|
@@ -26,8 +21,9 @@ import Typography from 'cozy-ui/transpiled/react/Typography';
|
|
|
26
21
|
import { useI18n } from 'cozy-ui/transpiled/react/I18n';
|
|
27
22
|
import AppLinkCard, { AppLinkButton } from '../components/cards/AppLinkCard';
|
|
28
23
|
import appLinksProps from '../components/KonnectorConfiguration/DataTab/appLinksProps';
|
|
29
|
-
import
|
|
24
|
+
import { MountPointContext } from '../components/MountPointContext';
|
|
30
25
|
import { getFileIcon } from './mime-utils';
|
|
26
|
+
import { useDataCardFiles } from './useDataCardFiles';
|
|
31
27
|
|
|
32
28
|
var LoadingFileListItem = function LoadingFileListItem(_ref) {
|
|
33
29
|
var divider = _ref.divider;
|
|
@@ -85,10 +81,14 @@ var FileCard = function FileCard(_ref4) {
|
|
|
85
81
|
var files = _ref4.files,
|
|
86
82
|
loading = _ref4.loading,
|
|
87
83
|
konnector = _ref4.konnector,
|
|
88
|
-
trigger = _ref4.trigger
|
|
84
|
+
trigger = _ref4.trigger,
|
|
85
|
+
accountId = _ref4.accountId;
|
|
89
86
|
|
|
90
87
|
var _useI18n2 = useI18n(),
|
|
91
|
-
t = _useI18n2.t;
|
|
88
|
+
t = _useI18n2.t;
|
|
89
|
+
|
|
90
|
+
var _useContext = useContext(MountPointContext),
|
|
91
|
+
pushHistory = _useContext.pushHistory; // Remember files that were there initially so that we do not
|
|
92
92
|
// animate their ListItem.
|
|
93
93
|
// Only files coming from realtime and that are added to files
|
|
94
94
|
// while the component is mounted will be animated.
|
|
@@ -102,19 +102,6 @@ var FileCard = function FileCard(_ref4) {
|
|
|
102
102
|
_useState2 = _slicedToArray(_useState, 1),
|
|
103
103
|
initialFilesById = _useState2[0];
|
|
104
104
|
|
|
105
|
-
var _useState3 = useState(null),
|
|
106
|
-
_useState4 = _slicedToArray(_useState3, 2),
|
|
107
|
-
viewerIndex = _useState4[0],
|
|
108
|
-
setViewerIndex = _useState4[1];
|
|
109
|
-
|
|
110
|
-
var handleCloseViewer = function handleCloseViewer() {
|
|
111
|
-
return setViewerIndex(null);
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
var handleFileChange = function handleFileChange(file, newIndex) {
|
|
115
|
-
return setViewerIndex(newIndex);
|
|
116
|
-
};
|
|
117
|
-
|
|
118
105
|
return /*#__PURE__*/React.createElement(Card, {
|
|
119
106
|
className: "u-ph-0 u-pb-0 u-ov-hidden"
|
|
120
107
|
}, /*#__PURE__*/React.createElement("div", {
|
|
@@ -149,21 +136,12 @@ var FileCard = function FileCard(_ref4) {
|
|
|
149
136
|
key: file._id
|
|
150
137
|
}, /*#__PURE__*/React.createElement(FileListItem, {
|
|
151
138
|
onClick: function onClick() {
|
|
152
|
-
|
|
139
|
+
pushHistory("/viewer/".concat(accountId, "/").concat(get(trigger, 'message.folder_to_save'), "/").concat(i));
|
|
153
140
|
},
|
|
154
141
|
file: file,
|
|
155
142
|
divider: i !== files.length - 1
|
|
156
143
|
}));
|
|
157
|
-
})),
|
|
158
|
-
into: "body"
|
|
159
|
-
}, /*#__PURE__*/React.createElement(Modal, {
|
|
160
|
-
open: true
|
|
161
|
-
}, /*#__PURE__*/React.createElement(Viewer, {
|
|
162
|
-
files: files,
|
|
163
|
-
currentIndex: viewerIndex,
|
|
164
|
-
onCloseRequest: handleCloseViewer,
|
|
165
|
-
onChangeRequest: handleFileChange
|
|
166
|
-
}))), /*#__PURE__*/React.createElement("div", {
|
|
144
|
+
})), /*#__PURE__*/React.createElement("div", {
|
|
167
145
|
className: "u-ta-right u-mv-half u-mh-1"
|
|
168
146
|
}, /*#__PURE__*/React.createElement(AppLinkButton, {
|
|
169
147
|
slug: "drive",
|
|
@@ -171,63 +149,27 @@ var FileCard = function FileCard(_ref4) {
|
|
|
171
149
|
})));
|
|
172
150
|
};
|
|
173
151
|
|
|
174
|
-
var
|
|
175
|
-
var
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
dir_id: trigger.message.folder_to_save,
|
|
179
|
-
trashed: false
|
|
180
|
-
}).indexFields(['dir_id', 'cozyMetadata.createdAt']).sortBy([{
|
|
181
|
-
dir_id: 'desc'
|
|
182
|
-
}, {
|
|
183
|
-
'cozyMetadata.createdAt': 'desc'
|
|
184
|
-
}]).limitBy(5),
|
|
185
|
-
as: "fileDataCard_io.cozy.files/".concat(trigger.message.folder_to_save, "/io.cozy.files"),
|
|
186
|
-
fetchPolicy: CozyClient.fetchPolicies.olderThan(30 * 1000)
|
|
187
|
-
};
|
|
188
|
-
};
|
|
152
|
+
var FileDataCard = function FileDataCard(_ref5) {
|
|
153
|
+
var accountId = _ref5.accountId,
|
|
154
|
+
konnector = _ref5.konnector,
|
|
155
|
+
trigger = _ref5.trigger;
|
|
189
156
|
|
|
190
|
-
var
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
query: Q('io.cozy.files').where({
|
|
194
|
-
'cozyMetadata.sourceAccount': accountId,
|
|
195
|
-
trashed: false
|
|
196
|
-
}).indexFields(['cozyMetadata.sourceAccount', 'cozyMetadata.createdAt']).sortBy([{
|
|
197
|
-
'cozyMetadata.sourceAccount': 'desc'
|
|
198
|
-
}, {
|
|
199
|
-
'cozyMetadata.createdAt': 'desc'
|
|
200
|
-
}]).limitBy(5),
|
|
201
|
-
as: "fileDataCard_io.cozy.accounts/".concat(accountId, "/io.cozy.files"),
|
|
202
|
-
fetchPolicy: CozyClient.fetchPolicies.olderThan(30 * 1000)
|
|
203
|
-
};
|
|
204
|
-
};
|
|
157
|
+
var _useDataCardFiles = useDataCardFiles(accountId, trigger.message.folder_to_save),
|
|
158
|
+
data = _useDataCardFiles.data,
|
|
159
|
+
fetchStatus = _useDataCardFiles.fetchStatus;
|
|
205
160
|
|
|
206
|
-
var
|
|
207
|
-
var
|
|
208
|
-
sourceAccountFiles = _ref7.sourceAccountFiles,
|
|
209
|
-
konnector = _ref7.konnector,
|
|
210
|
-
trigger = _ref7.trigger;
|
|
211
|
-
var files1 = folderToSaveFiles.data;
|
|
212
|
-
var files2 = sourceAccountFiles.data;
|
|
213
|
-
var noFiles = hasQueryBeenLoaded(folderToSaveFiles) && files1.length === 0 && hasQueryBeenLoaded(sourceAccountFiles) && files2.length === 0;
|
|
214
|
-
var isLoading = isQueryLoading(folderToSaveFiles) || isQueryLoading(sourceAccountFiles);
|
|
215
|
-
var files = useMemo(function () {
|
|
216
|
-
return sortBy(uniq([].concat(_toConsumableArray(files1), _toConsumableArray(files2)), function (x) {
|
|
217
|
-
return x._id;
|
|
218
|
-
}), function (x) {
|
|
219
|
-
return get(x, 'cozyMetadata.createdAt');
|
|
220
|
-
}).reverse().slice(0, 5);
|
|
221
|
-
}, [files1, files2]);
|
|
161
|
+
var isLoading = fetchStatus === 'loading';
|
|
162
|
+
var noFiles = fetchStatus === 'empty' || fetchStatus === 'failed';
|
|
222
163
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(RealTimeQueries, {
|
|
223
164
|
doctype: "io.cozy.files"
|
|
224
165
|
}), noFiles ? /*#__PURE__*/React.createElement(AppLinkCard, appLinksProps.drive({
|
|
225
166
|
trigger: trigger
|
|
226
167
|
})) : /*#__PURE__*/React.createElement(FileCard, {
|
|
227
|
-
files:
|
|
168
|
+
files: data,
|
|
228
169
|
loading: isLoading,
|
|
229
170
|
konnector: konnector,
|
|
230
|
-
trigger: trigger
|
|
171
|
+
trigger: trigger,
|
|
172
|
+
accountId: accountId
|
|
231
173
|
}));
|
|
232
174
|
};
|
|
233
175
|
|
|
@@ -236,11 +178,4 @@ FileDataCard.propTypes = {
|
|
|
236
178
|
accountId: PropTypes.string.isRequired,
|
|
237
179
|
trigger: PropTypes.object.isRequired
|
|
238
180
|
};
|
|
239
|
-
export default
|
|
240
|
-
folderToSaveFiles: function folderToSaveFiles(props) {
|
|
241
|
-
return makeFolderToSaveQueryFromProps(props);
|
|
242
|
-
},
|
|
243
|
-
sourceAccountFiles: function sourceAccountFiles(props) {
|
|
244
|
-
return makeSourceAccountQueryFromProps(props);
|
|
245
|
-
}
|
|
246
|
-
})(FileDataCard);
|
|
181
|
+
export default FileDataCard;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React, { useContext } from 'react';
|
|
2
|
+
import Overlay from 'cozy-ui/transpiled/react/Overlay';
|
|
3
|
+
import Viewer from 'cozy-ui/transpiled/react/Viewer';
|
|
4
|
+
import { MountPointContext } from '../components/MountPointContext';
|
|
5
|
+
import { useDataCardFiles } from './useDataCardFiles';
|
|
6
|
+
export var ViewerModal = function ViewerModal(_ref) {
|
|
7
|
+
var _ref$match$params = _ref.match.params,
|
|
8
|
+
accountId = _ref$match$params.accountId,
|
|
9
|
+
folderToSaveId = _ref$match$params.folderToSaveId,
|
|
10
|
+
fileIndex = _ref$match$params.fileIndex;
|
|
11
|
+
|
|
12
|
+
var _useContext = useContext(MountPointContext),
|
|
13
|
+
pushHistory = _useContext.pushHistory,
|
|
14
|
+
replaceHistory = _useContext.replaceHistory;
|
|
15
|
+
|
|
16
|
+
var _useDataCardFiles = useDataCardFiles(accountId, folderToSaveId),
|
|
17
|
+
data = _useDataCardFiles.data,
|
|
18
|
+
fetchStatus = _useDataCardFiles.fetchStatus;
|
|
19
|
+
|
|
20
|
+
var handleCloseViewer = function handleCloseViewer() {
|
|
21
|
+
return replaceHistory("/accounts");
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
var handleFileChange = function handleFileChange(_file, newIndex) {
|
|
25
|
+
return pushHistory("/viewer/".concat(accountId, "/").concat(folderToSaveId, "/").concat(newIndex));
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
if (fetchStatus === 'empty' || fetchStatus === 'failed' || fetchStatus === 'loaded' && fileIndex > data.length) {
|
|
29
|
+
handleCloseViewer();
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (fetchStatus === 'loading') return /*#__PURE__*/React.createElement(Overlay, null);
|
|
34
|
+
return /*#__PURE__*/React.createElement(Overlay, null, /*#__PURE__*/React.createElement(Viewer, {
|
|
35
|
+
files: data,
|
|
36
|
+
currentIndex: Number(fileIndex),
|
|
37
|
+
onCloseRequest: handleCloseViewer,
|
|
38
|
+
onChangeRequest: handleFileChange
|
|
39
|
+
}));
|
|
40
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import get from 'lodash/get';
|
|
4
|
+
import sortBy from 'lodash/sortBy';
|
|
5
|
+
import uniq from 'lodash/uniq';
|
|
6
|
+
import CozyClient, { Q, useQuery, hasQueryBeenLoaded } from 'cozy-client';
|
|
7
|
+
|
|
8
|
+
var useFolderToSaveFiles = function useFolderToSaveFiles(folderToSaveId) {
|
|
9
|
+
return useQuery(Q('io.cozy.files').where({
|
|
10
|
+
dir_id: folderToSaveId,
|
|
11
|
+
trashed: false
|
|
12
|
+
}).indexFields(['dir_id', 'cozyMetadata.createdAt']).sortBy([{
|
|
13
|
+
dir_id: 'desc'
|
|
14
|
+
}, {
|
|
15
|
+
'cozyMetadata.createdAt': 'desc'
|
|
16
|
+
}]).limitBy(5), {
|
|
17
|
+
as: "fileDataCard_io.cozy.files/".concat(folderToSaveId, "/io.cozy.files"),
|
|
18
|
+
fetchPolicy: CozyClient.fetchPolicies.olderThan(30 * 1000)
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
var useSourceAccountFiles = function useSourceAccountFiles(accountId) {
|
|
23
|
+
return useQuery(Q('io.cozy.files').where({
|
|
24
|
+
'cozyMetadata.sourceAccount': accountId,
|
|
25
|
+
trashed: false
|
|
26
|
+
}).indexFields(['cozyMetadata.sourceAccount', 'cozyMetadata.createdAt']).sortBy([{
|
|
27
|
+
'cozyMetadata.sourceAccount': 'desc'
|
|
28
|
+
}, {
|
|
29
|
+
'cozyMetadata.createdAt': 'desc'
|
|
30
|
+
}]).limitBy(5), {
|
|
31
|
+
as: "fileDataCard_io.cozy.accounts/".concat(accountId, "/io.cozy.files"),
|
|
32
|
+
fetchPolicy: CozyClient.fetchPolicies.olderThan(30 * 1000)
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
var getResponse = function getResponse(folderToSaveFiles, sourceAccountFiles) {
|
|
37
|
+
var loaded = Boolean(hasQueryBeenLoaded(folderToSaveFiles) && hasQueryBeenLoaded(sourceAccountFiles));
|
|
38
|
+
if (folderToSaveFiles.fetchStatus === 'failed' && sourceAccountFiles === 'failed') return {
|
|
39
|
+
fetchStatus: 'failed'
|
|
40
|
+
};
|
|
41
|
+
if (loaded && folderToSaveFiles.data.length === 0 && sourceAccountFiles.data.length === 0) return {
|
|
42
|
+
fetchStatus: 'empty'
|
|
43
|
+
};
|
|
44
|
+
if (loaded) return {
|
|
45
|
+
data: sortBy(uniq([].concat(_toConsumableArray(folderToSaveFiles.data), _toConsumableArray(sourceAccountFiles.data)), function (x) {
|
|
46
|
+
return x._id;
|
|
47
|
+
}), function (x) {
|
|
48
|
+
return get(x, 'cozyMetadata.createdAt');
|
|
49
|
+
}).reverse().slice(0, 5),
|
|
50
|
+
fetchStatus: 'loaded'
|
|
51
|
+
};
|
|
52
|
+
return {
|
|
53
|
+
fetchStatus: 'loading'
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export var useDataCardFiles = function useDataCardFiles(accountId, folderToSaveId) {
|
|
58
|
+
var folderToSaveFiles = useFolderToSaveFiles(folderToSaveId);
|
|
59
|
+
var sourceAccountFiles = useSourceAccountFiles(accountId);
|
|
60
|
+
return useMemo(function () {
|
|
61
|
+
return getResponse(folderToSaveFiles, sourceAccountFiles);
|
|
62
|
+
}, [folderToSaveFiles, sourceAccountFiles]);
|
|
63
|
+
};
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
|
|
3
|
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
4
|
+
|
|
5
|
+
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; }
|
|
6
|
+
|
|
7
|
+
import { renderHook } from '@testing-library/react-hooks';
|
|
8
|
+
import { useDataCardFiles } from './useDataCardFiles';
|
|
9
|
+
var mockUseQuery = jest.fn();
|
|
10
|
+
var mockFile1 = {
|
|
11
|
+
cozyMetadata: {
|
|
12
|
+
createdAt: '1970-01-01T00:00:11Z'
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
var mockFile2 = {
|
|
16
|
+
cozyMetadata: {
|
|
17
|
+
createdAt: '1970-01-01T00:00:10Z'
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
var mockFile3 = {
|
|
21
|
+
cozyMetadata: {
|
|
22
|
+
createdAt: '1970-01-01T00:00:09Z'
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
var mockFile4 = {
|
|
26
|
+
cozyMetadata: {
|
|
27
|
+
createdAt: '1970-01-01T00:00:08Z'
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
var mockFile5 = {
|
|
31
|
+
cozyMetadata: {
|
|
32
|
+
createdAt: '1970-01-01T00:00:07Z'
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
var mockFile6 = {
|
|
36
|
+
cozyMetadata: {
|
|
37
|
+
createdAt: '1970-01-01T00:00:06Z'
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
var mockFile7 = {
|
|
41
|
+
cozyMetadata: {
|
|
42
|
+
createdAt: '1970-01-01T00:00:05Z'
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
var mockFile8 = {
|
|
46
|
+
cozyMetadata: {
|
|
47
|
+
createdAt: '1970-01-01T00:00:04Z'
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
var mockFile9 = {
|
|
51
|
+
cozyMetadata: {
|
|
52
|
+
createdAt: '1970-01-01T00:00:03Z'
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
var mockFile10 = {
|
|
56
|
+
cozyMetadata: {
|
|
57
|
+
createdAt: '1970-01-01T00:00:02Z'
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
var mockFile11 = {
|
|
61
|
+
cozyMetadata: {
|
|
62
|
+
createdAt: '1970-01-01T00:00:01Z'
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
var mockFile12 = {
|
|
66
|
+
cozyMetadata: {
|
|
67
|
+
createdAt: '1970-01-01T00:00:00Z'
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
jest.mock('cozy-client', function () {
|
|
71
|
+
return _objectSpread(_objectSpread({}, jest.requireActual('cozy-client')), {}, {
|
|
72
|
+
useQuery: function useQuery() {
|
|
73
|
+
return mockUseQuery();
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
afterEach(function () {
|
|
78
|
+
mockUseQuery.mockClear();
|
|
79
|
+
});
|
|
80
|
+
it('handles files pending', function () {
|
|
81
|
+
mockUseQuery.mockReturnValueOnce({
|
|
82
|
+
fetchStatus: 'pending',
|
|
83
|
+
data: null
|
|
84
|
+
});
|
|
85
|
+
mockUseQuery.mockReturnValueOnce({
|
|
86
|
+
fetchStatus: 'pending',
|
|
87
|
+
data: null
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
var _renderHook = renderHook(function () {
|
|
91
|
+
return useDataCardFiles('1', '2');
|
|
92
|
+
}),
|
|
93
|
+
result = _renderHook.result;
|
|
94
|
+
|
|
95
|
+
expect(result.current).toStrictEqual({
|
|
96
|
+
fetchStatus: 'loading'
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
it('handles files loading', function () {
|
|
100
|
+
mockUseQuery.mockReturnValueOnce({
|
|
101
|
+
fetchStatus: 'loading',
|
|
102
|
+
data: null
|
|
103
|
+
});
|
|
104
|
+
mockUseQuery.mockReturnValueOnce({
|
|
105
|
+
fetchStatus: 'loading',
|
|
106
|
+
data: null
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
var _renderHook2 = renderHook(function () {
|
|
110
|
+
return useDataCardFiles('1', '2');
|
|
111
|
+
}),
|
|
112
|
+
result = _renderHook2.result;
|
|
113
|
+
|
|
114
|
+
expect(result.current).toStrictEqual({
|
|
115
|
+
fetchStatus: 'loading'
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
it('handles files loading with partial data', function () {
|
|
119
|
+
mockUseQuery.mockReturnValueOnce({
|
|
120
|
+
fetchStatus: 'loading',
|
|
121
|
+
data: [mockFile1]
|
|
122
|
+
});
|
|
123
|
+
mockUseQuery.mockReturnValueOnce({
|
|
124
|
+
fetchStatus: 'loading',
|
|
125
|
+
data: [mockFile2]
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
var _renderHook3 = renderHook(function () {
|
|
129
|
+
return useDataCardFiles('1', '2');
|
|
130
|
+
}),
|
|
131
|
+
result = _renderHook3.result;
|
|
132
|
+
|
|
133
|
+
expect(result.current).toStrictEqual({
|
|
134
|
+
fetchStatus: 'loading'
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
it('handles files loading with more partial data', function () {
|
|
138
|
+
mockUseQuery.mockReturnValueOnce({
|
|
139
|
+
fetchStatus: 'loading',
|
|
140
|
+
data: [mockFile1, mockFile2]
|
|
141
|
+
});
|
|
142
|
+
mockUseQuery.mockReturnValueOnce({
|
|
143
|
+
fetchStatus: 'loading',
|
|
144
|
+
data: [mockFile3, mockFile4]
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
var _renderHook4 = renderHook(function () {
|
|
148
|
+
return useDataCardFiles('1', '2');
|
|
149
|
+
}),
|
|
150
|
+
result = _renderHook4.result;
|
|
151
|
+
|
|
152
|
+
expect(result.current).toStrictEqual({
|
|
153
|
+
fetchStatus: 'loading'
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
it('handles files loading with empty data', function () {
|
|
157
|
+
mockUseQuery.mockReturnValueOnce({
|
|
158
|
+
fetchStatus: 'loaded',
|
|
159
|
+
data: [],
|
|
160
|
+
lastFetch: 1
|
|
161
|
+
});
|
|
162
|
+
mockUseQuery.mockReturnValueOnce({
|
|
163
|
+
fetchStatus: 'loaded',
|
|
164
|
+
data: [],
|
|
165
|
+
lastFetch: 1
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
var _renderHook5 = renderHook(function () {
|
|
169
|
+
return useDataCardFiles('1', '2');
|
|
170
|
+
}),
|
|
171
|
+
result = _renderHook5.result;
|
|
172
|
+
|
|
173
|
+
expect(result.current).toStrictEqual({
|
|
174
|
+
fetchStatus: 'empty'
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
it('handles files loaded and return in correct order', function () {
|
|
178
|
+
mockUseQuery.mockReturnValueOnce({
|
|
179
|
+
fetchStatus: 'loaded',
|
|
180
|
+
data: [mockFile2, mockFile1],
|
|
181
|
+
lastFetch: 1
|
|
182
|
+
});
|
|
183
|
+
mockUseQuery.mockReturnValueOnce({
|
|
184
|
+
fetchStatus: 'loaded',
|
|
185
|
+
data: [mockFile3, mockFile4],
|
|
186
|
+
lastFetch: 1
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
var _renderHook6 = renderHook(function () {
|
|
190
|
+
return useDataCardFiles('1', '2');
|
|
191
|
+
}),
|
|
192
|
+
result = _renderHook6.result;
|
|
193
|
+
|
|
194
|
+
expect(result.current).toStrictEqual({
|
|
195
|
+
data: [mockFile1, mockFile2, mockFile3, mockFile4],
|
|
196
|
+
fetchStatus: 'loaded'
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
it('handles files loaded with identical double return', function () {
|
|
200
|
+
mockUseQuery.mockReturnValueOnce({
|
|
201
|
+
fetchStatus: 'loaded',
|
|
202
|
+
data: [mockFile1, mockFile2, mockFile3, mockFile4],
|
|
203
|
+
lastFetch: 1
|
|
204
|
+
});
|
|
205
|
+
mockUseQuery.mockReturnValueOnce({
|
|
206
|
+
fetchStatus: 'loaded',
|
|
207
|
+
data: [mockFile3, mockFile2, mockFile3, mockFile4],
|
|
208
|
+
lastFetch: 1
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
var _renderHook7 = renderHook(function () {
|
|
212
|
+
return useDataCardFiles('1', '2');
|
|
213
|
+
}),
|
|
214
|
+
result = _renderHook7.result;
|
|
215
|
+
|
|
216
|
+
expect(result.current).toStrictEqual({
|
|
217
|
+
data: [mockFile1, mockFile2, mockFile3, mockFile4],
|
|
218
|
+
fetchStatus: 'loaded'
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
it('handles files loaded with more than 5 result', function () {
|
|
222
|
+
mockUseQuery.mockReturnValueOnce({
|
|
223
|
+
fetchStatus: 'loaded',
|
|
224
|
+
data: [mockFile1, mockFile2, mockFile3, mockFile4, mockFile5, mockFile6],
|
|
225
|
+
lastFetch: 1
|
|
226
|
+
});
|
|
227
|
+
mockUseQuery.mockReturnValueOnce({
|
|
228
|
+
fetchStatus: 'loaded',
|
|
229
|
+
data: [mockFile7, mockFile8, mockFile9, mockFile10, mockFile11, mockFile12],
|
|
230
|
+
lastFetch: 1
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
var _renderHook8 = renderHook(function () {
|
|
234
|
+
return useDataCardFiles('1', '2');
|
|
235
|
+
}),
|
|
236
|
+
result = _renderHook8.result;
|
|
237
|
+
|
|
238
|
+
expect(result.current).toStrictEqual({
|
|
239
|
+
data: [mockFile1, mockFile2, mockFile3, mockFile4, mockFile5],
|
|
240
|
+
fetchStatus: 'loaded'
|
|
241
|
+
});
|
|
242
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cozy-harvest-lib",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.3.1",
|
|
4
4
|
"description": "Provides logic, modules and components for Cozy's harvest applications.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"author": "Cozy",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@cozy/minilog": "^1.0.0",
|
|
30
30
|
"@sentry/browser": "^6.0.1",
|
|
31
|
-
"cozy-bi-auth": "0.0.
|
|
31
|
+
"cozy-bi-auth": "0.0.25",
|
|
32
32
|
"cozy-doctypes": "^1.83.7",
|
|
33
33
|
"cozy-logger": "^1.9.0",
|
|
34
34
|
"date-fns": "^1.30.1",
|
|
@@ -85,5 +85,5 @@
|
|
|
85
85
|
"react-router-dom": "^5.0.1"
|
|
86
86
|
},
|
|
87
87
|
"sideEffects": false,
|
|
88
|
-
"gitHead": "
|
|
88
|
+
"gitHead": "aea5ca9cbfb60d5b3bb8318939087952adbe8522"
|
|
89
89
|
}
|
|
@@ -132,7 +132,7 @@ export class AccountForm extends PureComponent {
|
|
|
132
132
|
handleSubmit(values, form) {
|
|
133
133
|
const { account, konnector } = this.props
|
|
134
134
|
|
|
135
|
-
const identifier = manifest.getIdentifier(konnector.fields)
|
|
135
|
+
const identifier = manifest.getIdentifier(manifest.sanitizeFields(konnector.fields))
|
|
136
136
|
if (
|
|
137
137
|
account &&
|
|
138
138
|
account.auth[identifier] &&
|
|
@@ -228,7 +228,7 @@ export class AccountForm extends PureComponent {
|
|
|
228
228
|
this.props.readOnlyIdentifier
|
|
229
229
|
|
|
230
230
|
if (isReadOnlyIdentifier) {
|
|
231
|
-
const identifier = manifest.getIdentifier(
|
|
231
|
+
const identifier = manifest.getIdentifier(sanitizedFields)
|
|
232
232
|
sanitizedFields[identifier].type = 'hidden'
|
|
233
233
|
}
|
|
234
234
|
|
|
@@ -268,7 +268,7 @@ export class AccountForm extends PureComponent {
|
|
|
268
268
|
konnector={konnector}
|
|
269
269
|
identifier={get(
|
|
270
270
|
account,
|
|
271
|
-
`auth.${manifest.getIdentifier(
|
|
271
|
+
`auth.${manifest.getIdentifier(sanitizedFields)}`
|
|
272
272
|
)}
|
|
273
273
|
/>
|
|
274
274
|
)}
|
|
@@ -49,6 +49,19 @@ const fixtures = {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
},
|
|
52
|
+
konnectorWithAdvancedField: {
|
|
53
|
+
fields: {
|
|
54
|
+
advancedFields: {
|
|
55
|
+
folderPath: {
|
|
56
|
+
advanced: true,
|
|
57
|
+
isRequired: false
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
username: {
|
|
61
|
+
type: 'text'
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
},
|
|
52
65
|
account: {
|
|
53
66
|
auth: {
|
|
54
67
|
username: 'Toto',
|
|
@@ -386,6 +399,42 @@ describe('AccountForm', () => {
|
|
|
386
399
|
|
|
387
400
|
const hiddenInput = wrapper.find('input[type="hidden"][name="username"]')
|
|
388
401
|
|
|
402
|
+
expect(hiddenInput).toHaveLength(1)
|
|
403
|
+
})
|
|
404
|
+
it('should render a read-only identifier field even with advancedFields field in the manifest', () => {
|
|
405
|
+
const accountWithCipher = {
|
|
406
|
+
...fixtures.account,
|
|
407
|
+
relationships: {
|
|
408
|
+
vaultCipher: {
|
|
409
|
+
_id: 'fake-cipher-id',
|
|
410
|
+
_type: 'com.bitwarden.ciphers',
|
|
411
|
+
_protocol: 'bitwarden'
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
const flowState = {}
|
|
416
|
+
const wrapper = mount(
|
|
417
|
+
<I18n lang="en" dictRequire={() => {}}>
|
|
418
|
+
<AccountForm
|
|
419
|
+
flowState={flowState}
|
|
420
|
+
t={t}
|
|
421
|
+
konnector={fixtures.konnectorWithAdvancedField}
|
|
422
|
+
onSubmit={onSubmit}
|
|
423
|
+
account={accountWithCipher}
|
|
424
|
+
readOnlyIdentifier={true}
|
|
425
|
+
fieldOptions={{}}
|
|
426
|
+
/>
|
|
427
|
+
</I18n>,
|
|
428
|
+
{
|
|
429
|
+
context: { t },
|
|
430
|
+
childContextTypes: {
|
|
431
|
+
t: PropTypes.func
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
const hiddenInput = wrapper.find('input[type="hidden"][name="username"]')
|
|
437
|
+
|
|
389
438
|
expect(hiddenInput).toHaveLength(1)
|
|
390
439
|
})
|
|
391
440
|
})
|
|
@@ -7,6 +7,11 @@ import {
|
|
|
7
7
|
DialogCloseButton,
|
|
8
8
|
useCozyDialog
|
|
9
9
|
} from 'cozy-ui/transpiled/react/CozyDialogs'
|
|
10
|
+
import {
|
|
11
|
+
useVaultUnlockContext,
|
|
12
|
+
VaultUnlockProvider,
|
|
13
|
+
VaultUnlockPlaceholder
|
|
14
|
+
} from 'cozy-keys-lib'
|
|
10
15
|
|
|
11
16
|
import KonnectorAccounts from './KonnectorAccounts'
|
|
12
17
|
import AccountModal from './AccountModal'
|
|
@@ -18,11 +23,8 @@ import HarvestVaultProvider from './HarvestVaultProvider'
|
|
|
18
23
|
import { MountPointProvider } from './MountPointContext'
|
|
19
24
|
import DialogContext from './DialogContext'
|
|
20
25
|
import { DatacardOptions } from './Datacards/DatacardOptionsContext'
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
VaultUnlockProvider,
|
|
24
|
-
VaultUnlockPlaceholder
|
|
25
|
-
} from 'cozy-keys-lib'
|
|
26
|
+
|
|
27
|
+
import { ViewerModal } from '../datacards/ViewerModal'
|
|
26
28
|
|
|
27
29
|
/**
|
|
28
30
|
* Dialog will not be centered vertically since we need the modal to "stay in place"
|
|
@@ -101,6 +103,13 @@ const Routes = ({ konnectorRoot, konnector, onDismiss, datacardOptions }) => {
|
|
|
101
103
|
/>
|
|
102
104
|
)}
|
|
103
105
|
/>
|
|
106
|
+
<Route
|
|
107
|
+
path={`${konnectorRoot}/viewer/:accountId/:folderToSaveId/:fileIndex`}
|
|
108
|
+
exact
|
|
109
|
+
render={routeComponentProps => (
|
|
110
|
+
<ViewerModal {...routeComponentProps} />
|
|
111
|
+
)}
|
|
112
|
+
/>
|
|
104
113
|
<Route
|
|
105
114
|
path={`${konnectorRoot}/new`}
|
|
106
115
|
exact
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useContext, useState } from 'react'
|
|
2
2
|
import PropTypes from 'prop-types'
|
|
3
3
|
import get from 'lodash/get'
|
|
4
|
-
import sortBy from 'lodash/sortBy'
|
|
5
|
-
import uniq from 'lodash/uniq'
|
|
6
4
|
import keyBy from 'lodash/keyBy'
|
|
7
5
|
|
|
8
6
|
import 'leaflet/dist/leaflet.css'
|
|
@@ -12,15 +10,13 @@ import List from '@material-ui/core/List'
|
|
|
12
10
|
import ListItem from '@material-ui/core/ListItem'
|
|
13
11
|
import ListItemIcon from '@material-ui/core/ListItemIcon'
|
|
14
12
|
import Slide from '@material-ui/core/Slide'
|
|
15
|
-
import Modal from '@material-ui/core/Modal'
|
|
16
13
|
|
|
17
14
|
import ListItemText from 'cozy-ui/transpiled/react/ListItemText'
|
|
18
15
|
|
|
16
|
+
import { RealTimeQueries } from 'cozy-client'
|
|
19
17
|
import palette from 'cozy-ui/transpiled/react/palette'
|
|
20
18
|
import { Media, Bd, Img } from 'cozy-ui/transpiled/react/Media'
|
|
21
19
|
import Circle from 'cozy-ui/transpiled/react/Circle'
|
|
22
|
-
import Portal from 'cozy-ui/transpiled/react/Portal'
|
|
23
|
-
import Viewer from 'cozy-ui/transpiled/react/Viewer'
|
|
24
20
|
import Card from 'cozy-ui/transpiled/react/Card'
|
|
25
21
|
import Icon from 'cozy-ui/transpiled/react/Icon'
|
|
26
22
|
import FileIcon from 'cozy-ui/transpiled/react/Icons/File'
|
|
@@ -29,16 +25,9 @@ import { useI18n } from 'cozy-ui/transpiled/react/I18n'
|
|
|
29
25
|
|
|
30
26
|
import AppLinkCard, { AppLinkButton } from '../components/cards/AppLinkCard'
|
|
31
27
|
import appLinksProps from '../components/KonnectorConfiguration/DataTab/appLinksProps'
|
|
32
|
-
|
|
33
|
-
import CozyClient, {
|
|
34
|
-
Q,
|
|
35
|
-
queryConnect,
|
|
36
|
-
isQueryLoading,
|
|
37
|
-
hasQueryBeenLoaded,
|
|
38
|
-
RealTimeQueries
|
|
39
|
-
} from 'cozy-client'
|
|
40
|
-
|
|
28
|
+
import { MountPointContext } from '../components/MountPointContext'
|
|
41
29
|
import { getFileIcon } from './mime-utils'
|
|
30
|
+
import { useDataCardFiles } from './useDataCardFiles'
|
|
42
31
|
|
|
43
32
|
const LoadingFileListItem = ({ divider }) => {
|
|
44
33
|
return (
|
|
@@ -87,17 +76,15 @@ const TransitionWrapper = ({ children }) => {
|
|
|
87
76
|
)
|
|
88
77
|
}
|
|
89
78
|
|
|
90
|
-
const FileCard = ({ files, loading, konnector, trigger }) => {
|
|
79
|
+
const FileCard = ({ files, loading, konnector, trigger, accountId }) => {
|
|
91
80
|
const { t } = useI18n()
|
|
81
|
+
const { pushHistory } = useContext(MountPointContext)
|
|
92
82
|
|
|
93
83
|
// Remember files that were there initially so that we do not
|
|
94
84
|
// animate their ListItem.
|
|
95
85
|
// Only files coming from realtime and that are added to files
|
|
96
86
|
// while the component is mounted will be animated.
|
|
97
87
|
const [initialFilesById] = useState(() => keyBy(files, x => x._id))
|
|
98
|
-
const [viewerIndex, setViewerIndex] = useState(null)
|
|
99
|
-
const handleCloseViewer = () => setViewerIndex(null)
|
|
100
|
-
const handleFileChange = (file, newIndex) => setViewerIndex(newIndex)
|
|
101
88
|
|
|
102
89
|
return (
|
|
103
90
|
<Card className="u-ph-0 u-pb-0 u-ov-hidden">
|
|
@@ -138,7 +125,14 @@ const FileCard = ({ files, loading, konnector, trigger }) => {
|
|
|
138
125
|
return (
|
|
139
126
|
<ItemWrapper key={file._id}>
|
|
140
127
|
<FileListItem
|
|
141
|
-
onClick={() =>
|
|
128
|
+
onClick={() => {
|
|
129
|
+
pushHistory(
|
|
130
|
+
`/viewer/${accountId}/${get(
|
|
131
|
+
trigger,
|
|
132
|
+
'message.folder_to_save'
|
|
133
|
+
)}/${i}`
|
|
134
|
+
)
|
|
135
|
+
}}
|
|
142
136
|
file={file}
|
|
143
137
|
divider={i !== files.length - 1}
|
|
144
138
|
/>
|
|
@@ -147,18 +141,6 @@ const FileCard = ({ files, loading, konnector, trigger }) => {
|
|
|
147
141
|
})
|
|
148
142
|
)}
|
|
149
143
|
</List>
|
|
150
|
-
{viewerIndex !== null && (
|
|
151
|
-
<Portal into="body">
|
|
152
|
-
<Modal open={true}>
|
|
153
|
-
<Viewer
|
|
154
|
-
files={files}
|
|
155
|
-
currentIndex={viewerIndex}
|
|
156
|
-
onCloseRequest={handleCloseViewer}
|
|
157
|
-
onChangeRequest={handleFileChange}
|
|
158
|
-
/>
|
|
159
|
-
</Modal>
|
|
160
|
-
</Portal>
|
|
161
|
-
)}
|
|
162
144
|
<div className="u-ta-right u-mv-half u-mh-1">
|
|
163
145
|
<AppLinkButton
|
|
164
146
|
slug="drive"
|
|
@@ -169,60 +151,14 @@ const FileCard = ({ files, loading, konnector, trigger }) => {
|
|
|
169
151
|
)
|
|
170
152
|
}
|
|
171
153
|
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
.sortBy([{ dir_id: 'desc' }, { 'cozyMetadata.createdAt': 'desc' }])
|
|
180
|
-
.limitBy(5),
|
|
181
|
-
as: `fileDataCard_io.cozy.files/${trigger.message.folder_to_save}/io.cozy.files`,
|
|
182
|
-
fetchPolicy: CozyClient.fetchPolicies.olderThan(30 * 1000)
|
|
183
|
-
})
|
|
184
|
-
|
|
185
|
-
const makeSourceAccountQueryFromProps = ({ accountId }) => ({
|
|
186
|
-
query: Q('io.cozy.files')
|
|
187
|
-
.where({
|
|
188
|
-
'cozyMetadata.sourceAccount': accountId,
|
|
189
|
-
trashed: false
|
|
190
|
-
})
|
|
191
|
-
.indexFields(['cozyMetadata.sourceAccount', 'cozyMetadata.createdAt'])
|
|
192
|
-
.sortBy([
|
|
193
|
-
{ 'cozyMetadata.sourceAccount': 'desc' },
|
|
194
|
-
{ 'cozyMetadata.createdAt': 'desc' }
|
|
195
|
-
])
|
|
196
|
-
.limitBy(5),
|
|
197
|
-
as: `fileDataCard_io.cozy.accounts/${accountId}/io.cozy.files`,
|
|
198
|
-
fetchPolicy: CozyClient.fetchPolicies.olderThan(30 * 1000)
|
|
199
|
-
})
|
|
200
|
-
|
|
201
|
-
const FileDataCard = ({
|
|
202
|
-
folderToSaveFiles,
|
|
203
|
-
sourceAccountFiles,
|
|
204
|
-
konnector,
|
|
205
|
-
trigger
|
|
206
|
-
}) => {
|
|
207
|
-
const { data: files1 } = folderToSaveFiles
|
|
208
|
-
const { data: files2 } = sourceAccountFiles
|
|
209
|
-
|
|
210
|
-
const noFiles =
|
|
211
|
-
hasQueryBeenLoaded(folderToSaveFiles) &&
|
|
212
|
-
files1.length === 0 &&
|
|
213
|
-
hasQueryBeenLoaded(sourceAccountFiles) &&
|
|
214
|
-
files2.length === 0
|
|
215
|
-
const isLoading =
|
|
216
|
-
isQueryLoading(folderToSaveFiles) || isQueryLoading(sourceAccountFiles)
|
|
154
|
+
const FileDataCard = ({ accountId, konnector, trigger }) => {
|
|
155
|
+
const { data, fetchStatus } = useDataCardFiles(
|
|
156
|
+
accountId,
|
|
157
|
+
trigger.message.folder_to_save
|
|
158
|
+
)
|
|
159
|
+
const isLoading = fetchStatus === 'loading'
|
|
160
|
+
const noFiles = fetchStatus === 'empty' || fetchStatus === 'failed'
|
|
217
161
|
|
|
218
|
-
const files = useMemo(() => {
|
|
219
|
-
return sortBy(
|
|
220
|
-
uniq([...files1, ...files2], x => x._id),
|
|
221
|
-
x => get(x, 'cozyMetadata.createdAt')
|
|
222
|
-
)
|
|
223
|
-
.reverse()
|
|
224
|
-
.slice(0, 5)
|
|
225
|
-
}, [files1, files2])
|
|
226
162
|
return (
|
|
227
163
|
<>
|
|
228
164
|
<RealTimeQueries doctype="io.cozy.files" />
|
|
@@ -230,10 +166,11 @@ const FileDataCard = ({
|
|
|
230
166
|
<AppLinkCard {...appLinksProps.drive({ trigger })} />
|
|
231
167
|
) : (
|
|
232
168
|
<FileCard
|
|
233
|
-
files={
|
|
169
|
+
files={data}
|
|
234
170
|
loading={isLoading}
|
|
235
171
|
konnector={konnector}
|
|
236
172
|
trigger={trigger}
|
|
173
|
+
accountId={accountId}
|
|
237
174
|
/>
|
|
238
175
|
)}
|
|
239
176
|
</>
|
|
@@ -246,7 +183,4 @@ FileDataCard.propTypes = {
|
|
|
246
183
|
trigger: PropTypes.object.isRequired
|
|
247
184
|
}
|
|
248
185
|
|
|
249
|
-
export default
|
|
250
|
-
folderToSaveFiles: props => makeFolderToSaveQueryFromProps(props),
|
|
251
|
-
sourceAccountFiles: props => makeSourceAccountQueryFromProps(props)
|
|
252
|
-
})(FileDataCard)
|
|
186
|
+
export default FileDataCard
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React, { useContext } from 'react'
|
|
2
|
+
|
|
3
|
+
import Overlay from 'cozy-ui/transpiled/react/Overlay'
|
|
4
|
+
import Viewer from 'cozy-ui/transpiled/react/Viewer'
|
|
5
|
+
|
|
6
|
+
import { MountPointContext } from '../components/MountPointContext'
|
|
7
|
+
import { useDataCardFiles } from './useDataCardFiles'
|
|
8
|
+
|
|
9
|
+
export const ViewerModal = ({
|
|
10
|
+
match: {
|
|
11
|
+
params: { accountId, folderToSaveId, fileIndex }
|
|
12
|
+
}
|
|
13
|
+
}) => {
|
|
14
|
+
const { pushHistory, replaceHistory } = useContext(MountPointContext)
|
|
15
|
+
const { data, fetchStatus } = useDataCardFiles(accountId, folderToSaveId)
|
|
16
|
+
|
|
17
|
+
const handleCloseViewer = () => replaceHistory(`/accounts`)
|
|
18
|
+
const handleFileChange = (_file, newIndex) =>
|
|
19
|
+
pushHistory(`/viewer/${accountId}/${folderToSaveId}/${newIndex}`)
|
|
20
|
+
|
|
21
|
+
if (
|
|
22
|
+
fetchStatus === 'empty' ||
|
|
23
|
+
fetchStatus === 'failed' ||
|
|
24
|
+
(fetchStatus === 'loaded' && fileIndex > data.length)
|
|
25
|
+
) {
|
|
26
|
+
handleCloseViewer()
|
|
27
|
+
|
|
28
|
+
return null
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (fetchStatus === 'loading') return <Overlay />
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<Overlay>
|
|
35
|
+
<Viewer
|
|
36
|
+
files={data}
|
|
37
|
+
currentIndex={Number(fileIndex)}
|
|
38
|
+
onCloseRequest={handleCloseViewer}
|
|
39
|
+
onChangeRequest={handleFileChange}
|
|
40
|
+
/>
|
|
41
|
+
</Overlay>
|
|
42
|
+
)
|
|
43
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { useMemo } from 'react'
|
|
2
|
+
import get from 'lodash/get'
|
|
3
|
+
import sortBy from 'lodash/sortBy'
|
|
4
|
+
import uniq from 'lodash/uniq'
|
|
5
|
+
|
|
6
|
+
import CozyClient, { Q, useQuery, hasQueryBeenLoaded } from 'cozy-client'
|
|
7
|
+
|
|
8
|
+
const useFolderToSaveFiles = folderToSaveId =>
|
|
9
|
+
useQuery(
|
|
10
|
+
Q('io.cozy.files')
|
|
11
|
+
.where({
|
|
12
|
+
dir_id: folderToSaveId,
|
|
13
|
+
trashed: false
|
|
14
|
+
})
|
|
15
|
+
.indexFields(['dir_id', 'cozyMetadata.createdAt'])
|
|
16
|
+
.sortBy([{ dir_id: 'desc' }, { 'cozyMetadata.createdAt': 'desc' }])
|
|
17
|
+
.limitBy(5),
|
|
18
|
+
{
|
|
19
|
+
as: `fileDataCard_io.cozy.files/${folderToSaveId}/io.cozy.files`,
|
|
20
|
+
fetchPolicy: CozyClient.fetchPolicies.olderThan(30 * 1000)
|
|
21
|
+
}
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
const useSourceAccountFiles = accountId =>
|
|
25
|
+
useQuery(
|
|
26
|
+
Q('io.cozy.files')
|
|
27
|
+
.where({ 'cozyMetadata.sourceAccount': accountId, trashed: false })
|
|
28
|
+
.indexFields(['cozyMetadata.sourceAccount', 'cozyMetadata.createdAt'])
|
|
29
|
+
.sortBy([
|
|
30
|
+
{ 'cozyMetadata.sourceAccount': 'desc' },
|
|
31
|
+
{ 'cozyMetadata.createdAt': 'desc' }
|
|
32
|
+
])
|
|
33
|
+
.limitBy(5),
|
|
34
|
+
{
|
|
35
|
+
as: `fileDataCard_io.cozy.accounts/${accountId}/io.cozy.files`,
|
|
36
|
+
fetchPolicy: CozyClient.fetchPolicies.olderThan(30 * 1000)
|
|
37
|
+
}
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
const getResponse = (folderToSaveFiles, sourceAccountFiles) => {
|
|
41
|
+
const loaded = Boolean(
|
|
42
|
+
hasQueryBeenLoaded(folderToSaveFiles) &&
|
|
43
|
+
hasQueryBeenLoaded(sourceAccountFiles)
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
if (
|
|
47
|
+
folderToSaveFiles.fetchStatus === 'failed' &&
|
|
48
|
+
sourceAccountFiles === 'failed'
|
|
49
|
+
)
|
|
50
|
+
return { fetchStatus: 'failed' }
|
|
51
|
+
|
|
52
|
+
if (
|
|
53
|
+
loaded &&
|
|
54
|
+
folderToSaveFiles.data.length === 0 &&
|
|
55
|
+
sourceAccountFiles.data.length === 0
|
|
56
|
+
)
|
|
57
|
+
return { fetchStatus: 'empty' }
|
|
58
|
+
|
|
59
|
+
if (loaded)
|
|
60
|
+
return {
|
|
61
|
+
data: sortBy(
|
|
62
|
+
uniq(
|
|
63
|
+
[...folderToSaveFiles.data, ...sourceAccountFiles.data],
|
|
64
|
+
x => x._id
|
|
65
|
+
),
|
|
66
|
+
x => get(x, 'cozyMetadata.createdAt')
|
|
67
|
+
)
|
|
68
|
+
.reverse()
|
|
69
|
+
.slice(0, 5),
|
|
70
|
+
fetchStatus: 'loaded'
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return { fetchStatus: 'loading' }
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export const useDataCardFiles = (accountId, folderToSaveId) => {
|
|
77
|
+
const folderToSaveFiles = useFolderToSaveFiles(folderToSaveId)
|
|
78
|
+
const sourceAccountFiles = useSourceAccountFiles(accountId)
|
|
79
|
+
|
|
80
|
+
return useMemo(
|
|
81
|
+
() => getResponse(folderToSaveFiles, sourceAccountFiles),
|
|
82
|
+
[folderToSaveFiles, sourceAccountFiles]
|
|
83
|
+
)
|
|
84
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { renderHook } from '@testing-library/react-hooks'
|
|
2
|
+
|
|
3
|
+
import { useDataCardFiles } from './useDataCardFiles'
|
|
4
|
+
|
|
5
|
+
const mockUseQuery = jest.fn()
|
|
6
|
+
const mockFile1 = { cozyMetadata: { createdAt: '1970-01-01T00:00:11Z' } }
|
|
7
|
+
const mockFile2 = { cozyMetadata: { createdAt: '1970-01-01T00:00:10Z' } }
|
|
8
|
+
const mockFile3 = { cozyMetadata: { createdAt: '1970-01-01T00:00:09Z' } }
|
|
9
|
+
const mockFile4 = { cozyMetadata: { createdAt: '1970-01-01T00:00:08Z' } }
|
|
10
|
+
const mockFile5 = { cozyMetadata: { createdAt: '1970-01-01T00:00:07Z' } }
|
|
11
|
+
const mockFile6 = { cozyMetadata: { createdAt: '1970-01-01T00:00:06Z' } }
|
|
12
|
+
const mockFile7 = { cozyMetadata: { createdAt: '1970-01-01T00:00:05Z' } }
|
|
13
|
+
const mockFile8 = { cozyMetadata: { createdAt: '1970-01-01T00:00:04Z' } }
|
|
14
|
+
const mockFile9 = { cozyMetadata: { createdAt: '1970-01-01T00:00:03Z' } }
|
|
15
|
+
const mockFile10 = { cozyMetadata: { createdAt: '1970-01-01T00:00:02Z' } }
|
|
16
|
+
const mockFile11 = { cozyMetadata: { createdAt: '1970-01-01T00:00:01Z' } }
|
|
17
|
+
const mockFile12 = { cozyMetadata: { createdAt: '1970-01-01T00:00:00Z' } }
|
|
18
|
+
|
|
19
|
+
jest.mock('cozy-client', () => ({
|
|
20
|
+
...jest.requireActual('cozy-client'),
|
|
21
|
+
useQuery: () => mockUseQuery()
|
|
22
|
+
}))
|
|
23
|
+
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
mockUseQuery.mockClear()
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('handles files pending', () => {
|
|
29
|
+
mockUseQuery.mockReturnValueOnce({ fetchStatus: 'pending', data: null })
|
|
30
|
+
mockUseQuery.mockReturnValueOnce({ fetchStatus: 'pending', data: null })
|
|
31
|
+
const { result } = renderHook(() => useDataCardFiles('1', '2'))
|
|
32
|
+
expect(result.current).toStrictEqual({ fetchStatus: 'loading' })
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('handles files loading', () => {
|
|
36
|
+
mockUseQuery.mockReturnValueOnce({ fetchStatus: 'loading', data: null })
|
|
37
|
+
mockUseQuery.mockReturnValueOnce({ fetchStatus: 'loading', data: null })
|
|
38
|
+
const { result } = renderHook(() => useDataCardFiles('1', '2'))
|
|
39
|
+
expect(result.current).toStrictEqual({ fetchStatus: 'loading' })
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('handles files loading with partial data', () => {
|
|
43
|
+
mockUseQuery.mockReturnValueOnce({
|
|
44
|
+
fetchStatus: 'loading',
|
|
45
|
+
data: [mockFile1]
|
|
46
|
+
})
|
|
47
|
+
mockUseQuery.mockReturnValueOnce({
|
|
48
|
+
fetchStatus: 'loading',
|
|
49
|
+
data: [mockFile2]
|
|
50
|
+
})
|
|
51
|
+
const { result } = renderHook(() => useDataCardFiles('1', '2'))
|
|
52
|
+
expect(result.current).toStrictEqual({ fetchStatus: 'loading' })
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('handles files loading with more partial data', () => {
|
|
56
|
+
mockUseQuery.mockReturnValueOnce({
|
|
57
|
+
fetchStatus: 'loading',
|
|
58
|
+
data: [mockFile1, mockFile2]
|
|
59
|
+
})
|
|
60
|
+
mockUseQuery.mockReturnValueOnce({
|
|
61
|
+
fetchStatus: 'loading',
|
|
62
|
+
data: [mockFile3, mockFile4]
|
|
63
|
+
})
|
|
64
|
+
const { result } = renderHook(() => useDataCardFiles('1', '2'))
|
|
65
|
+
expect(result.current).toStrictEqual({ fetchStatus: 'loading' })
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('handles files loading with empty data', () => {
|
|
69
|
+
mockUseQuery.mockReturnValueOnce({
|
|
70
|
+
fetchStatus: 'loaded',
|
|
71
|
+
data: [],
|
|
72
|
+
lastFetch: 1
|
|
73
|
+
})
|
|
74
|
+
mockUseQuery.mockReturnValueOnce({
|
|
75
|
+
fetchStatus: 'loaded',
|
|
76
|
+
data: [],
|
|
77
|
+
lastFetch: 1
|
|
78
|
+
})
|
|
79
|
+
const { result } = renderHook(() => useDataCardFiles('1', '2'))
|
|
80
|
+
expect(result.current).toStrictEqual({ fetchStatus: 'empty' })
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('handles files loaded and return in correct order', () => {
|
|
84
|
+
mockUseQuery.mockReturnValueOnce({
|
|
85
|
+
fetchStatus: 'loaded',
|
|
86
|
+
data: [mockFile2, mockFile1],
|
|
87
|
+
lastFetch: 1
|
|
88
|
+
})
|
|
89
|
+
mockUseQuery.mockReturnValueOnce({
|
|
90
|
+
fetchStatus: 'loaded',
|
|
91
|
+
data: [mockFile3, mockFile4],
|
|
92
|
+
lastFetch: 1
|
|
93
|
+
})
|
|
94
|
+
const { result } = renderHook(() => useDataCardFiles('1', '2'))
|
|
95
|
+
expect(result.current).toStrictEqual({
|
|
96
|
+
data: [mockFile1, mockFile2, mockFile3, mockFile4],
|
|
97
|
+
fetchStatus: 'loaded'
|
|
98
|
+
})
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
it('handles files loaded with identical double return', () => {
|
|
102
|
+
mockUseQuery.mockReturnValueOnce({
|
|
103
|
+
fetchStatus: 'loaded',
|
|
104
|
+
data: [mockFile1, mockFile2, mockFile3, mockFile4],
|
|
105
|
+
lastFetch: 1
|
|
106
|
+
})
|
|
107
|
+
mockUseQuery.mockReturnValueOnce({
|
|
108
|
+
fetchStatus: 'loaded',
|
|
109
|
+
data: [mockFile3, mockFile2, mockFile3, mockFile4],
|
|
110
|
+
lastFetch: 1
|
|
111
|
+
})
|
|
112
|
+
const { result } = renderHook(() => useDataCardFiles('1', '2'))
|
|
113
|
+
expect(result.current).toStrictEqual({
|
|
114
|
+
data: [mockFile1, mockFile2, mockFile3, mockFile4],
|
|
115
|
+
fetchStatus: 'loaded'
|
|
116
|
+
})
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
it('handles files loaded with more than 5 result', () => {
|
|
120
|
+
mockUseQuery.mockReturnValueOnce({
|
|
121
|
+
fetchStatus: 'loaded',
|
|
122
|
+
data: [mockFile1, mockFile2, mockFile3, mockFile4, mockFile5, mockFile6],
|
|
123
|
+
lastFetch: 1
|
|
124
|
+
})
|
|
125
|
+
mockUseQuery.mockReturnValueOnce({
|
|
126
|
+
fetchStatus: 'loaded',
|
|
127
|
+
data: [mockFile7, mockFile8, mockFile9, mockFile10, mockFile11, mockFile12],
|
|
128
|
+
lastFetch: 1
|
|
129
|
+
})
|
|
130
|
+
const { result } = renderHook(() => useDataCardFiles('1', '2'))
|
|
131
|
+
expect(result.current).toStrictEqual({
|
|
132
|
+
data: [mockFile1, mockFile2, mockFile3, mockFile4, mockFile5],
|
|
133
|
+
fetchStatus: 'loaded'
|
|
134
|
+
})
|
|
135
|
+
})
|