cozy-harvest-lib 8.4.2 → 9.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 +43 -0
- package/dist/components/InAppBrowser.js +65 -0
- package/dist/components/InAppBrowser.spec.js +104 -0
- package/dist/components/KonnectorConfiguration/ConfigurationTab/index.js +5 -2
- package/dist/components/OAuthWindow.js +7 -2
- package/dist/components/TriggerManager.js +32 -8
- package/package.json +8 -6
- package/src/components/AccountForm/index.jsx +3 -1
- package/src/components/InAppBrowser.jsx +33 -0
- package/src/components/InAppBrowser.spec.jsx +60 -0
- package/src/components/KonnectorConfiguration/ConfigurationTab/index.jsx +3 -2
- package/src/components/NewAccountModal.spec.jsx +6 -2
- package/src/components/OAuthWindow.jsx +7 -2
- package/src/components/TriggerManager.jsx +45 -9
- package/src/models/ConnectionFlow.js +1 -1
- package/src/models/ConnectionFlow.spec.js +12 -7
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,49 @@
|
|
|
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
|
+
# [9.1.0](https://github.com/cozy/cozy-libs/compare/cozy-harvest-lib@9.0.0...cozy-harvest-lib@9.1.0) (2022-05-02)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* Multiple fixes after review ([0351500](https://github.com/cozy/cozy-libs/commit/0351500e1845df6ef4a31211aec6061090ccf66e))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
* Open InAppBrowser via cozy-intent when in flaghip app ([5ee31ea](https://github.com/cozy/cozy-libs/commit/5ee31eafcb62e23a6242386bb6b09312f778e871))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# [9.0.0](https://github.com/cozy/cozy-libs/compare/cozy-harvest-lib@8.4.3...cozy-harvest-lib@9.0.0) (2022-04-29)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Bug Fixes
|
|
26
|
+
|
|
27
|
+
* Check if we need to display the unlock form ([fe230ce](https://github.com/cozy/cozy-libs/commit/fe230ce0791c511c31098be47e633408bceb9c30))
|
|
28
|
+
* Upgrade cozy-keys-lib requirement ([c4eb57f](https://github.com/cozy/cozy-libs/commit/c4eb57f22b4a86d42c4422619a158605d894edcf))
|
|
29
|
+
* VaultClient can be undefined at first ([8a6f02b](https://github.com/cozy/cozy-libs/commit/8a6f02b9e9c161622afedff88ba4805468ee6f59))
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
### BREAKING CHANGES
|
|
33
|
+
|
|
34
|
+
* cozy-keys-lib >= 4.1.9 is now
|
|
35
|
+
required.
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
## [8.4.3](https://github.com/cozy/cozy-libs/compare/cozy-harvest-lib@8.4.2...cozy-harvest-lib@8.4.3) (2022-04-28)
|
|
42
|
+
|
|
43
|
+
**Note:** Version bump only for package cozy-harvest-lib
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
6
49
|
## [8.4.2](https://github.com/cozy/cozy-libs/compare/cozy-harvest-lib@8.4.1...cozy-harvest-lib@8.4.2) (2022-04-26)
|
|
7
50
|
|
|
8
51
|
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
2
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
3
|
+
import { useEffect } from 'react';
|
|
4
|
+
import PropTypes from 'prop-types';
|
|
5
|
+
import { useWebviewIntent } from 'cozy-intent';
|
|
6
|
+
import logger from '../logger';
|
|
7
|
+
|
|
8
|
+
var InAppBrowser = function InAppBrowser(_ref) {
|
|
9
|
+
var url = _ref.url,
|
|
10
|
+
onClose = _ref.onClose;
|
|
11
|
+
var webviewIntent = useWebviewIntent();
|
|
12
|
+
useEffect(function () {
|
|
13
|
+
function insideEffect() {
|
|
14
|
+
return _insideEffect.apply(this, arguments);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function _insideEffect() {
|
|
18
|
+
_insideEffect = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
19
|
+
var result;
|
|
20
|
+
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
21
|
+
while (1) {
|
|
22
|
+
switch (_context.prev = _context.next) {
|
|
23
|
+
case 0:
|
|
24
|
+
if (!webviewIntent) {
|
|
25
|
+
_context.next = 5;
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
_context.next = 3;
|
|
30
|
+
return webviewIntent.call('showInAppBrowser', {
|
|
31
|
+
url: url
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
case 3:
|
|
35
|
+
result = _context.sent;
|
|
36
|
+
|
|
37
|
+
if ((result === null || result === void 0 ? void 0 : result.type) === 'cancel' && onClose) {
|
|
38
|
+
onClose();
|
|
39
|
+
} else if ((result === null || result === void 0 ? void 0 : result.type) !== 'dismiss') {
|
|
40
|
+
logger.error('Unexpected InAppBrowser result', result);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
case 5:
|
|
44
|
+
case "end":
|
|
45
|
+
return _context.stop();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}, _callee);
|
|
49
|
+
}));
|
|
50
|
+
return _insideEffect.apply(this, arguments);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
insideEffect();
|
|
54
|
+
return function cleanup() {
|
|
55
|
+
webviewIntent.call('closeInAppBrowser');
|
|
56
|
+
};
|
|
57
|
+
}, [webviewIntent, url, onClose]);
|
|
58
|
+
return null;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
InAppBrowser.propTypes = {
|
|
62
|
+
url: PropTypes.string.isRequired,
|
|
63
|
+
onClose: PropTypes.func
|
|
64
|
+
};
|
|
65
|
+
export default InAppBrowser;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
2
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { render, waitFor } from '@testing-library/react';
|
|
5
|
+
import InAppBrowser from './InAppBrowser';
|
|
6
|
+
import { WebviewIntentProvider } from 'cozy-intent';
|
|
7
|
+
describe('InAppBrowser', function () {
|
|
8
|
+
it('should call showInAppBrowser', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
9
|
+
var url, intentCall, webviewService;
|
|
10
|
+
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
11
|
+
while (1) {
|
|
12
|
+
switch (_context.prev = _context.next) {
|
|
13
|
+
case 0:
|
|
14
|
+
url = 'https://test.url';
|
|
15
|
+
intentCall = jest.fn();
|
|
16
|
+
webviewService = {
|
|
17
|
+
call: intentCall
|
|
18
|
+
};
|
|
19
|
+
intentCall.mockResolvedValue({
|
|
20
|
+
type: 'dismiss'
|
|
21
|
+
});
|
|
22
|
+
render( /*#__PURE__*/React.createElement(WebviewIntentProvider, {
|
|
23
|
+
webviewService: webviewService
|
|
24
|
+
}, /*#__PURE__*/React.createElement(InAppBrowser, {
|
|
25
|
+
url: url
|
|
26
|
+
})));
|
|
27
|
+
expect(webviewService.call).toHaveBeenNthCalledWith(1, 'showInAppBrowser', {
|
|
28
|
+
url: url
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
case 6:
|
|
32
|
+
case "end":
|
|
33
|
+
return _context.stop();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}, _callee);
|
|
37
|
+
})));
|
|
38
|
+
it('should call onClose when user closes the inAppBrowser in app', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
|
|
39
|
+
var url, intentCall, webviewService, onClose;
|
|
40
|
+
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
|
|
41
|
+
while (1) {
|
|
42
|
+
switch (_context2.prev = _context2.next) {
|
|
43
|
+
case 0:
|
|
44
|
+
url = 'https://test.url';
|
|
45
|
+
intentCall = jest.fn();
|
|
46
|
+
webviewService = {
|
|
47
|
+
call: intentCall
|
|
48
|
+
};
|
|
49
|
+
onClose = jest.fn();
|
|
50
|
+
intentCall.mockResolvedValue({
|
|
51
|
+
type: 'cancel'
|
|
52
|
+
});
|
|
53
|
+
render( /*#__PURE__*/React.createElement(WebviewIntentProvider, {
|
|
54
|
+
webviewService: webviewService
|
|
55
|
+
}, /*#__PURE__*/React.createElement(InAppBrowser, {
|
|
56
|
+
url: url,
|
|
57
|
+
onClose: onClose
|
|
58
|
+
})));
|
|
59
|
+
_context2.next = 8;
|
|
60
|
+
return waitFor(function () {
|
|
61
|
+
return expect(onClose).toHaveBeenCalledTimes(1);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
case 8:
|
|
65
|
+
expect(onClose).toHaveBeenCalledWith();
|
|
66
|
+
|
|
67
|
+
case 9:
|
|
68
|
+
case "end":
|
|
69
|
+
return _context2.stop();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}, _callee2);
|
|
73
|
+
})));
|
|
74
|
+
it('should call closeInAppBrowser when the component is unmounted', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
|
|
75
|
+
var url, intentCall, webviewService, _render, unmount;
|
|
76
|
+
|
|
77
|
+
return _regeneratorRuntime.wrap(function _callee3$(_context3) {
|
|
78
|
+
while (1) {
|
|
79
|
+
switch (_context3.prev = _context3.next) {
|
|
80
|
+
case 0:
|
|
81
|
+
url = 'https://test.url';
|
|
82
|
+
intentCall = jest.fn();
|
|
83
|
+
webviewService = {
|
|
84
|
+
call: intentCall
|
|
85
|
+
};
|
|
86
|
+
intentCall.mockResolvedValue({
|
|
87
|
+
type: 'dismiss'
|
|
88
|
+
});
|
|
89
|
+
_render = render( /*#__PURE__*/React.createElement(WebviewIntentProvider, {
|
|
90
|
+
webviewService: webviewService
|
|
91
|
+
}, /*#__PURE__*/React.createElement(InAppBrowser, {
|
|
92
|
+
url: url
|
|
93
|
+
}))), unmount = _render.unmount;
|
|
94
|
+
unmount();
|
|
95
|
+
expect(webviewService.call).toHaveBeenNthCalledWith(2, 'closeInAppBrowser');
|
|
96
|
+
|
|
97
|
+
case 7:
|
|
98
|
+
case "end":
|
|
99
|
+
return _context3.stop();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}, _callee3);
|
|
103
|
+
})));
|
|
104
|
+
});
|
|
@@ -6,7 +6,7 @@ import PropTypes from 'prop-types';
|
|
|
6
6
|
import cx from 'classnames';
|
|
7
7
|
import { useClient } from 'cozy-client';
|
|
8
8
|
import { Account } from 'cozy-doctypes';
|
|
9
|
-
import { useVaultClient } from 'cozy-keys-lib';
|
|
9
|
+
import { useVaultClient, CozyUtils } from 'cozy-keys-lib';
|
|
10
10
|
import Button from 'cozy-ui/transpiled/react/Button';
|
|
11
11
|
import Spinner from 'cozy-ui/transpiled/react/Spinner';
|
|
12
12
|
import palette from 'cozy-ui/transpiled/react/palette';
|
|
@@ -118,7 +118,10 @@ var ConfigurationTab = function ConfigurationTab(_ref2) {
|
|
|
118
118
|
|
|
119
119
|
showUnlockForm({
|
|
120
120
|
closable: true,
|
|
121
|
-
onUnlock: handleUnlockForDeletion
|
|
121
|
+
onUnlock: handleUnlockForDeletion,
|
|
122
|
+
addCheckShouldUnlock: function addCheckShouldUnlock() {
|
|
123
|
+
return CozyUtils.checkHasInstalledExtension(client);
|
|
124
|
+
}
|
|
122
125
|
});
|
|
123
126
|
_context.next = 8;
|
|
124
127
|
break;
|
|
@@ -15,9 +15,11 @@ import PropTypes from 'prop-types';
|
|
|
15
15
|
import { withClient } from 'cozy-client';
|
|
16
16
|
import { translate } from 'cozy-ui/transpiled/react/I18n';
|
|
17
17
|
import CozyRealtime from 'cozy-realtime';
|
|
18
|
+
import { isFlagshipApp } from 'cozy-device-helper';
|
|
18
19
|
import { prepareOAuth, checkOAuthData, terminateOAuth, OAUTH_REALTIME_CHANNEL } from '../helpers/oauth'; // TODO use PopUp from cozy-ui
|
|
19
20
|
|
|
20
21
|
import Popup from './Popup';
|
|
22
|
+
import InAppBrowser from './InAppBrowser';
|
|
21
23
|
var OAUTH_POPUP_HEIGHT = 800;
|
|
22
24
|
var OAUTH_POPUP_WIDTH = 800;
|
|
23
25
|
/**
|
|
@@ -177,14 +179,17 @@ export var OAuthWindow = /*#__PURE__*/function (_PureComponent) {
|
|
|
177
179
|
var _this$state = this.state,
|
|
178
180
|
oAuthUrl = _this$state.oAuthUrl,
|
|
179
181
|
succeed = _this$state.succeed;
|
|
180
|
-
return oAuthUrl && !succeed && /*#__PURE__*/React.createElement(Popup, {
|
|
182
|
+
return oAuthUrl && !succeed && (!isFlagshipApp() ? /*#__PURE__*/React.createElement(Popup, {
|
|
181
183
|
url: oAuthUrl,
|
|
182
184
|
height: OAUTH_POPUP_HEIGHT,
|
|
183
185
|
width: OAUTH_POPUP_WIDTH,
|
|
184
186
|
onClose: this.handleClose,
|
|
185
187
|
onUrlChange: this.handleUrlChange,
|
|
186
188
|
title: t("oauth.window.title")
|
|
187
|
-
})
|
|
189
|
+
}) : /*#__PURE__*/React.createElement(InAppBrowser, {
|
|
190
|
+
url: oAuthUrl,
|
|
191
|
+
onClose: this.handleClose
|
|
192
|
+
}));
|
|
188
193
|
}
|
|
189
194
|
}]);
|
|
190
195
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/extends";
|
|
2
2
|
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
|
|
3
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
3
4
|
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
4
5
|
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
5
6
|
import _createClass from "@babel/runtime/helpers/createClass";
|
|
@@ -9,6 +10,9 @@ import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstruct
|
|
|
9
10
|
import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
|
|
10
11
|
var _excluded = ["onLaunch", "onSuccess", "onLoginSuccess", "onError", "initialTrigger"],
|
|
11
12
|
_excluded2 = ["vaultUnlockFormProps"];
|
|
13
|
+
|
|
14
|
+
var _DumbTriggerManager$p;
|
|
15
|
+
|
|
12
16
|
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
13
17
|
|
|
14
18
|
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
|
|
@@ -24,7 +28,7 @@ import { Account } from 'cozy-doctypes';
|
|
|
24
28
|
import { translate } from 'cozy-ui/transpiled/react/I18n';
|
|
25
29
|
import Spinner from 'cozy-ui/transpiled/react/Spinner';
|
|
26
30
|
import { ModalBackButton } from 'cozy-ui/transpiled/react/Modal';
|
|
27
|
-
import { CipherType } from 'cozy-keys-lib';
|
|
31
|
+
import { CipherType, withVaultUnlockContext, VaultUnlockPlaceholder, VaultUnlockProvider, useVaultClient, CozyUtils } from 'cozy-keys-lib';
|
|
28
32
|
import AccountForm from './AccountForm';
|
|
29
33
|
import OAuthForm from './OAuthForm';
|
|
30
34
|
import { fetchAccount } from '../connections/accounts';
|
|
@@ -34,7 +38,6 @@ import manifest from '../helpers/manifest';
|
|
|
34
38
|
import logger from '../logger';
|
|
35
39
|
import { findKonnectorPolicy } from '../konnector-policies';
|
|
36
40
|
import withConnectionFlow from '../models/withConnectionFlow';
|
|
37
|
-
import { withVaultUnlockContext, VaultUnlockPlaceholder, VaultUnlockProvider } from 'cozy-keys-lib';
|
|
38
41
|
import HarvestVaultProvider from './HarvestVaultProvider';
|
|
39
42
|
var IDLE = 'IDLE';
|
|
40
43
|
var RUNNING = 'RUNNING';
|
|
@@ -301,13 +304,13 @@ export var DumbTriggerManager = /*#__PURE__*/function (_Component) {
|
|
|
301
304
|
key: "componentDidMount",
|
|
302
305
|
value: function () {
|
|
303
306
|
var _componentDidMount = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
|
|
304
|
-
var _this$props3, konnector, showUnlockForm, onVaultDismiss, vaultClosable, vaultClient, konnectorPolicy, isVaultLocked;
|
|
307
|
+
var _this$props3, konnector, showUnlockForm, onVaultDismiss, vaultClosable, vaultClient, client, konnectorPolicy, isVaultLocked;
|
|
305
308
|
|
|
306
309
|
return _regeneratorRuntime.wrap(function _callee3$(_context3) {
|
|
307
310
|
while (1) {
|
|
308
311
|
switch (_context3.prev = _context3.next) {
|
|
309
312
|
case 0:
|
|
310
|
-
_this$props3 = this.props, konnector = _this$props3.konnector, showUnlockForm = _this$props3.showUnlockForm, onVaultDismiss = _this$props3.onVaultDismiss, vaultClosable = _this$props3.vaultClosable, vaultClient = _this$props3.vaultClient;
|
|
313
|
+
_this$props3 = this.props, konnector = _this$props3.konnector, showUnlockForm = _this$props3.showUnlockForm, onVaultDismiss = _this$props3.onVaultDismiss, vaultClosable = _this$props3.vaultClosable, vaultClient = _this$props3.vaultClient, client = _this$props3.client;
|
|
311
314
|
konnectorPolicy = findKonnectorPolicy(konnector);
|
|
312
315
|
|
|
313
316
|
if (!konnectorPolicy.saveInVault) {
|
|
@@ -333,7 +336,10 @@ export var DumbTriggerManager = /*#__PURE__*/function (_Component) {
|
|
|
333
336
|
showUnlockForm({
|
|
334
337
|
onDismiss: onVaultDismiss,
|
|
335
338
|
closable: vaultClosable,
|
|
336
|
-
onUnlock: this.handleVaultUnlock
|
|
339
|
+
onUnlock: this.handleVaultUnlock,
|
|
340
|
+
addCheckShouldUnlock: function addCheckShouldUnlock() {
|
|
341
|
+
return CozyUtils.checkHasInstalledExtension(client);
|
|
342
|
+
}
|
|
337
343
|
});
|
|
338
344
|
} else {
|
|
339
345
|
this.handleVaultUnlock();
|
|
@@ -561,7 +567,7 @@ export var DumbTriggerManager = /*#__PURE__*/function (_Component) {
|
|
|
561
567
|
|
|
562
568
|
return DumbTriggerManager;
|
|
563
569
|
}(Component);
|
|
564
|
-
DumbTriggerManager.propTypes = {
|
|
570
|
+
DumbTriggerManager.propTypes = (_DumbTriggerManager$p = {
|
|
565
571
|
/**
|
|
566
572
|
* Account document. Used to get initial form values.
|
|
567
573
|
* If no account is passed, AccountForm will use empty initial values.
|
|
@@ -594,11 +600,29 @@ DumbTriggerManager.propTypes = {
|
|
|
594
600
|
* Whether the vault will be closable or not.
|
|
595
601
|
* @type {Boolean}
|
|
596
602
|
*/
|
|
597
|
-
vaultClosable: PropTypes.bool
|
|
598
|
-
|
|
603
|
+
vaultClosable: PropTypes.bool,
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
*
|
|
607
|
+
*/
|
|
608
|
+
vaultClient: PropTypes.object,
|
|
609
|
+
client: PropTypes.object,
|
|
610
|
+
onError: PropTypes.func,
|
|
611
|
+
showUnlockForm: PropTypes.func
|
|
612
|
+
}, _defineProperty(_DumbTriggerManager$p, "onVaultDismiss", PropTypes.func), _defineProperty(_DumbTriggerManager$p, "error", PropTypes.any), _defineProperty(_DumbTriggerManager$p, "showError", PropTypes.bool), _defineProperty(_DumbTriggerManager$p, "fieldOptions", PropTypes.object), _defineProperty(_DumbTriggerManager$p, "flow", PropTypes.object), _defineProperty(_DumbTriggerManager$p, "flowState", PropTypes.object), _DumbTriggerManager$p);
|
|
599
613
|
var TriggerManager = compose(translate(), withClient, withVaultUnlockContext, withConnectionFlow())(DumbTriggerManager); // TriggerManager is exported wrapped in FlowProvider to avoid breaking changes.
|
|
600
614
|
|
|
601
615
|
var LegacyTriggerManager = function LegacyTriggerManager(props) {
|
|
616
|
+
// Since the 4.1.0 of cozy-keys-lib, we
|
|
617
|
+
// render children even if vaultClient is
|
|
618
|
+
// not defined yet. In that case we we were
|
|
619
|
+
// displaying TriggerManager without vaultClient.
|
|
620
|
+
// It was raising an error.
|
|
621
|
+
// The current fix, is to not display the
|
|
622
|
+
// TriggerManager when vaultClient is null.
|
|
623
|
+
var vaultClient = useVaultClient();
|
|
624
|
+
if (!vaultClient) return null;
|
|
625
|
+
|
|
602
626
|
var onLaunch = props.onLaunch,
|
|
603
627
|
onSuccess = props.onSuccess,
|
|
604
628
|
onLoginSuccess = props.onLoginSuccess,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cozy-harvest-lib",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.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",
|
|
@@ -53,10 +53,11 @@
|
|
|
53
53
|
"babel-plugin-inline-react-svg": "1.1.2",
|
|
54
54
|
"babel-preset-cozy-app": "^2.0.2",
|
|
55
55
|
"cozy-client": "27.17.0",
|
|
56
|
-
"cozy-device-helper": "^
|
|
56
|
+
"cozy-device-helper": "^2.0.0",
|
|
57
57
|
"cozy-flags": "^2.8.7",
|
|
58
|
-
"cozy-
|
|
59
|
-
"cozy-
|
|
58
|
+
"cozy-intent": "^1.17.1",
|
|
59
|
+
"cozy-keys-lib": "^4.1.9",
|
|
60
|
+
"cozy-realtime": "^4.0.8",
|
|
60
61
|
"cozy-ui": "60.6.0",
|
|
61
62
|
"enzyme": "3.11.0",
|
|
62
63
|
"enzyme-adapter-react-16": "1.15.6",
|
|
@@ -78,12 +79,13 @@
|
|
|
78
79
|
"cozy-client": ">=27.17.0",
|
|
79
80
|
"cozy-device-helper": ">=1.10.2",
|
|
80
81
|
"cozy-flags": ">=2.3.5",
|
|
81
|
-
"cozy-
|
|
82
|
+
"cozy-intent": ">=1.14.1",
|
|
83
|
+
"cozy-keys-lib": ">=4.1.9",
|
|
82
84
|
"cozy-realtime": ">=3.12.2",
|
|
83
85
|
"cozy-ui": ">=60.6.0",
|
|
84
86
|
"leaflet": "^1.7.1",
|
|
85
87
|
"react-router-dom": "^5.0.1"
|
|
86
88
|
},
|
|
87
89
|
"sideEffects": false,
|
|
88
|
-
"gitHead": "
|
|
90
|
+
"gitHead": "2e308c267a13adc3cd826639e3058fe35770d830"
|
|
89
91
|
}
|
|
@@ -132,7 +132,9 @@ export class AccountForm extends PureComponent {
|
|
|
132
132
|
handleSubmit(values, form) {
|
|
133
133
|
const { account, konnector } = this.props
|
|
134
134
|
|
|
135
|
-
const identifier = manifest.getIdentifier(
|
|
135
|
+
const identifier = manifest.getIdentifier(
|
|
136
|
+
manifest.sanitizeFields(konnector.fields)
|
|
137
|
+
)
|
|
136
138
|
if (
|
|
137
139
|
account &&
|
|
138
140
|
account.auth[identifier] &&
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { useEffect } from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import { useWebviewIntent } from 'cozy-intent'
|
|
4
|
+
import logger from '../logger'
|
|
5
|
+
|
|
6
|
+
const InAppBrowser = ({ url, onClose }) => {
|
|
7
|
+
const webviewIntent = useWebviewIntent()
|
|
8
|
+
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
async function insideEffect() {
|
|
11
|
+
if (webviewIntent) {
|
|
12
|
+
const result = await webviewIntent.call('showInAppBrowser', { url })
|
|
13
|
+
if (result?.type === 'cancel' && onClose) {
|
|
14
|
+
onClose()
|
|
15
|
+
} else if (result?.type !== 'dismiss') {
|
|
16
|
+
logger.error('Unexpected InAppBrowser result', result)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
insideEffect()
|
|
21
|
+
return function cleanup() {
|
|
22
|
+
webviewIntent.call('closeInAppBrowser')
|
|
23
|
+
}
|
|
24
|
+
}, [webviewIntent, url, onClose])
|
|
25
|
+
return null
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
InAppBrowser.propTypes = {
|
|
29
|
+
url: PropTypes.string.isRequired,
|
|
30
|
+
onClose: PropTypes.func
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default InAppBrowser
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { render, waitFor } from '@testing-library/react'
|
|
3
|
+
import InAppBrowser from './InAppBrowser'
|
|
4
|
+
import { WebviewIntentProvider } from 'cozy-intent'
|
|
5
|
+
|
|
6
|
+
describe('InAppBrowser', () => {
|
|
7
|
+
it('should call showInAppBrowser', async () => {
|
|
8
|
+
const url = 'https://test.url'
|
|
9
|
+
const intentCall = jest.fn()
|
|
10
|
+
const webviewService = {
|
|
11
|
+
call: intentCall
|
|
12
|
+
}
|
|
13
|
+
intentCall.mockResolvedValue({type: 'dismiss'})
|
|
14
|
+
render(
|
|
15
|
+
<WebviewIntentProvider webviewService={webviewService}>
|
|
16
|
+
<InAppBrowser url={url} />
|
|
17
|
+
</WebviewIntentProvider>
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
expect(webviewService.call).toHaveBeenNthCalledWith(1, 'showInAppBrowser', {
|
|
21
|
+
url
|
|
22
|
+
})
|
|
23
|
+
})
|
|
24
|
+
it('should call onClose when user closes the inAppBrowser in app', async () => {
|
|
25
|
+
const url = 'https://test.url'
|
|
26
|
+
const intentCall = jest.fn()
|
|
27
|
+
const webviewService = {
|
|
28
|
+
call: intentCall
|
|
29
|
+
}
|
|
30
|
+
const onClose = jest.fn()
|
|
31
|
+
|
|
32
|
+
intentCall.mockResolvedValue({type: 'cancel'})
|
|
33
|
+
render(
|
|
34
|
+
<WebviewIntentProvider webviewService={webviewService}>
|
|
35
|
+
<InAppBrowser url={url} onClose={onClose} />
|
|
36
|
+
</WebviewIntentProvider>
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
await waitFor(() => expect(onClose).toHaveBeenCalledTimes(1))
|
|
40
|
+
expect(onClose).toHaveBeenCalledWith()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
})
|
|
44
|
+
it('should call closeInAppBrowser when the component is unmounted', async () => {
|
|
45
|
+
const url = 'https://test.url'
|
|
46
|
+
const intentCall = jest.fn()
|
|
47
|
+
const webviewService = {
|
|
48
|
+
call: intentCall
|
|
49
|
+
}
|
|
50
|
+
intentCall.mockResolvedValue({type: 'dismiss'})
|
|
51
|
+
const { unmount } = render(
|
|
52
|
+
<WebviewIntentProvider webviewService={webviewService}>
|
|
53
|
+
<InAppBrowser url={url} />
|
|
54
|
+
</WebviewIntentProvider>
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
unmount()
|
|
58
|
+
expect(webviewService.call).toHaveBeenNthCalledWith(2, 'closeInAppBrowser')
|
|
59
|
+
})
|
|
60
|
+
})
|
|
@@ -4,7 +4,7 @@ import cx from 'classnames'
|
|
|
4
4
|
|
|
5
5
|
import { useClient } from 'cozy-client'
|
|
6
6
|
import { Account } from 'cozy-doctypes'
|
|
7
|
-
import { useVaultClient } from 'cozy-keys-lib'
|
|
7
|
+
import { useVaultClient, CozyUtils } from 'cozy-keys-lib'
|
|
8
8
|
|
|
9
9
|
import Button from 'cozy-ui/transpiled/react/Button'
|
|
10
10
|
import Spinner from 'cozy-ui/transpiled/react/Spinner'
|
|
@@ -96,7 +96,8 @@ const ConfigurationTab = ({
|
|
|
96
96
|
if (konnectorPolicy.saveInVault) {
|
|
97
97
|
showUnlockForm({
|
|
98
98
|
closable: true,
|
|
99
|
-
onUnlock: handleUnlockForDeletion
|
|
99
|
+
onUnlock: handleUnlockForDeletion,
|
|
100
|
+
addCheckShouldUnlock: () => CozyUtils.checkHasInstalledExtension(client)
|
|
100
101
|
})
|
|
101
102
|
} else {
|
|
102
103
|
await handleDeleteAccount()
|
|
@@ -58,7 +58,9 @@ describe('NewAccountModal', () => {
|
|
|
58
58
|
</AppLike>
|
|
59
59
|
)
|
|
60
60
|
onLoginSuccessFn(konnectorTrigger)
|
|
61
|
-
expect(replaceHistory).toHaveBeenCalledWith(
|
|
61
|
+
expect(replaceHistory).toHaveBeenCalledWith(
|
|
62
|
+
'/accounts/accountNumber/success'
|
|
63
|
+
)
|
|
62
64
|
})
|
|
63
65
|
it('should redirect to route without success on login success for client triggers', () => {
|
|
64
66
|
render(
|
|
@@ -85,7 +87,9 @@ describe('NewAccountModal', () => {
|
|
|
85
87
|
</AppLike>
|
|
86
88
|
)
|
|
87
89
|
onSuccessFn(konnectorTrigger)
|
|
88
|
-
expect(replaceHistory).toHaveBeenCalledWith(
|
|
90
|
+
expect(replaceHistory).toHaveBeenCalledWith(
|
|
91
|
+
'/accounts/accountNumber/success'
|
|
92
|
+
)
|
|
89
93
|
})
|
|
90
94
|
it('should redirect to route without success on success for client triggers', () => {
|
|
91
95
|
render(
|
|
@@ -4,6 +4,7 @@ import PropTypes from 'prop-types'
|
|
|
4
4
|
import { withClient } from 'cozy-client'
|
|
5
5
|
import { translate } from 'cozy-ui/transpiled/react/I18n'
|
|
6
6
|
import CozyRealtime from 'cozy-realtime'
|
|
7
|
+
import { isFlagshipApp } from 'cozy-device-helper'
|
|
7
8
|
|
|
8
9
|
import {
|
|
9
10
|
prepareOAuth,
|
|
@@ -13,6 +14,7 @@ import {
|
|
|
13
14
|
} from '../helpers/oauth'
|
|
14
15
|
// TODO use PopUp from cozy-ui
|
|
15
16
|
import Popup from './Popup'
|
|
17
|
+
import InAppBrowser from './InAppBrowser'
|
|
16
18
|
|
|
17
19
|
const OAUTH_POPUP_HEIGHT = 800
|
|
18
20
|
const OAUTH_POPUP_WIDTH = 800
|
|
@@ -141,7 +143,8 @@ export class OAuthWindow extends PureComponent {
|
|
|
141
143
|
const { oAuthUrl, succeed } = this.state
|
|
142
144
|
return (
|
|
143
145
|
oAuthUrl &&
|
|
144
|
-
!succeed &&
|
|
146
|
+
!succeed &&
|
|
147
|
+
(!isFlagshipApp() ? (
|
|
145
148
|
<Popup
|
|
146
149
|
url={oAuthUrl}
|
|
147
150
|
height={OAUTH_POPUP_HEIGHT}
|
|
@@ -150,7 +153,9 @@ export class OAuthWindow extends PureComponent {
|
|
|
150
153
|
onUrlChange={this.handleUrlChange}
|
|
151
154
|
title={t(`oauth.window.title`)}
|
|
152
155
|
/>
|
|
153
|
-
)
|
|
156
|
+
) : (
|
|
157
|
+
<InAppBrowser url={oAuthUrl} onClose={this.handleClose} />
|
|
158
|
+
))
|
|
154
159
|
)
|
|
155
160
|
}
|
|
156
161
|
}
|
|
@@ -10,7 +10,14 @@ import { translate } from 'cozy-ui/transpiled/react/I18n'
|
|
|
10
10
|
import Spinner from 'cozy-ui/transpiled/react/Spinner'
|
|
11
11
|
import { ModalBackButton } from 'cozy-ui/transpiled/react/Modal'
|
|
12
12
|
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
CipherType,
|
|
15
|
+
withVaultUnlockContext,
|
|
16
|
+
VaultUnlockPlaceholder,
|
|
17
|
+
VaultUnlockProvider,
|
|
18
|
+
useVaultClient,
|
|
19
|
+
CozyUtils
|
|
20
|
+
} from 'cozy-keys-lib'
|
|
14
21
|
|
|
15
22
|
import AccountForm from './AccountForm'
|
|
16
23
|
import OAuthForm from './OAuthForm'
|
|
@@ -21,11 +28,6 @@ import manifest from '../helpers/manifest'
|
|
|
21
28
|
import logger from '../logger'
|
|
22
29
|
import { findKonnectorPolicy } from '../konnector-policies'
|
|
23
30
|
import withConnectionFlow from '../models/withConnectionFlow'
|
|
24
|
-
import {
|
|
25
|
-
withVaultUnlockContext,
|
|
26
|
-
VaultUnlockPlaceholder,
|
|
27
|
-
VaultUnlockProvider
|
|
28
|
-
} from 'cozy-keys-lib'
|
|
29
31
|
import HarvestVaultProvider from './HarvestVaultProvider'
|
|
30
32
|
|
|
31
33
|
const IDLE = 'IDLE'
|
|
@@ -210,7 +212,8 @@ export class DumbTriggerManager extends Component {
|
|
|
210
212
|
showUnlockForm,
|
|
211
213
|
onVaultDismiss,
|
|
212
214
|
vaultClosable,
|
|
213
|
-
vaultClient
|
|
215
|
+
vaultClient,
|
|
216
|
+
client
|
|
214
217
|
} = this.props
|
|
215
218
|
const konnectorPolicy = findKonnectorPolicy(konnector)
|
|
216
219
|
if (konnectorPolicy.saveInVault) {
|
|
@@ -224,7 +227,9 @@ export class DumbTriggerManager extends Component {
|
|
|
224
227
|
showUnlockForm({
|
|
225
228
|
onDismiss: onVaultDismiss,
|
|
226
229
|
closable: vaultClosable,
|
|
227
|
-
onUnlock: this.handleVaultUnlock
|
|
230
|
+
onUnlock: this.handleVaultUnlock,
|
|
231
|
+
addCheckShouldUnlock: () =>
|
|
232
|
+
CozyUtils.checkHasInstalledExtension(client)
|
|
228
233
|
})
|
|
229
234
|
} else {
|
|
230
235
|
this.handleVaultUnlock()
|
|
@@ -410,7 +415,29 @@ DumbTriggerManager.propTypes = {
|
|
|
410
415
|
* Whether the vault will be closable or not.
|
|
411
416
|
* @type {Boolean}
|
|
412
417
|
*/
|
|
413
|
-
vaultClosable: PropTypes.bool
|
|
418
|
+
vaultClosable: PropTypes.bool,
|
|
419
|
+
/**
|
|
420
|
+
*
|
|
421
|
+
*/
|
|
422
|
+
vaultClient: PropTypes.object,
|
|
423
|
+
client: PropTypes.object,
|
|
424
|
+
onError: PropTypes.func,
|
|
425
|
+
showUnlockForm: PropTypes.func,
|
|
426
|
+
onVaultDismiss: PropTypes.func,
|
|
427
|
+
error: PropTypes.any,
|
|
428
|
+
/**
|
|
429
|
+
* Indicates if the AccountForm has to show errors. Sometimes errors may be
|
|
430
|
+
* displayed elsewhere. However, a KonnectorJobError corresponding to a login
|
|
431
|
+
* error is always displayed.
|
|
432
|
+
* @type {Boolean}
|
|
433
|
+
*/
|
|
434
|
+
showError: PropTypes.bool,
|
|
435
|
+
/**
|
|
436
|
+
* Used to have options on fields (forceEncryptedPlaceholder or focus)
|
|
437
|
+
*/
|
|
438
|
+
fieldOptions: PropTypes.object,
|
|
439
|
+
flow: PropTypes.object,
|
|
440
|
+
flowState: PropTypes.object
|
|
414
441
|
}
|
|
415
442
|
|
|
416
443
|
const TriggerManager = compose(
|
|
@@ -422,6 +449,15 @@ const TriggerManager = compose(
|
|
|
422
449
|
|
|
423
450
|
// TriggerManager is exported wrapped in FlowProvider to avoid breaking changes.
|
|
424
451
|
const LegacyTriggerManager = props => {
|
|
452
|
+
// Since the 4.1.0 of cozy-keys-lib, we
|
|
453
|
+
// render children even if vaultClient is
|
|
454
|
+
// not defined yet. In that case we we were
|
|
455
|
+
// displaying TriggerManager without vaultClient.
|
|
456
|
+
// It was raising an error.
|
|
457
|
+
// The current fix, is to not display the
|
|
458
|
+
// TriggerManager when vaultClient is null.
|
|
459
|
+
const vaultClient = useVaultClient()
|
|
460
|
+
if (!vaultClient) return null
|
|
425
461
|
const {
|
|
426
462
|
onLaunch,
|
|
427
463
|
onSuccess,
|
|
@@ -8,7 +8,9 @@ import {
|
|
|
8
8
|
launchTrigger
|
|
9
9
|
} from '../connections/triggers'
|
|
10
10
|
import CozyRealtime from 'cozy-realtime'
|
|
11
|
-
import KonnectorJobWatcher, {
|
|
11
|
+
import KonnectorJobWatcher, {
|
|
12
|
+
watchKonnectorJob
|
|
13
|
+
} from './konnector/KonnectorJobWatcher'
|
|
12
14
|
import { konnectorPolicy as biKonnectorPolicy } from '../services/budget-insight'
|
|
13
15
|
import fixtures from '../../test/fixtures'
|
|
14
16
|
import sentryHub from '../sentry'
|
|
@@ -118,14 +120,13 @@ describe('ConnectionFlow', () => {
|
|
|
118
120
|
return flow.getState().running === true
|
|
119
121
|
}
|
|
120
122
|
beforeAll(() => {
|
|
121
|
-
watchKonnectorJob.mockReturnValue({on: () => ({})})
|
|
123
|
+
watchKonnectorJob.mockReturnValue({ on: () => ({}) })
|
|
122
124
|
})
|
|
123
125
|
|
|
124
126
|
afterEach(() => {
|
|
125
127
|
jest.clearAllMocks()
|
|
126
128
|
})
|
|
127
129
|
|
|
128
|
-
|
|
129
130
|
it('should render as submitting when there is no account', async () => {
|
|
130
131
|
const { flow } = setup()
|
|
131
132
|
const submitPromise = setupSubmit(flow)
|
|
@@ -327,7 +328,7 @@ describe('ConnectionFlow', () => {
|
|
|
327
328
|
describe('ensureTriggerAndLaunch', () => {
|
|
328
329
|
beforeAll(() => {
|
|
329
330
|
jest.spyOn(cronHelpers, 'fromFrequency').mockReturnValue('0 0 0 * * 0')
|
|
330
|
-
watchKonnectorJob.mockReturnValue({on: () => ({})})
|
|
331
|
+
watchKonnectorJob.mockReturnValue({ on: () => ({}) })
|
|
331
332
|
})
|
|
332
333
|
|
|
333
334
|
afterEach(() => {
|
|
@@ -494,7 +495,7 @@ describe('ConnectionFlow', () => {
|
|
|
494
495
|
|
|
495
496
|
describe('constructor', () => {
|
|
496
497
|
beforeAll(() => {
|
|
497
|
-
watchKonnectorJob.mockReturnValue({on: () => ({})})
|
|
498
|
+
watchKonnectorJob.mockReturnValue({ on: () => ({}) })
|
|
498
499
|
})
|
|
499
500
|
|
|
500
501
|
afterEach(() => {
|
|
@@ -502,8 +503,12 @@ describe('ConnectionFlow', () => {
|
|
|
502
503
|
})
|
|
503
504
|
|
|
504
505
|
it('should watch a running trigger', () => {
|
|
505
|
-
setup({trigger: fixtures.runningTrigger})
|
|
506
|
-
expect(watchKonnectorJob).toHaveBeenCalledWith(
|
|
506
|
+
setup({ trigger: fixtures.runningTrigger })
|
|
507
|
+
expect(watchKonnectorJob).toHaveBeenCalledWith(
|
|
508
|
+
expect.any(Object),
|
|
509
|
+
{ _id: 'runningjobid' },
|
|
510
|
+
{ autoSuccessTimer: false }
|
|
511
|
+
)
|
|
507
512
|
})
|
|
508
513
|
})
|
|
509
514
|
})
|