cozy-harvest-lib 12.0.0 → 12.2.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.
Files changed (28) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/components/AccountForm/index.js +3 -2
  3. package/dist/components/AccountModalWithoutTabs/AccountModalContentWrapper.js +41 -0
  4. package/dist/components/AccountModalWithoutTabs/AccountModalHeader.js +36 -0
  5. package/dist/components/AccountModalWithoutTabs/AccountModalWithoutTabs.js +68 -0
  6. package/dist/components/AccountModalWithoutTabs/Error.js +38 -0
  7. package/dist/components/AccountModalWithoutTabs/OpenOAuthWindowButton.js +74 -0
  8. package/dist/components/AccountModalWithoutTabs/TriggerError.js +41 -0
  9. package/dist/components/AccountModalWithoutTabs/TriggerErrorAction.js +33 -0
  10. package/dist/components/AccountModalWithoutTabs/helpers.js +6 -0
  11. package/dist/components/Routes/RoutesV6.js +30 -0
  12. package/dist/components/cards/LaunchTriggerAlert.js +39 -3
  13. package/dist/connections/accounts.js +19 -0
  14. package/dist/helpers/accounts.js +71 -0
  15. package/package.json +2 -2
  16. package/src/components/AccountForm/index.jsx +8 -9
  17. package/src/components/AccountModalWithoutTabs/AccountModalContentWrapper.jsx +37 -0
  18. package/src/components/AccountModalWithoutTabs/AccountModalHeader.jsx +45 -0
  19. package/src/components/AccountModalWithoutTabs/AccountModalWithoutTabs.jsx +80 -0
  20. package/src/components/AccountModalWithoutTabs/Error.jsx +38 -0
  21. package/src/components/AccountModalWithoutTabs/OpenOAuthWindowButton.jsx +58 -0
  22. package/src/components/AccountModalWithoutTabs/TriggerError.jsx +46 -0
  23. package/src/components/AccountModalWithoutTabs/TriggerErrorAction.jsx +33 -0
  24. package/src/components/AccountModalWithoutTabs/helpers.js +10 -0
  25. package/src/components/Routes/RoutesV6.jsx +67 -17
  26. package/src/components/cards/LaunchTriggerAlert.jsx +43 -8
  27. package/src/connections/accounts.js +18 -0
  28. package/src/helpers/accounts.js +35 -0
package/CHANGELOG.md CHANGED
@@ -3,6 +3,38 @@
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
+ # [12.2.0](https://github.com/cozy/cozy-libs/compare/cozy-harvest-lib@12.1.0...cozy-harvest-lib@12.2.0) (2023-01-11)
7
+
8
+
9
+ ### Features
10
+
11
+ * **harvest:** Add AccountModalContentWrapper component ([748939e](https://github.com/cozy/cozy-libs/commit/748939e8cb20ef5b79c6a8e0b68dbd8afacec417))
12
+ * **harvest:** Add AccountModalHeader component ([7d17627](https://github.com/cozy/cozy-libs/commit/7d1762776000f78815ea00ff96b750e52e10649a))
13
+ * **harvest:** Add AccountModalWithoutTabs component ([afcf7f2](https://github.com/cozy/cozy-libs/commit/afcf7f28e94ad0f0685a515ecfdda4724b12bbaa))
14
+ * **harvest:** Add Error component ([4dd2c27](https://github.com/cozy/cozy-libs/commit/4dd2c273884619d158ee2d2d2d1376c073b4a336))
15
+ * **harvest:** Add Routes in RoutesV6 component ([59e37c3](https://github.com/cozy/cozy-libs/commit/59e37c3bc53b3b07e59e2517f0163d40981deca0))
16
+ * **harvest:** Add TriggerError component ([3a3866a](https://github.com/cozy/cozy-libs/commit/3a3866abfd88dcd1424187f408d10c308186100d))
17
+
18
+
19
+
20
+
21
+
22
+ # [12.1.0](https://github.com/cozy/cozy-libs/compare/cozy-harvest-lib@12.0.0...cozy-harvest-lib@12.1.0) (2023-01-11)
23
+
24
+
25
+ ### Bug Fixes
26
+
27
+ * **harvest:** Font size of the help link in the account login modal ([0da0d51](https://github.com/cozy/cozy-libs/commit/0da0d51e865c3aea4358463843d736dcdb9a4f7a))
28
+
29
+
30
+ ### Features
31
+
32
+ * Add `LaunchTriggerAlert` menu with the first action ([ad410d9](https://github.com/cozy/cozy-libs/commit/ad410d9cf91d21e96f84e3f5430cacd1f2b4e669))
33
+
34
+
35
+
36
+
37
+
6
38
  # [12.0.0](https://github.com/cozy/cozy-libs/compare/cozy-harvest-lib@11.4.0...cozy-harvest-lib@12.0.0) (2023-01-11)
7
39
 
8
40
 
@@ -376,11 +376,12 @@ export var AccountForm = /*#__PURE__*/function (_PureComponent) {
376
376
  initialValues: values,
377
377
  inputRefByName: _this3.inputRefByName,
378
378
  t: t
379
- }), flag('harvest.inappconnectors.enabled') && /*#__PURE__*/React.createElement(Typography, null, /*#__PURE__*/React.createElement(Link, {
379
+ }), flag('harvest.inappconnectors.enabled') && /*#__PURE__*/React.createElement(Link, {
380
380
  className: "u-mt-1",
381
+ variant: "body1",
381
382
  component: "button",
382
383
  onClick: _this3.showCannotConnectModal
383
- }, t('accountForm.cannotConnectLink'))), /*#__PURE__*/React.createElement(Button, {
384
+ }, t('accountForm.cannotConnectLink')), /*#__PURE__*/React.createElement(Button, {
384
385
  busy: submitting && (!flag('harvest.inappconnectors.enabled') || !_this3.state.showConnectionBackdrop),
385
386
  className: "u-mt-2 u-mb-1-half",
386
387
  disabled: submitting || !_this3.isSubmittable({
@@ -0,0 +1,41 @@
1
+ import React from 'react';
2
+ import { useOutletContext } from 'react-router-dom';
3
+ import DialogContent from '@material-ui/core/DialogContent';
4
+ import useBreakpoints from 'cozy-ui/transpiled/react/hooks/useBreakpoints';
5
+ import FlowProvider from '../FlowProvider';
6
+ import TriggerError from './TriggerError';
7
+
8
+ var AccountModalContentWrapper = function AccountModalContentWrapper(_ref) {
9
+ var children = _ref.children;
10
+
11
+ var _useBreakpoints = useBreakpoints(),
12
+ isMobile = _useBreakpoints.isMobile;
13
+
14
+ var _useOutletContext = useOutletContext(),
15
+ trigger = _useOutletContext.trigger,
16
+ account = _useOutletContext.account,
17
+ konnector = _useOutletContext.konnector;
18
+
19
+ return /*#__PURE__*/React.createElement(DialogContent, {
20
+ className: isMobile ? 'u-p-0' : 'u-pt-0'
21
+ }, /*#__PURE__*/React.createElement(FlowProvider, {
22
+ initialTrigger: trigger,
23
+ konnector: konnector
24
+ }, function (_ref2) {
25
+ var flow = _ref2.flow;
26
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(TriggerError, {
27
+ flow: flow,
28
+ konnector: konnector,
29
+ account: account,
30
+ trigger: trigger
31
+ }), React.Children.map(children, function (child) {
32
+ return /*#__PURE__*/React.isValidElement(child) ? /*#__PURE__*/React.cloneElement(child, {
33
+ flow: flow,
34
+ trigger: trigger,
35
+ account: account
36
+ }) : null;
37
+ }));
38
+ }));
39
+ };
40
+
41
+ export default AccountModalContentWrapper;
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import AccountSelectBox from '../AccountSelectBox/AccountSelectBox';
4
+ import KonnectorModalHeader from '../KonnectorModalHeader';
5
+ import { withMountPointProps } from '../MountPointContext';
6
+ export var AccountModalHeader = function AccountModalHeader(_ref) {
7
+ var konnector = _ref.konnector,
8
+ account = _ref.account,
9
+ accountsAndTriggers = _ref.accountsAndTriggers,
10
+ showAccountSelection = _ref.showAccountSelection,
11
+ pushHistory = _ref.pushHistory;
12
+ return /*#__PURE__*/React.createElement(KonnectorModalHeader, {
13
+ konnector: konnector
14
+ }, showAccountSelection && /*#__PURE__*/React.createElement(AccountSelectBox, {
15
+ loading: !account,
16
+ selectedAccount: account,
17
+ accountsAndTriggers: accountsAndTriggers,
18
+ onChange: function onChange(option) {
19
+ pushHistory("/accounts/".concat(option.account._id));
20
+ },
21
+ onCreate: function onCreate() {
22
+ pushHistory('/new');
23
+ }
24
+ }));
25
+ };
26
+ AccountModalHeader.defaultProps = {
27
+ showAccountSelection: true
28
+ };
29
+ AccountModalHeader.propTypes = {
30
+ konnector: PropTypes.object.isRequired,
31
+ account: PropTypes.object,
32
+ accountsAndTriggers: PropTypes.array.isRequired,
33
+ showAccountSelection: PropTypes.bool,
34
+ pushHistory: PropTypes.func.isRequired
35
+ };
36
+ export default withMountPointProps(AccountModalHeader);
@@ -0,0 +1,68 @@
1
+ import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
2
+ var _excluded = ["data"];
3
+ import React from 'react';
4
+ import PropTypes from 'prop-types';
5
+ import { Outlet } from 'react-router-dom';
6
+ import DialogContent from '@material-ui/core/DialogContent';
7
+ import { useQuery, isQueryLoading } from 'cozy-client';
8
+ import Spinner from 'cozy-ui/transpiled/react/Spinner';
9
+ import { buildAccountQueryById } from '../../connections/accounts';
10
+ import { withMountPointProps } from '../MountPointContext';
11
+ import { getMatchingTrigger } from './helpers';
12
+ import AccountModalHeader from './AccountModalHeader';
13
+ import Error from './Error';
14
+
15
+ var AccountModalWithoutTabs = function AccountModalWithoutTabs(_ref) {
16
+ var accountsAndTriggers = _ref.accountsAndTriggers,
17
+ konnector = _ref.konnector,
18
+ accountId = _ref.accountId;
19
+ var matchingTrigger = getMatchingTrigger(accountsAndTriggers, accountId);
20
+ var matchingAccountId = matchingTrigger ? accountId : undefined;
21
+
22
+ var _buildAccountQueryByI = buildAccountQueryById(matchingAccountId),
23
+ definition = _buildAccountQueryByI.definition,
24
+ options = _buildAccountQueryByI.options;
25
+
26
+ var _useQuery = useQuery(definition, options),
27
+ accounts = _useQuery.data,
28
+ accountQueryResult = _objectWithoutProperties(_useQuery, _excluded);
29
+
30
+ var isLoading = isQueryLoading(accountQueryResult) || accountQueryResult.hasMore;
31
+ var isError = !isLoading && (!matchingTrigger || !accounts || (accounts === null || accounts === void 0 ? void 0 : accounts.length) === 0);
32
+ var account = accounts === null || accounts === void 0 ? void 0 : accounts[0];
33
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(AccountModalHeader, {
34
+ konnector: konnector,
35
+ account: account,
36
+ accountsAndTriggers: accountsAndTriggers
37
+ }), (isError || isLoading) && /*#__PURE__*/React.createElement(DialogContent, {
38
+ className: "u-pb-2"
39
+ }, isError && /*#__PURE__*/React.createElement(Error, {
40
+ accountId: accountId,
41
+ accountsAndTriggers: accountsAndTriggers,
42
+ trigger: matchingTrigger,
43
+ lastError: accountQueryResult.lastError
44
+ }), isLoading && /*#__PURE__*/React.createElement(Spinner, {
45
+ className: "u-flex u-flex-justify-center",
46
+ size: "xxlarge"
47
+ })), !isError && !isLoading && /*#__PURE__*/React.createElement(Outlet, {
48
+ context: {
49
+ trigger: matchingTrigger,
50
+ account: account,
51
+ konnector: konnector
52
+ }
53
+ }));
54
+ };
55
+
56
+ AccountModalWithoutTabs.propTypes = {
57
+ konnector: PropTypes.object.isRequired,
58
+
59
+ /**
60
+ * @type {{ account: 'io.cozy.accounts', trigger: 'io.cozy.triggers' }[]} - An array of objects containing an account and its associated trigger
61
+ */
62
+ accountsAndTriggers: PropTypes.arrayOf(PropTypes.shape({
63
+ account: PropTypes.object.isRequired,
64
+ trigger: PropTypes.object.isRequired
65
+ })).isRequired,
66
+ accountId: PropTypes.string.isRequired
67
+ };
68
+ export default withMountPointProps(AccountModalWithoutTabs);
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import { useClient } from 'cozy-client';
3
+ import Infos from 'cozy-ui/transpiled/react/Infos';
4
+ import Button from 'cozy-ui/transpiled/react/Buttons';
5
+ import { useI18n } from 'cozy-ui/transpiled/react/I18n';
6
+ import { loadSelectedAccountId } from '../../helpers/accounts';
7
+ import withLocales from '../hoc/withLocales';
8
+
9
+ var Error = function Error(_ref) {
10
+ var accountId = _ref.accountId,
11
+ accountsAndTriggers = _ref.accountsAndTriggers,
12
+ trigger = _ref.trigger,
13
+ lastError = _ref.lastError;
14
+
15
+ var _useI18n = useI18n(),
16
+ t = _useI18n.t;
17
+
18
+ var client = useClient();
19
+ var error = !trigger ? new Error('No matching trigger found') : lastError;
20
+
21
+ var handleClick = function handleClick() {
22
+ loadSelectedAccountId(client, accountId, accountsAndTriggers);
23
+ };
24
+
25
+ return /*#__PURE__*/React.createElement(Infos, {
26
+ actionButton: /*#__PURE__*/React.createElement(Button, {
27
+ label: t('modal.konnector.error.button'),
28
+ color: "error",
29
+ onClick: handleClick
30
+ }),
31
+ title: t('modal.konnector.error.title'),
32
+ text: t('modal.konnector.error.description', error),
33
+ icon: "warning",
34
+ isImportant: true
35
+ });
36
+ };
37
+
38
+ export default withLocales(Error);
@@ -0,0 +1,74 @@
1
+ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
+ import _regeneratorRuntime from "@babel/runtime/regenerator";
3
+ import React, { useCallback } from 'react';
4
+ import PropTypes from 'prop-types';
5
+ import flag from 'cozy-flags';
6
+ import { useClient } from 'cozy-client';
7
+ import { useI18n } from 'cozy-ui/transpiled/react/I18n';
8
+ import { Button } from 'cozy-ui/transpiled/react/Button';
9
+ import useOAuthExtraParams from '../hooks/useOAuthExtraParams';
10
+ import { OAUTH_SERVICE_OK, openOAuthWindow } from '../OAuthService';
11
+
12
+ var OpenOAuthWindowButton = function OpenOAuthWindowButton(_ref) {
13
+ var flow = _ref.flow,
14
+ account = _ref.account,
15
+ konnector = _ref.konnector;
16
+
17
+ var _useI18n = useI18n(),
18
+ t = _useI18n.t;
19
+
20
+ var client = useClient();
21
+
22
+ var _useOAuthExtraParams = useOAuthExtraParams({
23
+ account: account,
24
+ client: client,
25
+ konnector: konnector,
26
+ reconnect: true
27
+ }),
28
+ extraParams = _useOAuthExtraParams.extraParams;
29
+
30
+ var handleClick = useCallback( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
31
+ var response;
32
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
33
+ while (1) {
34
+ switch (_context.prev = _context.next) {
35
+ case 0:
36
+ _context.next = 2;
37
+ return openOAuthWindow({
38
+ client: client,
39
+ konnector: konnector,
40
+ account: account,
41
+ extraParams: extraParams,
42
+ reconnect: true
43
+ });
44
+
45
+ case 2:
46
+ response = _context.sent;
47
+
48
+ if (response.result === OAUTH_SERVICE_OK && flag('harvest.bi.fullwebhooks')) {
49
+ flow.expectTriggerLaunch();
50
+ }
51
+
52
+ case 4:
53
+ case "end":
54
+ return _context.stop();
55
+ }
56
+ }
57
+ }, _callee);
58
+ })), [account, client, extraParams, flow, konnector]);
59
+ return /*#__PURE__*/React.createElement(Button, {
60
+ className: "u-ml-0",
61
+ variant: "secondary",
62
+ label: t('error.reconnect-via-form'),
63
+ onClick: handleClick,
64
+ disabled: !extraParams,
65
+ busy: !extraParams
66
+ });
67
+ };
68
+
69
+ OpenOAuthWindowButton.propTypes = {
70
+ flow: PropTypes.object.isRequired,
71
+ account: PropTypes.object.isRequired,
72
+ konnector: PropTypes.object.isRequired
73
+ };
74
+ export default OpenOAuthWindowButton;
@@ -0,0 +1,41 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { useClient } from 'cozy-client';
4
+ import useMaintenanceStatus from '../hooks/useMaintenanceStatus';
5
+ import TriggerErrorInfo from '../infos/TriggerErrorInfo';
6
+ import TriggerErrorAction from './TriggerErrorAction';
7
+
8
+ var TriggerError = function TriggerError(_ref) {
9
+ var flow = _ref.flow,
10
+ konnector = _ref.konnector,
11
+ account = _ref.account,
12
+ trigger = _ref.trigger;
13
+ var client = useClient();
14
+ var flowState = flow.getState();
15
+ var error = flowState.error;
16
+
17
+ var _useMaintenanceStatus = useMaintenanceStatus(client, konnector),
18
+ isInMaintenance = _useMaintenanceStatus.data.isInMaintenance;
19
+
20
+ if (!error || isInMaintenance) return null;
21
+ return /*#__PURE__*/React.createElement(TriggerErrorInfo, {
22
+ error: error,
23
+ konnector: konnector,
24
+ action: /*#__PURE__*/React.createElement(TriggerErrorAction, {
25
+ error: error,
26
+ flow: flow,
27
+ konnector: konnector,
28
+ account: account,
29
+ trigger: trigger
30
+ }),
31
+ className: "u-mt-1"
32
+ });
33
+ };
34
+
35
+ export default TriggerError;
36
+ TriggerError.propTypes = {
37
+ flow: PropTypes.object.isRequired,
38
+ konnector: PropTypes.object.isRequired,
39
+ account: PropTypes.object,
40
+ trigger: PropTypes.object
41
+ };
@@ -0,0 +1,33 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { findKonnectorPolicy } from '../../konnector-policies';
4
+ import RedirectToAccountFormButton from '../RedirectToAccountFormButton';
5
+ import OpenOAuthWindowButton from './OpenOAuthWindowButton';
6
+
7
+ var TriggerErrorAction = function TriggerErrorAction(_ref) {
8
+ var flow = _ref.flow,
9
+ konnector = _ref.konnector,
10
+ account = _ref.account,
11
+ trigger = _ref.trigger,
12
+ error = _ref.error;
13
+ var konnectorPolicy = findKonnectorPolicy(konnector);
14
+ if (!error.isSolvableViaReconnect()) return null;
15
+ if (konnectorPolicy.isBIWebView) return /*#__PURE__*/React.createElement(OpenOAuthWindowButton, {
16
+ flow: flow,
17
+ account: account,
18
+ konnector: konnector
19
+ });
20
+ return /*#__PURE__*/React.createElement(RedirectToAccountFormButton, {
21
+ konnector: konnector,
22
+ trigger: trigger
23
+ });
24
+ };
25
+
26
+ TriggerErrorAction.propTypes = {
27
+ flow: PropTypes.object.isRequired,
28
+ konnector: PropTypes.object.isRequired,
29
+ account: PropTypes.object,
30
+ trigger: PropTypes.object,
31
+ error: PropTypes.object.isRequired
32
+ };
33
+ export default TriggerErrorAction;
@@ -0,0 +1,6 @@
1
+ import get from 'lodash/get';
2
+ export var getMatchingTrigger = function getMatchingTrigger(accountsAndTriggers, accountId) {
3
+ return get(accountsAndTriggers.find(function (accountAndTrigger) {
4
+ return accountAndTrigger.account._id === accountId;
5
+ }), 'trigger');
6
+ };
@@ -3,10 +3,14 @@ import { Routes, Route, Navigate, useParams } from 'react-router-dom';
3
3
  import flag from 'cozy-flags';
4
4
  import { ViewerModal } from '../../datacards/ViewerModal';
5
5
  import AccountModal from '../AccountModal';
6
+ import AccountModalWithoutTabs from '../AccountModalWithoutTabs/AccountModalWithoutTabs';
7
+ import AccountModalContentWrapper from '../AccountModalWithoutTabs/AccountModalContentWrapper';
6
8
  import NewAccountModal from '../NewAccountModal';
7
9
  import EditAccountModal from '../EditAccountModal';
8
10
  import KonnectorSuccess from '../KonnectorSuccess';
9
11
  import HarvestModalRoot from '../HarvestModalRoot';
12
+ import DataTab from '../KonnectorConfiguration/DataTab';
13
+ import ConfigurationTab from '../KonnectorConfiguration/ConfigurationTab';
10
14
 
11
15
  var HarvestParamsWrapper = function HarvestParamsWrapper(props) {
12
16
  var params = useParams();
@@ -31,7 +35,33 @@ var RoutesV6 = function RoutesV6(_ref) {
31
35
  onSuccess: onSuccess,
32
36
  onDismiss: onDismiss
33
37
  })
38
+ }), flag('harvest.inappconnectors.enabled') ? /*#__PURE__*/React.createElement(Route, {
39
+ path: "accounts/:accountId",
40
+ element: /*#__PURE__*/React.createElement(HarvestParamsWrapper, null, function (params) {
41
+ return /*#__PURE__*/React.createElement(AccountModalWithoutTabs, {
42
+ konnector: konnectorWithTriggers,
43
+ accountId: params.accountId,
44
+ accountsAndTriggers: accountsAndTriggers,
45
+ showNewAccountButton: !konnectorWithTriggers.clientSide,
46
+ showAccountSelection: !konnectorWithTriggers.clientSide,
47
+ onDismiss: onDismiss
48
+ });
49
+ })
50
+ }, /*#__PURE__*/React.createElement(Route, {
51
+ index: true,
52
+ element: /*#__PURE__*/React.createElement(AccountModalContentWrapper, null, /*#__PURE__*/React.createElement(DataTab, {
53
+ konnector: konnectorWithTriggers,
54
+ showNewAccountButton: !konnectorWithTriggers.clientSide,
55
+ onDismiss: onDismiss
56
+ }))
34
57
  }), /*#__PURE__*/React.createElement(Route, {
58
+ path: "config",
59
+ element: /*#__PURE__*/React.createElement(AccountModalContentWrapper, null, /*#__PURE__*/React.createElement(ConfigurationTab, {
60
+ konnector: konnectorWithTriggers,
61
+ showNewAccountButton: !konnectorWithTriggers.clientSide,
62
+ onDismiss: onDismiss
63
+ }))
64
+ })) : /*#__PURE__*/React.createElement(Route, {
35
65
  path: "accounts/:accountId",
36
66
  element: /*#__PURE__*/React.createElement(HarvestParamsWrapper, null, function (params) {
37
67
  return /*#__PURE__*/React.createElement(AccountModal, {
@@ -1,10 +1,15 @@
1
1
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
- import React, { useState, useEffect } from 'react';
2
+ import React, { useRef, useState, useEffect } from 'react';
3
+ import ActionMenu, { ActionMenuItem } from 'cozy-ui/transpiled/react/ActionMenu';
3
4
  import Alert from 'cozy-ui/transpiled/react/Alert';
4
5
  import Button from 'cozy-ui/transpiled/react/Buttons';
6
+ import Icon from 'cozy-ui/transpiled/react/Icon';
7
+ import IconButton from 'cozy-ui/transpiled/react/IconButton';
5
8
  import Typography from 'cozy-ui/transpiled/react/Typography';
6
9
  import Spinner from 'cozy-ui/transpiled/react/Spinner';
7
10
  import Snackbar from 'cozy-ui/transpiled/react/Snackbar';
11
+ import DotsIcon from 'cozy-ui/transpiled/react/Icons/Dots';
12
+ import SyncIcon from 'cozy-ui/transpiled/react/Icons/Sync';
8
13
  import { getLastSuccessDate, getKonnectorSlug } from '../../helpers/triggers';
9
14
  import { isRunnable } from '../../helpers/konnectors';
10
15
  import { useFlowState } from '../../models/withConnectionFlow';
@@ -35,6 +40,13 @@ export var LaunchTriggerAlert = function LaunchTriggerAlert(_ref) {
35
40
  win: window,
36
41
  konnector: konnector
37
42
  });
43
+ var anchorRef = useRef();
44
+
45
+ var _useState3 = useState(false),
46
+ _useState4 = _slicedToArray(_useState3, 2),
47
+ showOptions = _useState4[0],
48
+ setShowOptions = _useState4[1];
49
+
38
50
  useEffect(function () {
39
51
  if (status === SUCCESS) {
40
52
  setShowSuccessSnackbar(true);
@@ -49,7 +61,7 @@ export var LaunchTriggerAlert = function LaunchTriggerAlert(_ref) {
49
61
  className: "u-w-1 u-h-1",
50
62
  konnectorSlug: getKonnectorSlug(trigger)
51
63
  }),
52
- action: isKonnectorRunnable && /*#__PURE__*/React.createElement(Button, {
64
+ action: isKonnectorRunnable && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Button, {
53
65
  variant: "text",
54
66
  size: "small",
55
67
  disabled: running || disabled,
@@ -59,7 +71,31 @@ export var LaunchTriggerAlert = function LaunchTriggerAlert(_ref) {
59
71
  autoSuccessTimer: false
60
72
  });
61
73
  }
62
- })
74
+ }), /*#__PURE__*/React.createElement(IconButton, {
75
+ ref: anchorRef,
76
+ onClick: function onClick() {
77
+ return setShowOptions(true);
78
+ },
79
+ className: "u-p-half"
80
+ }, /*#__PURE__*/React.createElement(Icon, {
81
+ icon: DotsIcon
82
+ })), showOptions && /*#__PURE__*/React.createElement(ActionMenu, {
83
+ anchorElRef: anchorRef,
84
+ autoclose: true,
85
+ onClose: function onClose() {
86
+ return setShowOptions(false);
87
+ }
88
+ }, !running && !disabled && /*#__PURE__*/React.createElement(ActionMenuItem, {
89
+ left: /*#__PURE__*/React.createElement(Icon, {
90
+ icon: SyncIcon
91
+ }),
92
+ onClick: function onClick() {
93
+ launch({
94
+ autoSuccessTimer: false
95
+ });
96
+ setShowOptions(false);
97
+ }
98
+ }, t('card.launchTrigger.button.label'))))
63
99
  }, /*#__PURE__*/React.createElement(Typography, {
64
100
  variant: "caption"
65
101
  }, makeLabel({
@@ -66,6 +66,25 @@ export var createAccount = /*#__PURE__*/function () {
66
66
  return _ref.apply(this, arguments);
67
67
  };
68
68
  }();
69
+ /**
70
+ * Build an account query for the given konnector.
71
+ * ("getById" throws an error even if the query is not enabled)
72
+ * @param {string} accountId - io.cozy.accounts document's id
73
+ * @returns {object} - a query spec
74
+ */
75
+
76
+ export var buildAccountQueryById = function buildAccountQueryById(accountId) {
77
+ return {
78
+ definition: function definition() {
79
+ return Q(ACCOUNTS_DOCTYPE).where({
80
+ _id: accountId
81
+ });
82
+ },
83
+ options: {
84
+ as: "".concat(ACCOUNTS_DOCTYPE, "/").concat(accountId)
85
+ }
86
+ };
87
+ };
69
88
  export var createAccountQuerySpec = function createAccountQuerySpec(accountId) {
70
89
  if (!accountId) {
71
90
  throw new Error('createAccountQuerySpec called with undefined accountId');
@@ -1,7 +1,10 @@
1
+ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
1
2
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
3
 
3
4
  var _TWOFA_USER_INPUT;
4
5
 
6
+ import _regeneratorRuntime from "@babel/runtime/regenerator";
7
+
5
8
  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; }
6
9
 
7
10
  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; }
@@ -11,6 +14,8 @@ import merge from 'lodash/merge';
11
14
  import clone from 'lodash/clone';
12
15
  import assert from '../assert';
13
16
  import manifest from './manifest';
17
+ import { fetchAccount } from '../connections/accounts';
18
+ import * as triggersModel from '../helpers/triggers';
14
19
  var DEFAULT_TWOFA_CODE_PROVIDER_TYPE = 'default';
15
20
  export var TWOFA_PROVIDERS = {
16
21
  EMAIL: 'email',
@@ -207,6 +212,72 @@ export var setSessionResetIfNecessary = function setSessionResetIfNecessary(acco
207
212
  state: RESET_SESSION_STATE
208
213
  }) : account;
209
214
  };
215
+ /**
216
+ * @param {CozyClient} client - Instance of CozyClient
217
+ * @param {string} accountId - id of the account to fetch
218
+ * @param {{ account: 'io.cozy.accounts', trigger: 'io.cozy.triggers' }[]} accountsAndTriggers - list of accounts and triggers
219
+ * @returns {Promise<io.cozy.accounts>} - io.cozy.accounts document
220
+ */
221
+
222
+ export var loadSelectedAccountId = /*#__PURE__*/function () {
223
+ var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(client, accountId, accountsAndTriggers) {
224
+ var matchingTrigger;
225
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
226
+ while (1) {
227
+ switch (_context.prev = _context.next) {
228
+ case 0:
229
+ matchingTrigger = get(accountsAndTriggers.find(function (accountAndTrigger) {
230
+ return accountAndTrigger.account._id === accountId;
231
+ }), 'trigger');
232
+
233
+ if (!matchingTrigger) {
234
+ _context.next = 5;
235
+ break;
236
+ }
237
+
238
+ return _context.abrupt("return", fetchAccountProcess(client, matchingTrigger));
239
+
240
+ case 5:
241
+ return _context.abrupt("return", null);
242
+
243
+ case 6:
244
+ case "end":
245
+ return _context.stop();
246
+ }
247
+ }
248
+ }, _callee);
249
+ }));
250
+
251
+ return function loadSelectedAccountId(_x, _x2, _x3) {
252
+ return _ref2.apply(this, arguments);
253
+ };
254
+ }();
255
+ /**
256
+ * @param {CozyClient} client - Instance of CozyClient
257
+ * @param {'io.cozy.triggers'} trigger - io.cozy.triggers document
258
+ * @returns {Promise<io.cozy.accounts>} - io.cozy.accounts document
259
+ */
260
+
261
+ export var fetchAccountProcess = /*#__PURE__*/function () {
262
+ var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(client, trigger) {
263
+ return _regeneratorRuntime.wrap(function _callee2$(_context2) {
264
+ while (1) {
265
+ switch (_context2.prev = _context2.next) {
266
+ case 0:
267
+ return _context2.abrupt("return", fetchAccount(client, triggersModel.getAccountId(trigger)));
268
+
269
+ case 1:
270
+ case "end":
271
+ return _context2.stop();
272
+ }
273
+ }
274
+ }, _callee2);
275
+ }));
276
+
277
+ return function fetchAccountProcess(_x4, _x5) {
278
+ return _ref3.apply(this, arguments);
279
+ };
280
+ }();
210
281
  export default {
211
282
  build: build,
212
283
  getLabel: getLabel,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-harvest-lib",
3
- "version": "12.0.0",
3
+ "version": "12.2.0",
4
4
  "description": "Provides logic, modules and components for Cozy's harvest applications.",
5
5
  "main": "dist/index.js",
6
6
  "author": "Cozy",
@@ -88,5 +88,5 @@
88
88
  "react-router-dom": ">=4.3.1"
89
89
  },
90
90
  "sideEffects": false,
91
- "gitHead": "36d9a948b0d14e5f1500bfc58751543e956af185"
91
+ "gitHead": "53527f83fa5f4cacc7202f90e4afe22a43b24311"
92
92
  }
@@ -316,15 +316,14 @@ export class AccountForm extends PureComponent {
316
316
  t={t}
317
317
  />
318
318
  {flag('harvest.inappconnectors.enabled') && (
319
- <Typography>
320
- <Link
321
- className="u-mt-1"
322
- component="button"
323
- onClick={this.showCannotConnectModal}
324
- >
325
- {t('accountForm.cannotConnectLink')}
326
- </Link>
327
- </Typography>
319
+ <Link
320
+ className="u-mt-1"
321
+ variant="body1"
322
+ component="button"
323
+ onClick={this.showCannotConnectModal}
324
+ >
325
+ {t('accountForm.cannotConnectLink')}
326
+ </Link>
328
327
  )}
329
328
  <Button
330
329
  busy={
@@ -0,0 +1,37 @@
1
+ import React from 'react'
2
+ import { useOutletContext } from 'react-router-dom'
3
+ import DialogContent from '@material-ui/core/DialogContent'
4
+
5
+ import useBreakpoints from 'cozy-ui/transpiled/react/hooks/useBreakpoints'
6
+
7
+ import FlowProvider from '../FlowProvider'
8
+ import TriggerError from './TriggerError'
9
+
10
+ const AccountModalContentWrapper = ({ children }) => {
11
+ const { isMobile } = useBreakpoints()
12
+ const { trigger, account, konnector } = useOutletContext()
13
+
14
+ return (
15
+ <DialogContent className={isMobile ? 'u-p-0' : 'u-pt-0'}>
16
+ <FlowProvider initialTrigger={trigger} konnector={konnector}>
17
+ {({ flow }) => (
18
+ <>
19
+ <TriggerError
20
+ flow={flow}
21
+ konnector={konnector}
22
+ account={account}
23
+ trigger={trigger}
24
+ />
25
+ {React.Children.map(children, child =>
26
+ React.isValidElement(child)
27
+ ? React.cloneElement(child, { flow, trigger, account })
28
+ : null
29
+ )}
30
+ </>
31
+ )}
32
+ </FlowProvider>
33
+ </DialogContent>
34
+ )
35
+ }
36
+
37
+ export default AccountModalContentWrapper
@@ -0,0 +1,45 @@
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+
4
+ import AccountSelectBox from '../AccountSelectBox/AccountSelectBox'
5
+ import KonnectorModalHeader from '../KonnectorModalHeader'
6
+ import { withMountPointProps } from '../MountPointContext'
7
+
8
+ export const AccountModalHeader = ({
9
+ konnector,
10
+ account,
11
+ accountsAndTriggers,
12
+ showAccountSelection,
13
+ pushHistory
14
+ }) => {
15
+ return (
16
+ <KonnectorModalHeader konnector={konnector}>
17
+ {showAccountSelection && (
18
+ <AccountSelectBox
19
+ loading={!account}
20
+ selectedAccount={account}
21
+ accountsAndTriggers={accountsAndTriggers}
22
+ onChange={option => {
23
+ pushHistory(`/accounts/${option.account._id}`)
24
+ }}
25
+ onCreate={() => {
26
+ pushHistory('/new')
27
+ }}
28
+ />
29
+ )}
30
+ </KonnectorModalHeader>
31
+ )
32
+ }
33
+
34
+ AccountModalHeader.defaultProps = {
35
+ showAccountSelection: true
36
+ }
37
+ AccountModalHeader.propTypes = {
38
+ konnector: PropTypes.object.isRequired,
39
+ account: PropTypes.object,
40
+ accountsAndTriggers: PropTypes.array.isRequired,
41
+ showAccountSelection: PropTypes.bool,
42
+ pushHistory: PropTypes.func.isRequired
43
+ }
44
+
45
+ export default withMountPointProps(AccountModalHeader)
@@ -0,0 +1,80 @@
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import { Outlet } from 'react-router-dom'
4
+ import DialogContent from '@material-ui/core/DialogContent'
5
+
6
+ import { useQuery, isQueryLoading } from 'cozy-client'
7
+ import Spinner from 'cozy-ui/transpiled/react/Spinner'
8
+
9
+ import { buildAccountQueryById } from '../../connections/accounts'
10
+ import { withMountPointProps } from '../MountPointContext'
11
+ import { getMatchingTrigger } from './helpers'
12
+ import AccountModalHeader from './AccountModalHeader'
13
+ import Error from './Error'
14
+
15
+ const AccountModalWithoutTabs = ({
16
+ accountsAndTriggers,
17
+ konnector,
18
+ accountId
19
+ }) => {
20
+ const matchingTrigger = getMatchingTrigger(accountsAndTriggers, accountId)
21
+ const matchingAccountId = matchingTrigger ? accountId : undefined
22
+
23
+ const { definition, options } = buildAccountQueryById(matchingAccountId)
24
+ const { data: accounts, ...accountQueryResult } = useQuery(
25
+ definition,
26
+ options
27
+ )
28
+
29
+ const isLoading =
30
+ isQueryLoading(accountQueryResult) || accountQueryResult.hasMore
31
+
32
+ const isError =
33
+ !isLoading && (!matchingTrigger || !accounts || accounts?.length === 0)
34
+
35
+ const account = accounts?.[0]
36
+
37
+ return (
38
+ <>
39
+ <AccountModalHeader
40
+ konnector={konnector}
41
+ account={account}
42
+ accountsAndTriggers={accountsAndTriggers}
43
+ />
44
+ {(isError || isLoading) && (
45
+ <DialogContent className="u-pb-2">
46
+ {isError && (
47
+ <Error
48
+ accountId={accountId}
49
+ accountsAndTriggers={accountsAndTriggers}
50
+ trigger={matchingTrigger}
51
+ lastError={accountQueryResult.lastError}
52
+ />
53
+ )}
54
+ {isLoading && (
55
+ <Spinner className="u-flex u-flex-justify-center" size="xxlarge" />
56
+ )}
57
+ </DialogContent>
58
+ )}
59
+ {!isError && !isLoading && (
60
+ <Outlet context={{ trigger: matchingTrigger, account, konnector }} />
61
+ )}
62
+ </>
63
+ )
64
+ }
65
+
66
+ AccountModalWithoutTabs.propTypes = {
67
+ konnector: PropTypes.object.isRequired,
68
+ /**
69
+ * @type {{ account: 'io.cozy.accounts', trigger: 'io.cozy.triggers' }[]} - An array of objects containing an account and its associated trigger
70
+ */
71
+ accountsAndTriggers: PropTypes.arrayOf(
72
+ PropTypes.shape({
73
+ account: PropTypes.object.isRequired,
74
+ trigger: PropTypes.object.isRequired
75
+ })
76
+ ).isRequired,
77
+ accountId: PropTypes.string.isRequired
78
+ }
79
+
80
+ export default withMountPointProps(AccountModalWithoutTabs)
@@ -0,0 +1,38 @@
1
+ import React from 'react'
2
+
3
+ import { useClient } from 'cozy-client'
4
+ import Infos from 'cozy-ui/transpiled/react/Infos'
5
+ import Button from 'cozy-ui/transpiled/react/Buttons'
6
+ import { useI18n } from 'cozy-ui/transpiled/react/I18n'
7
+
8
+ import { loadSelectedAccountId } from '../../helpers/accounts'
9
+ import withLocales from '../hoc/withLocales'
10
+
11
+ const Error = ({ accountId, accountsAndTriggers, trigger, lastError }) => {
12
+ const { t } = useI18n()
13
+ const client = useClient()
14
+
15
+ const error = !trigger ? new Error('No matching trigger found') : lastError
16
+
17
+ const handleClick = () => {
18
+ loadSelectedAccountId(client, accountId, accountsAndTriggers)
19
+ }
20
+
21
+ return (
22
+ <Infos
23
+ actionButton={
24
+ <Button
25
+ label={t('modal.konnector.error.button')}
26
+ color="error"
27
+ onClick={handleClick}
28
+ />
29
+ }
30
+ title={t('modal.konnector.error.title')}
31
+ text={t('modal.konnector.error.description', error)}
32
+ icon="warning"
33
+ isImportant
34
+ />
35
+ )
36
+ }
37
+
38
+ export default withLocales(Error)
@@ -0,0 +1,58 @@
1
+ import React, { useCallback } from 'react'
2
+ import PropTypes from 'prop-types'
3
+
4
+ import flag from 'cozy-flags'
5
+ import { useClient } from 'cozy-client'
6
+ import { useI18n } from 'cozy-ui/transpiled/react/I18n'
7
+ import { Button } from 'cozy-ui/transpiled/react/Button'
8
+
9
+ import useOAuthExtraParams from '../hooks/useOAuthExtraParams'
10
+ import { OAUTH_SERVICE_OK, openOAuthWindow } from '../OAuthService'
11
+
12
+ const OpenOAuthWindowButton = ({ flow, account, konnector }) => {
13
+ const { t } = useI18n()
14
+ const client = useClient()
15
+
16
+ const { extraParams } = useOAuthExtraParams({
17
+ account,
18
+ client,
19
+ konnector,
20
+ reconnect: true
21
+ })
22
+
23
+ const handleClick = useCallback(async () => {
24
+ const response = await openOAuthWindow({
25
+ client,
26
+ konnector,
27
+ account,
28
+ extraParams,
29
+ reconnect: true
30
+ })
31
+
32
+ if (
33
+ response.result === OAUTH_SERVICE_OK &&
34
+ flag('harvest.bi.fullwebhooks')
35
+ ) {
36
+ flow.expectTriggerLaunch()
37
+ }
38
+ }, [account, client, extraParams, flow, konnector])
39
+
40
+ return (
41
+ <Button
42
+ className="u-ml-0"
43
+ variant="secondary"
44
+ label={t('error.reconnect-via-form')}
45
+ onClick={handleClick}
46
+ disabled={!extraParams}
47
+ busy={!extraParams}
48
+ />
49
+ )
50
+ }
51
+
52
+ OpenOAuthWindowButton.propTypes = {
53
+ flow: PropTypes.object.isRequired,
54
+ account: PropTypes.object.isRequired,
55
+ konnector: PropTypes.object.isRequired
56
+ }
57
+
58
+ export default OpenOAuthWindowButton
@@ -0,0 +1,46 @@
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+
4
+ import { useClient } from 'cozy-client'
5
+
6
+ import useMaintenanceStatus from '../hooks/useMaintenanceStatus'
7
+ import TriggerErrorInfo from '../infos/TriggerErrorInfo'
8
+ import TriggerErrorAction from './TriggerErrorAction'
9
+
10
+ const TriggerError = ({ flow, konnector, account, trigger }) => {
11
+ const client = useClient()
12
+ const flowState = flow.getState()
13
+ const { error } = flowState
14
+
15
+ const {
16
+ data: { isInMaintenance }
17
+ } = useMaintenanceStatus(client, konnector)
18
+
19
+ if (!error || isInMaintenance) return null
20
+
21
+ return (
22
+ <TriggerErrorInfo
23
+ error={error}
24
+ konnector={konnector}
25
+ action={
26
+ <TriggerErrorAction
27
+ error={error}
28
+ flow={flow}
29
+ konnector={konnector}
30
+ account={account}
31
+ trigger={trigger}
32
+ />
33
+ }
34
+ className="u-mt-1"
35
+ />
36
+ )
37
+ }
38
+
39
+ export default TriggerError
40
+
41
+ TriggerError.propTypes = {
42
+ flow: PropTypes.object.isRequired,
43
+ konnector: PropTypes.object.isRequired,
44
+ account: PropTypes.object,
45
+ trigger: PropTypes.object
46
+ }
@@ -0,0 +1,33 @@
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+
4
+ import { findKonnectorPolicy } from '../../konnector-policies'
5
+ import RedirectToAccountFormButton from '../RedirectToAccountFormButton'
6
+ import OpenOAuthWindowButton from './OpenOAuthWindowButton'
7
+
8
+ const TriggerErrorAction = ({ flow, konnector, account, trigger, error }) => {
9
+ const konnectorPolicy = findKonnectorPolicy(konnector)
10
+
11
+ if (!error.isSolvableViaReconnect()) return null
12
+
13
+ if (konnectorPolicy.isBIWebView)
14
+ return (
15
+ <OpenOAuthWindowButton
16
+ flow={flow}
17
+ account={account}
18
+ konnector={konnector}
19
+ />
20
+ )
21
+
22
+ return <RedirectToAccountFormButton konnector={konnector} trigger={trigger} />
23
+ }
24
+
25
+ TriggerErrorAction.propTypes = {
26
+ flow: PropTypes.object.isRequired,
27
+ konnector: PropTypes.object.isRequired,
28
+ account: PropTypes.object,
29
+ trigger: PropTypes.object,
30
+ error: PropTypes.object.isRequired
31
+ }
32
+
33
+ export default TriggerErrorAction
@@ -0,0 +1,10 @@
1
+ import get from 'lodash/get'
2
+
3
+ export const getMatchingTrigger = (accountsAndTriggers, accountId) => {
4
+ return get(
5
+ accountsAndTriggers.find(
6
+ accountAndTrigger => accountAndTrigger.account._id === accountId
7
+ ),
8
+ 'trigger'
9
+ )
10
+ }
@@ -5,10 +5,14 @@ import flag from 'cozy-flags'
5
5
 
6
6
  import { ViewerModal } from '../../datacards/ViewerModal'
7
7
  import AccountModal from '../AccountModal'
8
+ import AccountModalWithoutTabs from '../AccountModalWithoutTabs/AccountModalWithoutTabs'
9
+ import AccountModalContentWrapper from '../AccountModalWithoutTabs/AccountModalContentWrapper'
8
10
  import NewAccountModal from '../NewAccountModal'
9
11
  import EditAccountModal from '../EditAccountModal'
10
12
  import KonnectorSuccess from '../KonnectorSuccess'
11
13
  import HarvestModalRoot from '../HarvestModalRoot'
14
+ import DataTab from '../KonnectorConfiguration/DataTab'
15
+ import ConfigurationTab from '../KonnectorConfiguration/ConfigurationTab'
12
16
 
13
17
  const HarvestParamsWrapper = props => {
14
18
  const params = useParams()
@@ -44,23 +48,69 @@ const RoutesV6 = ({
44
48
  }
45
49
  />
46
50
 
47
- <Route
48
- path="accounts/:accountId"
49
- element={
50
- <HarvestParamsWrapper>
51
- {params => (
52
- <AccountModal
53
- konnector={konnectorWithTriggers}
54
- accountId={params.accountId}
55
- accountsAndTriggers={accountsAndTriggers}
56
- onDismiss={onDismiss}
57
- showNewAccountButton={!konnectorWithTriggers.clientSide}
58
- showAccountSelection={!konnectorWithTriggers.clientSide}
59
- />
60
- )}
61
- </HarvestParamsWrapper>
62
- }
63
- />
51
+ {flag('harvest.inappconnectors.enabled') ? (
52
+ <Route
53
+ path="accounts/:accountId"
54
+ element={
55
+ <HarvestParamsWrapper>
56
+ {params => (
57
+ <AccountModalWithoutTabs
58
+ konnector={konnectorWithTriggers}
59
+ accountId={params.accountId}
60
+ accountsAndTriggers={accountsAndTriggers}
61
+ showNewAccountButton={!konnectorWithTriggers.clientSide}
62
+ showAccountSelection={!konnectorWithTriggers.clientSide}
63
+ onDismiss={onDismiss}
64
+ />
65
+ )}
66
+ </HarvestParamsWrapper>
67
+ }
68
+ >
69
+ <Route
70
+ index
71
+ element={
72
+ <AccountModalContentWrapper>
73
+ <DataTab
74
+ konnector={konnectorWithTriggers}
75
+ showNewAccountButton={!konnectorWithTriggers.clientSide}
76
+ onDismiss={onDismiss}
77
+ />
78
+ </AccountModalContentWrapper>
79
+ }
80
+ />
81
+ <Route
82
+ path="config"
83
+ element={
84
+ <AccountModalContentWrapper>
85
+ <ConfigurationTab
86
+ konnector={konnectorWithTriggers}
87
+ showNewAccountButton={!konnectorWithTriggers.clientSide}
88
+ onDismiss={onDismiss}
89
+ />
90
+ </AccountModalContentWrapper>
91
+ }
92
+ />
93
+ </Route>
94
+ ) : (
95
+ <Route
96
+ path="accounts/:accountId"
97
+ element={
98
+ <HarvestParamsWrapper>
99
+ {params => (
100
+ <AccountModal
101
+ konnector={konnectorWithTriggers}
102
+ accountId={params.accountId}
103
+ accountsAndTriggers={accountsAndTriggers}
104
+ onDismiss={onDismiss}
105
+ showNewAccountButton={!konnectorWithTriggers.clientSide}
106
+ showAccountSelection={!konnectorWithTriggers.clientSide}
107
+ />
108
+ )}
109
+ </HarvestParamsWrapper>
110
+ }
111
+ />
112
+ )}
113
+
64
114
  <Route
65
115
  path="accounts/:accountId/edit"
66
116
  element={
@@ -1,10 +1,15 @@
1
- import React, { useState, useEffect } from 'react'
1
+ import React, { useRef, useState, useEffect } from 'react'
2
2
 
3
+ import ActionMenu, { ActionMenuItem } from 'cozy-ui/transpiled/react/ActionMenu'
3
4
  import Alert from 'cozy-ui/transpiled/react/Alert'
4
5
  import Button from 'cozy-ui/transpiled/react/Buttons'
6
+ import Icon from 'cozy-ui/transpiled/react/Icon'
7
+ import IconButton from 'cozy-ui/transpiled/react/IconButton'
5
8
  import Typography from 'cozy-ui/transpiled/react/Typography'
6
9
  import Spinner from 'cozy-ui/transpiled/react/Spinner'
7
10
  import Snackbar from 'cozy-ui/transpiled/react/Snackbar'
11
+ import DotsIcon from 'cozy-ui/transpiled/react/Icons/Dots'
12
+ import SyncIcon from 'cozy-ui/transpiled/react/Icons/Sync'
8
13
 
9
14
  import { getLastSuccessDate, getKonnectorSlug } from '../../helpers/triggers'
10
15
  import { isRunnable } from '../../helpers/konnectors'
@@ -21,6 +26,8 @@ export const LaunchTriggerAlert = ({ flow, f, t, disabled }) => {
21
26
 
22
27
  const lastSuccessDate = getLastSuccessDate(trigger)
23
28
  const isKonnectorRunnable = isRunnable({ win: window, konnector })
29
+ const anchorRef = useRef()
30
+ const [showOptions, setShowOptions] = useState(false)
24
31
 
25
32
  useEffect(() => {
26
33
  if (status === SUCCESS) {
@@ -44,13 +51,41 @@ export const LaunchTriggerAlert = ({ flow, f, t, disabled }) => {
44
51
  }
45
52
  action={
46
53
  isKonnectorRunnable && (
47
- <Button
48
- variant="text"
49
- size="small"
50
- disabled={running || disabled}
51
- label={t('card.launchTrigger.button.label')}
52
- onClick={() => launch({ autoSuccessTimer: false })}
53
- />
54
+ <>
55
+ <Button
56
+ variant="text"
57
+ size="small"
58
+ disabled={running || disabled}
59
+ label={t('card.launchTrigger.button.label')}
60
+ onClick={() => launch({ autoSuccessTimer: false })}
61
+ />
62
+ <IconButton
63
+ ref={anchorRef}
64
+ onClick={() => setShowOptions(true)}
65
+ className="u-p-half"
66
+ >
67
+ <Icon icon={DotsIcon} />
68
+ </IconButton>
69
+ {showOptions && (
70
+ <ActionMenu
71
+ anchorElRef={anchorRef}
72
+ autoclose={true}
73
+ onClose={() => setShowOptions(false)}
74
+ >
75
+ {!running && !disabled && (
76
+ <ActionMenuItem
77
+ left={<Icon icon={SyncIcon} />}
78
+ onClick={() => {
79
+ launch({ autoSuccessTimer: false })
80
+ setShowOptions(false)
81
+ }}
82
+ >
83
+ {t('card.launchTrigger.button.label')}
84
+ </ActionMenuItem>
85
+ )}
86
+ </ActionMenu>
87
+ )}
88
+ </>
54
89
  )
55
90
  }
56
91
  >
@@ -22,6 +22,24 @@ export const createAccount = async (client, konnector, attributes) => {
22
22
  return data
23
23
  }
24
24
 
25
+ /**
26
+ * Build an account query for the given konnector.
27
+ * ("getById" throws an error even if the query is not enabled)
28
+ * @param {string} accountId - io.cozy.accounts document's id
29
+ * @returns {object} - a query spec
30
+ */
31
+ export const buildAccountQueryById = accountId => {
32
+ return {
33
+ definition: () =>
34
+ Q(ACCOUNTS_DOCTYPE).where({
35
+ _id: accountId
36
+ }),
37
+ options: {
38
+ as: `${ACCOUNTS_DOCTYPE}/${accountId}`
39
+ }
40
+ }
41
+ }
42
+
25
43
  export const createAccountQuerySpec = accountId => {
26
44
  if (!accountId) {
27
45
  throw new Error('createAccountQuerySpec called with undefined accountId')
@@ -4,6 +4,8 @@ import clone from 'lodash/clone'
4
4
 
5
5
  import assert from '../assert'
6
6
  import manifest from './manifest'
7
+ import { fetchAccount } from '../connections/accounts'
8
+ import * as triggersModel from '../helpers/triggers'
7
9
 
8
10
  const DEFAULT_TWOFA_CODE_PROVIDER_TYPE = 'default'
9
11
 
@@ -207,6 +209,39 @@ export const setSessionResetIfNecessary = (account, changedFields = {}) => {
207
209
  : account
208
210
  }
209
211
 
212
+ /**
213
+ * @param {CozyClient} client - Instance of CozyClient
214
+ * @param {string} accountId - id of the account to fetch
215
+ * @param {{ account: 'io.cozy.accounts', trigger: 'io.cozy.triggers' }[]} accountsAndTriggers - list of accounts and triggers
216
+ * @returns {Promise<io.cozy.accounts>} - io.cozy.accounts document
217
+ */
218
+ export const loadSelectedAccountId = async (
219
+ client,
220
+ accountId,
221
+ accountsAndTriggers
222
+ ) => {
223
+ const matchingTrigger = get(
224
+ accountsAndTriggers.find(
225
+ accountAndTrigger => accountAndTrigger.account._id === accountId
226
+ ),
227
+ 'trigger'
228
+ )
229
+ if (matchingTrigger) {
230
+ return fetchAccountProcess(client, matchingTrigger)
231
+ } else {
232
+ return null
233
+ }
234
+ }
235
+
236
+ /**
237
+ * @param {CozyClient} client - Instance of CozyClient
238
+ * @param {'io.cozy.triggers'} trigger - io.cozy.triggers document
239
+ * @returns {Promise<io.cozy.accounts>} - io.cozy.accounts document
240
+ */
241
+ export const fetchAccountProcess = async (client, trigger) => {
242
+ return fetchAccount(client, triggersModel.getAccountId(trigger))
243
+ }
244
+
210
245
  export default {
211
246
  build,
212
247
  getLabel,