cozy-harvest-lib 22.0.7 → 22.1.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 +23 -0
- package/dist/components/TwoFAModal.js +1 -1
- package/dist/components/TwoFAModal.spec.js +75 -37
- package/dist/datacards/DoctypeDebugCard.js +72 -0
- package/dist/datacards/DoctypeDebugCard.stories.js +152 -0
- package/package.json +5 -4
- package/src/components/TwoFAModal.jsx +1 -1
- package/src/components/TwoFAModal.spec.jsx +25 -2
- package/src/datacards/DoctypeDebugCard.jsx +85 -0
- package/src/datacards/DoctypeDebugCard.stories.jsx +179 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,29 @@
|
|
|
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
|
+
# [22.1.0](https://github.com/cozy/cozy-libs/compare/cozy-harvest-lib@22.0.8...cozy-harvest-lib@22.1.0) (2024-01-25)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* Add DoctypeDebugCard component ([0741319](https://github.com/cozy/cozy-libs/commit/07413196c1dd82fa23c37cc96737399eb99ea2e2))
|
|
12
|
+
* Upgrade cozy-client to 45.1.0 ([05e8d65](https://github.com/cozy/cozy-libs/commit/05e8d65289cf40833997bcbacef62e2cd9de3adb))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
## [22.0.8](https://github.com/cozy/cozy-libs/compare/cozy-harvest-lib@22.0.7...cozy-harvest-lib@22.0.8) (2024-01-23)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Bug Fixes
|
|
22
|
+
|
|
23
|
+
* No more disabled submit button on 2nd 2FA ([7bdd26c](https://github.com/cozy/cozy-libs/commit/7bdd26c381f8883ea007fafb5515bb8625da67a1))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
6
29
|
## [22.0.7](https://github.com/cozy/cozy-libs/compare/cozy-harvest-lib@22.0.6...cozy-harvest-lib@22.0.7) (2024-01-17)
|
|
7
30
|
|
|
8
31
|
|
|
@@ -69,7 +69,7 @@ export var TwoFAModal = /*#__PURE__*/function (_PureComponent) {
|
|
|
69
69
|
var flowState = this.props.flow.getState();
|
|
70
70
|
this.setState({
|
|
71
71
|
hasErrored: flowState.twoFARetry,
|
|
72
|
-
isJobRunning: flowState.twoFARunning
|
|
72
|
+
isJobRunning: flowState.twoFARunning
|
|
73
73
|
});
|
|
74
74
|
}
|
|
75
75
|
}, {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
2
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
3
|
+
import { render, fireEvent, waitFor } from '@testing-library/react';
|
|
2
4
|
import React from 'react';
|
|
3
5
|
import TwoFAModal from './TwoFAModal';
|
|
4
6
|
import AppLike from '../../test/AppLike';
|
|
@@ -91,41 +93,77 @@ describe('TwoFAModal', function () {
|
|
|
91
93
|
expect(root.queryByPlaceholderText('')).toBeFalsy();
|
|
92
94
|
expect(root.getByText("You need to open your provider's app to confirm your authentication. In some cases, you will have to validate two times."));
|
|
93
95
|
});
|
|
94
|
-
it('should work for several two fa requests', function () {
|
|
95
|
-
var opts
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
96
|
+
it('should work for several two fa requests', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
97
|
+
var opts, _setup3, root, flow, input, button, input2, input3;
|
|
98
|
+
|
|
99
|
+
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
100
|
+
while (1) {
|
|
101
|
+
switch (_context.prev = _context.next) {
|
|
102
|
+
case 0:
|
|
103
|
+
opts = {
|
|
104
|
+
account: {
|
|
105
|
+
state: 'TWO_FA_NEEDED.SMS'
|
|
106
|
+
},
|
|
107
|
+
konnectorSlug: 'boursoma83'
|
|
108
|
+
};
|
|
109
|
+
_setup3 = setup(opts), root = _setup3.root, flow = _setup3.flow;
|
|
110
|
+
input = root.getByPlaceholderText('');
|
|
111
|
+
expect(input).toBeTruthy(); // expect(inp.length).toBe(1)
|
|
112
|
+
// expect((root)).toBe('')
|
|
113
|
+
|
|
114
|
+
expect(root.getByText('This code enables you to finish your connexion.')).toBeTruthy();
|
|
115
|
+
expect(root.getByText('code')).toBeTruthy();
|
|
116
|
+
fireEvent.change(input, {
|
|
117
|
+
target: {
|
|
118
|
+
value: 'abcd'
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
button = root.getByText('Validate').closest('button');
|
|
122
|
+
expect(button.getAttribute('aria-disabled')).toBe(null);
|
|
123
|
+
fireEvent.click(button); // 2nd 2FA request
|
|
124
|
+
|
|
125
|
+
flow.emit('twoFARequest');
|
|
126
|
+
expect(getInputValue(root)).toBe('');
|
|
127
|
+
expect(root.getByText('The second code received on your mobile phone or by email enables you to finalize your connexion.')).toBeTruthy();
|
|
128
|
+
expect(root.getByText('Second code')).toBeTruthy();
|
|
129
|
+
input2 = root.getByPlaceholderText('');
|
|
130
|
+
fireEvent.change(input2, {
|
|
131
|
+
target: {
|
|
132
|
+
value: 'abcd'
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
_context.next = 18;
|
|
136
|
+
return waitFor(function () {
|
|
137
|
+
return expect(root.getByText('Validate').closest('button').getAttribute('aria-disabled')).toBe(null);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
case 18:
|
|
141
|
+
flow.emit('twoFARequest'); // 3rd 2FA (should not happen, hypothetical case)
|
|
142
|
+
|
|
143
|
+
flow.emit('twoFARequest');
|
|
144
|
+
expect(getInputValue(root)).toBe('');
|
|
145
|
+
input3 = root.getByPlaceholderText('');
|
|
146
|
+
fireEvent.change(input3, {
|
|
147
|
+
target: {
|
|
148
|
+
value: 'abcd'
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
_context.next = 25;
|
|
152
|
+
return waitFor(function () {
|
|
153
|
+
return expect(root.getByText('Validate').closest('button').getAttribute('aria-disabled')).toBe(null);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
case 25:
|
|
157
|
+
// First attempt translations are re-used
|
|
158
|
+
expect(root.getByText('This code enables you to finish your connexion.')).toBeTruthy();
|
|
159
|
+
expect(root.getByText('code (4)')).toBeTruthy();
|
|
160
|
+
flow.emit('twoFARequest');
|
|
161
|
+
|
|
162
|
+
case 28:
|
|
163
|
+
case "end":
|
|
164
|
+
return _context.stop();
|
|
165
|
+
}
|
|
115
166
|
}
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
flow.emit('twoFARequest');
|
|
119
|
-
expect(getInputValue(root)).toBe('');
|
|
120
|
-
expect(root.getByText('The second code received on your mobile phone or by email enables you to finalize your connexion.')).toBeTruthy();
|
|
121
|
-
expect(root.getByText('Second code')).toBeTruthy();
|
|
122
|
-
flow.emit('twoFARequest'); // 3rd 2FA (should not happen, hypothetical case)
|
|
123
|
-
|
|
124
|
-
flow.emit('twoFARequest');
|
|
125
|
-
expect(getInputValue(root)).toBe(''); // First attempt translations are re-used
|
|
126
|
-
|
|
127
|
-
expect(root.getByText('This code enables you to finish your connexion.')).toBeTruthy();
|
|
128
|
-
expect(root.getByText('code (4)')).toBeTruthy();
|
|
129
|
-
flow.emit('twoFARequest');
|
|
130
|
-
});
|
|
167
|
+
}, _callee);
|
|
168
|
+
})));
|
|
131
169
|
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import PropTypes from 'prop-types';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import ReactJsonPrint from 'react-json-print';
|
|
4
|
+
import CozyClient, { Q, useQuery, hasQueryBeenLoaded } from 'cozy-client';
|
|
5
|
+
import Button from 'cozy-ui/transpiled/react/Buttons';
|
|
6
|
+
import Card from 'cozy-ui/transpiled/react/Card';
|
|
7
|
+
import Divider from 'cozy-ui/transpiled/react/Divider';
|
|
8
|
+
import Typography from 'cozy-ui/transpiled/react/Typography';
|
|
9
|
+
import logger from '../logger';
|
|
10
|
+
/**
|
|
11
|
+
* This component display json extracted doctype data
|
|
12
|
+
*
|
|
13
|
+
* @component
|
|
14
|
+
* @param {Object} props - The component props.
|
|
15
|
+
* @param {string} props.doctype - The doctype name
|
|
16
|
+
* @param {Array} props.data - The array of doctype values
|
|
17
|
+
* @returns {JSX.Element} The rendered DoctypeDebugCard component.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
var DoctypeDebugCard = function DoctypeDebugCard(_ref) {
|
|
21
|
+
var _navigator$clipboard;
|
|
22
|
+
|
|
23
|
+
var sourceAccountIdentifier = _ref.sourceAccountIdentifier,
|
|
24
|
+
konnector = _ref.konnector,
|
|
25
|
+
doctype = _ref.doctype;
|
|
26
|
+
var savedDocuments = useQuery(Q(doctype).where({
|
|
27
|
+
cozyMetadata: {
|
|
28
|
+
createdByApp: konnector.slug,
|
|
29
|
+
sourceAccountIdentifier: sourceAccountIdentifier
|
|
30
|
+
}
|
|
31
|
+
}).indexFields(['cozyMetadata.createdByApp', 'cozyMetadata.sourceAccountIdentifier', 'cozyMetadata.updatedAt']).sortBy([{
|
|
32
|
+
'cozyMetadata.createdByApp': 'desc'
|
|
33
|
+
}, {
|
|
34
|
+
'cozyMetadata.sourceAccountIdentifier': 'desc'
|
|
35
|
+
}, {
|
|
36
|
+
'cozyMetadata.updatedAt': 'desc'
|
|
37
|
+
}]).limitBy(30), {
|
|
38
|
+
as: "".concat(doctype, "/createdByApp/").concat(konnector.slug, "/sourceAccountIdentifier/").concat(sourceAccountIdentifier),
|
|
39
|
+
fetchPolicy: CozyClient.fetchPolicies.olderThan(30 * 1000)
|
|
40
|
+
});
|
|
41
|
+
var loaded = hasQueryBeenLoaded(savedDocuments);
|
|
42
|
+
var failed = savedDocuments.fetchStatus === 'failed';
|
|
43
|
+
|
|
44
|
+
if (failed) {
|
|
45
|
+
logger.error("DoctypeDebugCard ".concat(doctype, " : failed to fetch"));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
var clipBoardAvailable = (_navigator$clipboard = navigator.clipboard) === null || _navigator$clipboard === void 0 ? void 0 : _navigator$clipboard.writeText;
|
|
49
|
+
return !failed && loaded ? /*#__PURE__*/React.createElement(Card, null, /*#__PURE__*/React.createElement(Typography, {
|
|
50
|
+
variant: "button"
|
|
51
|
+
}, doctype), clipBoardAvailable ? /*#__PURE__*/React.createElement(Button, {
|
|
52
|
+
label: "copy",
|
|
53
|
+
variant: "text",
|
|
54
|
+
size: "small",
|
|
55
|
+
onClick: function onClick() {
|
|
56
|
+
return navigator.clipboard.writeText(JSON.stringify(savedDocuments.data, null, 2)).catch(function (err) {
|
|
57
|
+
return logger.error("Could not copy json object to clipboard: ".concat(err.message));
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}) : null, /*#__PURE__*/React.createElement(Divider, {
|
|
61
|
+
className: "u-ml-0 u-maw-100 u-mb-half"
|
|
62
|
+
}), /*#__PURE__*/React.createElement(ReactJsonPrint, {
|
|
63
|
+
dataObject: savedDocuments.data
|
|
64
|
+
})) : null;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
DoctypeDebugCard.propTypes = {
|
|
68
|
+
sourceAccountIdentifier: PropTypes.string,
|
|
69
|
+
konnector: PropTypes.object,
|
|
70
|
+
doctype: PropTypes.string
|
|
71
|
+
};
|
|
72
|
+
export default DoctypeDebugCard;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { CozyProvider } from 'cozy-client';
|
|
3
|
+
import { createFakeClient } from 'cozy-client/dist/mock';
|
|
4
|
+
import DoctypeDebugCard from './DoctypeDebugCard';
|
|
5
|
+
var meta = {
|
|
6
|
+
component: DoctypeDebugCard,
|
|
7
|
+
render: function render() {
|
|
8
|
+
var data = [{
|
|
9
|
+
_id: '180e24edac1433626f57a548481c045b',
|
|
10
|
+
_rev: '1-40014a89ba8dddc04d9718461e543303',
|
|
11
|
+
amount: 51.77,
|
|
12
|
+
cozyMetadata: {
|
|
13
|
+
createdAt: '2023-09-01T08:20:45.774Z',
|
|
14
|
+
createdByApp: 'template',
|
|
15
|
+
createdByAppVersion: '1.0.0',
|
|
16
|
+
doctypeVersion: 1,
|
|
17
|
+
metadataVersion: 1,
|
|
18
|
+
sourceAccount: '180e24edac1433626f57a548481aa62d',
|
|
19
|
+
sourceAccountIdentifier: 'testSourceAccountIdentifier',
|
|
20
|
+
updatedAt: '2023-09-01T08:20:45.774Z',
|
|
21
|
+
updatedByApps: [{
|
|
22
|
+
date: '2023-09-01T08:20:45.774Z',
|
|
23
|
+
slug: 'template',
|
|
24
|
+
version: '1.0.0'
|
|
25
|
+
}]
|
|
26
|
+
},
|
|
27
|
+
currency: 'EUR',
|
|
28
|
+
date: '2023-09-01T08:20:31.338Z',
|
|
29
|
+
filename: '2023-09-01_template_51.77EUR.jpg',
|
|
30
|
+
fileurl: 'http://books.toscrape.com/media/cache/2c/da/2cdad67c44b002e7ead0cc35693c0e8b.jpg',
|
|
31
|
+
invoice: 'io.cozy.files:180e24edac1433626f57a548481aca62',
|
|
32
|
+
matchingCriterias: {
|
|
33
|
+
labelRegex: '\\bbooks\\b'
|
|
34
|
+
},
|
|
35
|
+
title: 'A Light in the Attic',
|
|
36
|
+
vendor: 'template'
|
|
37
|
+
}, {
|
|
38
|
+
_id: '180e24edac1433626f57a548481c136e',
|
|
39
|
+
_rev: '1-54702210d9be33650da61001cdff18cc',
|
|
40
|
+
amount: 45.17,
|
|
41
|
+
cozyMetadata: {
|
|
42
|
+
createdAt: '2023-09-01T08:20:45.837Z',
|
|
43
|
+
createdByApp: 'template',
|
|
44
|
+
createdByAppVersion: '1.0.0',
|
|
45
|
+
doctypeVersion: 1,
|
|
46
|
+
metadataVersion: 1,
|
|
47
|
+
sourceAccount: '180e24edac1433626f57a548481aa62d',
|
|
48
|
+
sourceAccountIdentifier: 'testSourceAccountIdentifier',
|
|
49
|
+
updatedAt: '2023-09-01T08:20:45.837Z',
|
|
50
|
+
updatedByApps: [{
|
|
51
|
+
date: '2023-09-01T08:20:45.837Z',
|
|
52
|
+
slug: 'template',
|
|
53
|
+
version: '1.0.0'
|
|
54
|
+
}]
|
|
55
|
+
},
|
|
56
|
+
currency: 'EUR',
|
|
57
|
+
date: '2023-09-01T08:20:31.400Z',
|
|
58
|
+
filename: '2023-09-01_template_45.17EUR.jpg',
|
|
59
|
+
fileurl: 'http://books.toscrape.com/media/cache/27/a5/27a53d0bb95bdd88288eaf66c9230d7e.jpg',
|
|
60
|
+
invoice: 'io.cozy.files:180e24edac1433626f57a548481ad96a',
|
|
61
|
+
matchingCriterias: {
|
|
62
|
+
labelRegex: '\\bbooks\\b'
|
|
63
|
+
},
|
|
64
|
+
title: "It's Only the Himalayas",
|
|
65
|
+
vendor: 'template'
|
|
66
|
+
}, {
|
|
67
|
+
_id: '180e24edac1433626f57a548481c179f',
|
|
68
|
+
_rev: '1-d1b5f977455d918b2c2b9fd27f2e8120',
|
|
69
|
+
amount: 51.33,
|
|
70
|
+
cozyMetadata: {
|
|
71
|
+
createdAt: '2023-09-01T08:20:45.884Z',
|
|
72
|
+
createdByApp: 'template',
|
|
73
|
+
createdByAppVersion: '1.0.0',
|
|
74
|
+
doctypeVersion: 1,
|
|
75
|
+
metadataVersion: 1,
|
|
76
|
+
sourceAccount: '180e24edac1433626f57a548481aa62d',
|
|
77
|
+
sourceAccountIdentifier: 'testSourceAccountIdentifier',
|
|
78
|
+
updatedAt: '2023-09-01T08:20:45.884Z',
|
|
79
|
+
updatedByApps: [{
|
|
80
|
+
date: '2023-09-01T08:20:45.884Z',
|
|
81
|
+
slug: 'template',
|
|
82
|
+
version: '1.0.0'
|
|
83
|
+
}]
|
|
84
|
+
},
|
|
85
|
+
currency: 'EUR',
|
|
86
|
+
date: '2023-09-01T08:20:31.400Z',
|
|
87
|
+
filename: '2023-09-01_template_51.33EUR.jpg',
|
|
88
|
+
fileurl: 'http://books.toscrape.com/media/cache/0b/bc/0bbcd0a6f4bcd81ccb1049a52736406e.jpg',
|
|
89
|
+
invoice: 'io.cozy.files:180e24edac1433626f57a548481ae79c',
|
|
90
|
+
matchingCriterias: {
|
|
91
|
+
labelRegex: '\\bbooks\\b'
|
|
92
|
+
},
|
|
93
|
+
title: 'Libertarianism for Beginners',
|
|
94
|
+
vendor: 'template'
|
|
95
|
+
}, {
|
|
96
|
+
_id: '180e24edac1433626f57a548481c1c75',
|
|
97
|
+
_rev: '1-292df85b486fe8e67ce5d4d4c5293771',
|
|
98
|
+
amount: 37.59,
|
|
99
|
+
cozyMetadata: {
|
|
100
|
+
createdAt: '2023-09-01T08:20:45.935Z',
|
|
101
|
+
createdByApp: 'template',
|
|
102
|
+
createdByAppVersion: '1.0.0',
|
|
103
|
+
doctypeVersion: 1,
|
|
104
|
+
metadataVersion: 1,
|
|
105
|
+
sourceAccount: '180e24edac1433626f57a548481aa62d',
|
|
106
|
+
sourceAccountIdentifier: 'testSourceAccountIdentifier',
|
|
107
|
+
updatedAt: '2023-09-01T08:20:45.935Z',
|
|
108
|
+
updatedByApps: [{
|
|
109
|
+
date: '2023-09-01T08:20:45.935Z',
|
|
110
|
+
slug: 'template',
|
|
111
|
+
version: '1.0.0'
|
|
112
|
+
}]
|
|
113
|
+
},
|
|
114
|
+
currency: 'EUR',
|
|
115
|
+
date: '2023-09-01T08:20:31.400Z',
|
|
116
|
+
filename: '2023-09-01_template_37.59EUR.jpg',
|
|
117
|
+
fileurl: 'http://books.toscrape.com/media/cache/09/a3/09a3aef48557576e1a85ba7efea8ecb7.jpg',
|
|
118
|
+
invoice: 'io.cozy.files:180e24edac1433626f57a548481af3d8',
|
|
119
|
+
matchingCriterias: {
|
|
120
|
+
labelRegex: '\\bbooks\\b'
|
|
121
|
+
},
|
|
122
|
+
title: 'Mesaerion: The Best Science Fiction Stories 1800-1849',
|
|
123
|
+
vendor: 'template'
|
|
124
|
+
}];
|
|
125
|
+
var client = createFakeClient({
|
|
126
|
+
queries: {
|
|
127
|
+
'doctypeDebugCard_io.cozy.bills': {
|
|
128
|
+
doctype: 'io.cozy.bills',
|
|
129
|
+
definition: {
|
|
130
|
+
doctype: 'io.cozy.bills',
|
|
131
|
+
id: "io.cozy.bills/createdByApp/template/sourceAccountIdentifier/testSourceAccountIdentifier"
|
|
132
|
+
},
|
|
133
|
+
data: data
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
var konnector = {
|
|
138
|
+
slug: 'template'
|
|
139
|
+
};
|
|
140
|
+
return /*#__PURE__*/React.createElement(CozyProvider, {
|
|
141
|
+
client: client
|
|
142
|
+
}, /*#__PURE__*/React.createElement(DoctypeDebugCard, {
|
|
143
|
+
doctype: "io.cozy.bills",
|
|
144
|
+
konnector: konnector,
|
|
145
|
+
sourceAccountIdentifier: "testSourceAccountIdentifier"
|
|
146
|
+
}));
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
export default meta;
|
|
150
|
+
export var Default = {
|
|
151
|
+
name: 'default'
|
|
152
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cozy-harvest-lib",
|
|
3
|
-
"version": "22.0
|
|
3
|
+
"version": "22.1.0",
|
|
4
4
|
"description": "Provides logic, modules and components for Cozy's harvest applications.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"author": "Cozy",
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"microee": "^0.0.6",
|
|
42
42
|
"node-polyglot": "^2.4.0",
|
|
43
43
|
"react-final-form": "^3.7.0",
|
|
44
|
+
"react-json-print": "^0.1.3",
|
|
44
45
|
"react-markdown": "^4.2.2",
|
|
45
46
|
"use-deep-compare-effect": "^1.8.1",
|
|
46
47
|
"uuid": "^3.3.2"
|
|
@@ -64,7 +65,7 @@
|
|
|
64
65
|
"babel-jest": "26.6.3",
|
|
65
66
|
"babel-plugin-inline-react-svg": "1.1.2",
|
|
66
67
|
"babel-preset-cozy-app": "^2.1.0",
|
|
67
|
-
"cozy-client": "^45.0
|
|
68
|
+
"cozy-client": "^45.1.0",
|
|
68
69
|
"cozy-device-helper": "^3.0.0",
|
|
69
70
|
"cozy-flags": "^3.2.2",
|
|
70
71
|
"cozy-intent": "^2.19.2",
|
|
@@ -93,7 +94,7 @@
|
|
|
93
94
|
},
|
|
94
95
|
"peerDependencies": {
|
|
95
96
|
"@babel/runtime": ">=7.12.5",
|
|
96
|
-
"cozy-client": ">=45.0
|
|
97
|
+
"cozy-client": ">=45.1.0",
|
|
97
98
|
"cozy-device-helper": ">=2.6.0",
|
|
98
99
|
"cozy-flags": ">=2.3.5",
|
|
99
100
|
"cozy-intent": ">=1.14.1",
|
|
@@ -106,5 +107,5 @@
|
|
|
106
107
|
"react-router-dom": ">=4.3.1"
|
|
107
108
|
},
|
|
108
109
|
"sideEffects": false,
|
|
109
|
-
"gitHead": "
|
|
110
|
+
"gitHead": "f9c3597079f8b120e43249d752227da9a2e63541"
|
|
110
111
|
}
|
|
@@ -47,7 +47,7 @@ export class TwoFAModal extends PureComponent {
|
|
|
47
47
|
const flowState = this.props.flow.getState()
|
|
48
48
|
this.setState({
|
|
49
49
|
hasErrored: flowState.twoFARetry,
|
|
50
|
-
isJobRunning: flowState.twoFARunning
|
|
50
|
+
isJobRunning: flowState.twoFARunning
|
|
51
51
|
})
|
|
52
52
|
}
|
|
53
53
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { render, fireEvent } from '@testing-library/react'
|
|
1
|
+
import { render, fireEvent, waitFor } from '@testing-library/react'
|
|
2
2
|
import React from 'react'
|
|
3
3
|
|
|
4
4
|
import TwoFAModal from './TwoFAModal'
|
|
@@ -82,7 +82,7 @@ describe('TwoFAModal', () => {
|
|
|
82
82
|
)
|
|
83
83
|
})
|
|
84
84
|
|
|
85
|
-
it('should work for several two fa requests', () => {
|
|
85
|
+
it('should work for several two fa requests', async () => {
|
|
86
86
|
const opts = {
|
|
87
87
|
account: {
|
|
88
88
|
state: 'TWO_FA_NEEDED.SMS'
|
|
@@ -103,6 +103,9 @@ describe('TwoFAModal', () => {
|
|
|
103
103
|
expect(root.getByText('code')).toBeTruthy()
|
|
104
104
|
|
|
105
105
|
fireEvent.change(input, { target: { value: 'abcd' } })
|
|
106
|
+
const button = root.getByText('Validate').closest('button')
|
|
107
|
+
expect(button.getAttribute('aria-disabled')).toBe(null)
|
|
108
|
+
fireEvent.click(button)
|
|
106
109
|
|
|
107
110
|
// 2nd 2FA request
|
|
108
111
|
flow.emit('twoFARequest')
|
|
@@ -115,12 +118,32 @@ describe('TwoFAModal', () => {
|
|
|
115
118
|
).toBeTruthy()
|
|
116
119
|
|
|
117
120
|
expect(root.getByText('Second code')).toBeTruthy()
|
|
121
|
+
const input2 = root.getByPlaceholderText('')
|
|
122
|
+
fireEvent.change(input2, { target: { value: 'abcd' } })
|
|
123
|
+
await waitFor(() =>
|
|
124
|
+
expect(
|
|
125
|
+
root
|
|
126
|
+
.getByText('Validate')
|
|
127
|
+
.closest('button')
|
|
128
|
+
.getAttribute('aria-disabled')
|
|
129
|
+
).toBe(null)
|
|
130
|
+
)
|
|
118
131
|
flow.emit('twoFARequest')
|
|
119
132
|
|
|
120
133
|
// 3rd 2FA (should not happen, hypothetical case)
|
|
121
134
|
flow.emit('twoFARequest')
|
|
122
135
|
|
|
123
136
|
expect(getInputValue(root)).toBe('')
|
|
137
|
+
const input3 = root.getByPlaceholderText('')
|
|
138
|
+
fireEvent.change(input3, { target: { value: 'abcd' } })
|
|
139
|
+
await waitFor(() =>
|
|
140
|
+
expect(
|
|
141
|
+
root
|
|
142
|
+
.getByText('Validate')
|
|
143
|
+
.closest('button')
|
|
144
|
+
.getAttribute('aria-disabled')
|
|
145
|
+
).toBe(null)
|
|
146
|
+
)
|
|
124
147
|
// First attempt translations are re-used
|
|
125
148
|
expect(
|
|
126
149
|
root.getByText('This code enables you to finish your connexion.')
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import PropTypes from 'prop-types'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import ReactJsonPrint from 'react-json-print'
|
|
4
|
+
|
|
5
|
+
import CozyClient, { Q, useQuery, hasQueryBeenLoaded } from 'cozy-client'
|
|
6
|
+
import Button from 'cozy-ui/transpiled/react/Buttons'
|
|
7
|
+
import Card from 'cozy-ui/transpiled/react/Card'
|
|
8
|
+
import Divider from 'cozy-ui/transpiled/react/Divider'
|
|
9
|
+
import Typography from 'cozy-ui/transpiled/react/Typography'
|
|
10
|
+
|
|
11
|
+
import logger from '../logger'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* This component display json extracted doctype data
|
|
15
|
+
*
|
|
16
|
+
* @component
|
|
17
|
+
* @param {Object} props - The component props.
|
|
18
|
+
* @param {string} props.doctype - The doctype name
|
|
19
|
+
* @param {Array} props.data - The array of doctype values
|
|
20
|
+
* @returns {JSX.Element} The rendered DoctypeDebugCard component.
|
|
21
|
+
*/
|
|
22
|
+
const DoctypeDebugCard = ({ sourceAccountIdentifier, konnector, doctype }) => {
|
|
23
|
+
const savedDocuments = useQuery(
|
|
24
|
+
Q(doctype)
|
|
25
|
+
.where({
|
|
26
|
+
cozyMetadata: {
|
|
27
|
+
createdByApp: konnector.slug,
|
|
28
|
+
sourceAccountIdentifier
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
.indexFields([
|
|
32
|
+
'cozyMetadata.createdByApp',
|
|
33
|
+
'cozyMetadata.sourceAccountIdentifier',
|
|
34
|
+
'cozyMetadata.updatedAt'
|
|
35
|
+
])
|
|
36
|
+
.sortBy([
|
|
37
|
+
{ 'cozyMetadata.createdByApp': 'desc' },
|
|
38
|
+
{ 'cozyMetadata.sourceAccountIdentifier': 'desc' },
|
|
39
|
+
{ 'cozyMetadata.updatedAt': 'desc' }
|
|
40
|
+
])
|
|
41
|
+
.limitBy(30),
|
|
42
|
+
{
|
|
43
|
+
as: `${doctype}/createdByApp/${konnector.slug}/sourceAccountIdentifier/${sourceAccountIdentifier}`,
|
|
44
|
+
fetchPolicy: CozyClient.fetchPolicies.olderThan(30 * 1000)
|
|
45
|
+
}
|
|
46
|
+
)
|
|
47
|
+
const loaded = hasQueryBeenLoaded(savedDocuments)
|
|
48
|
+
const failed = savedDocuments.fetchStatus === 'failed'
|
|
49
|
+
if (failed) {
|
|
50
|
+
logger.error(`DoctypeDebugCard ${doctype} : failed to fetch`)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const clipBoardAvailable = navigator.clipboard?.writeText
|
|
54
|
+
return !failed && loaded ? (
|
|
55
|
+
<Card>
|
|
56
|
+
<Typography variant="button">{doctype}</Typography>
|
|
57
|
+
{clipBoardAvailable ? (
|
|
58
|
+
<Button
|
|
59
|
+
label="copy"
|
|
60
|
+
variant="text"
|
|
61
|
+
size="small"
|
|
62
|
+
onClick={() =>
|
|
63
|
+
navigator.clipboard
|
|
64
|
+
.writeText(JSON.stringify(savedDocuments.data, null, 2))
|
|
65
|
+
.catch(err =>
|
|
66
|
+
logger.error(
|
|
67
|
+
`Could not copy json object to clipboard: ${err.message}`
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
/>
|
|
72
|
+
) : null}
|
|
73
|
+
<Divider className="u-ml-0 u-maw-100 u-mb-half" />
|
|
74
|
+
<ReactJsonPrint dataObject={savedDocuments.data} />
|
|
75
|
+
</Card>
|
|
76
|
+
) : null
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
DoctypeDebugCard.propTypes = {
|
|
80
|
+
sourceAccountIdentifier: PropTypes.string,
|
|
81
|
+
konnector: PropTypes.object,
|
|
82
|
+
doctype: PropTypes.string
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export default DoctypeDebugCard
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import { CozyProvider } from 'cozy-client'
|
|
4
|
+
import { createFakeClient } from 'cozy-client/dist/mock'
|
|
5
|
+
|
|
6
|
+
import DoctypeDebugCard from './DoctypeDebugCard'
|
|
7
|
+
|
|
8
|
+
const meta = {
|
|
9
|
+
component: DoctypeDebugCard,
|
|
10
|
+
render: () => {
|
|
11
|
+
const data = [
|
|
12
|
+
{
|
|
13
|
+
_id: '180e24edac1433626f57a548481c045b',
|
|
14
|
+
_rev: '1-40014a89ba8dddc04d9718461e543303',
|
|
15
|
+
amount: 51.77,
|
|
16
|
+
cozyMetadata: {
|
|
17
|
+
createdAt: '2023-09-01T08:20:45.774Z',
|
|
18
|
+
createdByApp: 'template',
|
|
19
|
+
createdByAppVersion: '1.0.0',
|
|
20
|
+
doctypeVersion: 1,
|
|
21
|
+
metadataVersion: 1,
|
|
22
|
+
sourceAccount: '180e24edac1433626f57a548481aa62d',
|
|
23
|
+
sourceAccountIdentifier: 'testSourceAccountIdentifier',
|
|
24
|
+
updatedAt: '2023-09-01T08:20:45.774Z',
|
|
25
|
+
updatedByApps: [
|
|
26
|
+
{
|
|
27
|
+
date: '2023-09-01T08:20:45.774Z',
|
|
28
|
+
slug: 'template',
|
|
29
|
+
version: '1.0.0'
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
currency: 'EUR',
|
|
34
|
+
date: '2023-09-01T08:20:31.338Z',
|
|
35
|
+
filename: '2023-09-01_template_51.77EUR.jpg',
|
|
36
|
+
fileurl:
|
|
37
|
+
'http://books.toscrape.com/media/cache/2c/da/2cdad67c44b002e7ead0cc35693c0e8b.jpg',
|
|
38
|
+
invoice: 'io.cozy.files:180e24edac1433626f57a548481aca62',
|
|
39
|
+
matchingCriterias: {
|
|
40
|
+
labelRegex: '\\bbooks\\b'
|
|
41
|
+
},
|
|
42
|
+
title: 'A Light in the Attic',
|
|
43
|
+
vendor: 'template'
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
_id: '180e24edac1433626f57a548481c136e',
|
|
47
|
+
_rev: '1-54702210d9be33650da61001cdff18cc',
|
|
48
|
+
amount: 45.17,
|
|
49
|
+
cozyMetadata: {
|
|
50
|
+
createdAt: '2023-09-01T08:20:45.837Z',
|
|
51
|
+
createdByApp: 'template',
|
|
52
|
+
createdByAppVersion: '1.0.0',
|
|
53
|
+
doctypeVersion: 1,
|
|
54
|
+
metadataVersion: 1,
|
|
55
|
+
sourceAccount: '180e24edac1433626f57a548481aa62d',
|
|
56
|
+
sourceAccountIdentifier: 'testSourceAccountIdentifier',
|
|
57
|
+
updatedAt: '2023-09-01T08:20:45.837Z',
|
|
58
|
+
updatedByApps: [
|
|
59
|
+
{
|
|
60
|
+
date: '2023-09-01T08:20:45.837Z',
|
|
61
|
+
slug: 'template',
|
|
62
|
+
version: '1.0.0'
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
currency: 'EUR',
|
|
67
|
+
date: '2023-09-01T08:20:31.400Z',
|
|
68
|
+
filename: '2023-09-01_template_45.17EUR.jpg',
|
|
69
|
+
fileurl:
|
|
70
|
+
'http://books.toscrape.com/media/cache/27/a5/27a53d0bb95bdd88288eaf66c9230d7e.jpg',
|
|
71
|
+
invoice: 'io.cozy.files:180e24edac1433626f57a548481ad96a',
|
|
72
|
+
matchingCriterias: {
|
|
73
|
+
labelRegex: '\\bbooks\\b'
|
|
74
|
+
},
|
|
75
|
+
title: "It's Only the Himalayas",
|
|
76
|
+
vendor: 'template'
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
_id: '180e24edac1433626f57a548481c179f',
|
|
80
|
+
_rev: '1-d1b5f977455d918b2c2b9fd27f2e8120',
|
|
81
|
+
amount: 51.33,
|
|
82
|
+
cozyMetadata: {
|
|
83
|
+
createdAt: '2023-09-01T08:20:45.884Z',
|
|
84
|
+
createdByApp: 'template',
|
|
85
|
+
createdByAppVersion: '1.0.0',
|
|
86
|
+
doctypeVersion: 1,
|
|
87
|
+
metadataVersion: 1,
|
|
88
|
+
sourceAccount: '180e24edac1433626f57a548481aa62d',
|
|
89
|
+
sourceAccountIdentifier: 'testSourceAccountIdentifier',
|
|
90
|
+
updatedAt: '2023-09-01T08:20:45.884Z',
|
|
91
|
+
updatedByApps: [
|
|
92
|
+
{
|
|
93
|
+
date: '2023-09-01T08:20:45.884Z',
|
|
94
|
+
slug: 'template',
|
|
95
|
+
version: '1.0.0'
|
|
96
|
+
}
|
|
97
|
+
]
|
|
98
|
+
},
|
|
99
|
+
currency: 'EUR',
|
|
100
|
+
date: '2023-09-01T08:20:31.400Z',
|
|
101
|
+
filename: '2023-09-01_template_51.33EUR.jpg',
|
|
102
|
+
fileurl:
|
|
103
|
+
'http://books.toscrape.com/media/cache/0b/bc/0bbcd0a6f4bcd81ccb1049a52736406e.jpg',
|
|
104
|
+
invoice: 'io.cozy.files:180e24edac1433626f57a548481ae79c',
|
|
105
|
+
matchingCriterias: {
|
|
106
|
+
labelRegex: '\\bbooks\\b'
|
|
107
|
+
},
|
|
108
|
+
title: 'Libertarianism for Beginners',
|
|
109
|
+
vendor: 'template'
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
_id: '180e24edac1433626f57a548481c1c75',
|
|
113
|
+
_rev: '1-292df85b486fe8e67ce5d4d4c5293771',
|
|
114
|
+
amount: 37.59,
|
|
115
|
+
cozyMetadata: {
|
|
116
|
+
createdAt: '2023-09-01T08:20:45.935Z',
|
|
117
|
+
createdByApp: 'template',
|
|
118
|
+
createdByAppVersion: '1.0.0',
|
|
119
|
+
doctypeVersion: 1,
|
|
120
|
+
metadataVersion: 1,
|
|
121
|
+
sourceAccount: '180e24edac1433626f57a548481aa62d',
|
|
122
|
+
sourceAccountIdentifier: 'testSourceAccountIdentifier',
|
|
123
|
+
updatedAt: '2023-09-01T08:20:45.935Z',
|
|
124
|
+
updatedByApps: [
|
|
125
|
+
{
|
|
126
|
+
date: '2023-09-01T08:20:45.935Z',
|
|
127
|
+
slug: 'template',
|
|
128
|
+
version: '1.0.0'
|
|
129
|
+
}
|
|
130
|
+
]
|
|
131
|
+
},
|
|
132
|
+
currency: 'EUR',
|
|
133
|
+
date: '2023-09-01T08:20:31.400Z',
|
|
134
|
+
filename: '2023-09-01_template_37.59EUR.jpg',
|
|
135
|
+
fileurl:
|
|
136
|
+
'http://books.toscrape.com/media/cache/09/a3/09a3aef48557576e1a85ba7efea8ecb7.jpg',
|
|
137
|
+
invoice: 'io.cozy.files:180e24edac1433626f57a548481af3d8',
|
|
138
|
+
matchingCriterias: {
|
|
139
|
+
labelRegex: '\\bbooks\\b'
|
|
140
|
+
},
|
|
141
|
+
title: 'Mesaerion: The Best Science Fiction Stories 1800-1849',
|
|
142
|
+
vendor: 'template'
|
|
143
|
+
}
|
|
144
|
+
]
|
|
145
|
+
|
|
146
|
+
const client = createFakeClient({
|
|
147
|
+
queries: {
|
|
148
|
+
'doctypeDebugCard_io.cozy.bills': {
|
|
149
|
+
doctype: 'io.cozy.bills',
|
|
150
|
+
definition: {
|
|
151
|
+
doctype: 'io.cozy.bills',
|
|
152
|
+
id: `io.cozy.bills/createdByApp/template/sourceAccountIdentifier/testSourceAccountIdentifier`
|
|
153
|
+
},
|
|
154
|
+
data
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
const konnector = {
|
|
160
|
+
slug: 'template'
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<CozyProvider client={client}>
|
|
165
|
+
<DoctypeDebugCard
|
|
166
|
+
doctype="io.cozy.bills"
|
|
167
|
+
konnector={konnector}
|
|
168
|
+
sourceAccountIdentifier="testSourceAccountIdentifier"
|
|
169
|
+
/>
|
|
170
|
+
</CozyProvider>
|
|
171
|
+
)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export default meta
|
|
176
|
+
|
|
177
|
+
export const Default = {
|
|
178
|
+
name: 'default'
|
|
179
|
+
}
|