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 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 || flowState.konnectorRunning
72
+ isJobRunning: flowState.twoFARunning
73
73
  });
74
74
  }
75
75
  }, {
@@ -1,4 +1,6 @@
1
- import { render, fireEvent } from '@testing-library/react';
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
- account: {
97
- state: 'TWO_FA_NEEDED.SMS'
98
- },
99
- konnectorSlug: 'boursoma83'
100
- };
101
-
102
- var _setup3 = setup(opts),
103
- root = _setup3.root,
104
- flow = _setup3.flow;
105
-
106
- var input = root.getByPlaceholderText('');
107
- expect(input).toBeTruthy(); // expect(inp.length).toBe(1)
108
- // expect((root)).toBe('')
109
-
110
- expect(root.getByText('This code enables you to finish your connexion.')).toBeTruthy();
111
- expect(root.getByText('code')).toBeTruthy();
112
- fireEvent.change(input, {
113
- target: {
114
- value: 'abcd'
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
- }); // 2nd 2FA request
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.7",
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.1",
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.1",
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": "e96e3f59e027dc5c55614bbe1877b0b7a527b076"
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 || flowState.konnectorRunning
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
+ }