@truedat/cx 4.36.7 → 4.37.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/package.json +7 -6
  3. package/src/configurations/components/ConfigurationActions.js +1 -1
  4. package/src/configurations/components/ConfigurationCards.js +1 -1
  5. package/src/configurations/components/__tests__/__snapshots__/ConfigurationCards.spec.js.snap +5 -5
  6. package/src/messages/en.js +32 -25
  7. package/src/messages/es.js +32 -25
  8. package/src/sources/components/EditSource.js +3 -3
  9. package/src/sources/components/NewSource.js +1 -1
  10. package/src/sources/components/Source.js +3 -3
  11. package/src/sources/components/SourceActions.js +107 -79
  12. package/src/sources/components/SourceForm.js +15 -24
  13. package/src/sources/components/SourceRoutes.js +8 -18
  14. package/src/sources/components/{SourcesSelector.js → SourceSelector.js} +0 -0
  15. package/src/sources/components/Sources.js +53 -47
  16. package/src/sources/components/SourcesTable.js +88 -0
  17. package/src/sources/components/__tests__/SourceActions.spec.js +27 -6
  18. package/src/sources/components/__tests__/Sources.spec.js +68 -18
  19. package/src/sources/components/__tests__/SourcesTable.spec.js +59 -0
  20. package/src/sources/components/__tests__/__snapshots__/EditSource.spec.js.snap +3 -3
  21. package/src/sources/components/__tests__/__snapshots__/NewSource.spec.js.snap +1 -1
  22. package/src/sources/components/__tests__/__snapshots__/Source.spec.js.snap +1 -1
  23. package/src/sources/components/__tests__/__snapshots__/SourceActions.spec.js.snap +53 -65
  24. package/src/sources/components/__tests__/__snapshots__/SourceForm.spec.js.snap +10 -8
  25. package/src/sources/components/__tests__/__snapshots__/Sources.spec.js.snap +170 -62
  26. package/src/sources/components/__tests__/__snapshots__/SourcesTable.spec.js.snap +217 -0
  27. package/src/sources/components/index.js +3 -3
  28. package/src/sources/reducers/__tests__/sourceRedirect.spec.js +28 -5
  29. package/src/sources/reducers/source.js +4 -3
  30. package/src/sources/reducers/sourceRedirect.js +7 -1
  31. package/src/sources/routines.js +6 -4
  32. package/src/sources/sagas/__tests__/disableSource.spec.js +82 -0
  33. package/src/sources/sagas/__tests__/enableSource.spec.js +82 -0
  34. package/src/sources/sagas/disableSource.js +39 -0
  35. package/src/sources/sagas/enableSource.js +39 -0
  36. package/src/sources/sagas/index.js +13 -7
  37. package/src/sources/components/SourceCards.js +0 -115
  38. package/src/sources/components/__tests__/SourceCards.spec.js +0 -45
  39. package/src/sources/components/__tests__/__snapshots__/SourceCards.spec.js.snap +0 -421
@@ -2,11 +2,12 @@ import _ from "lodash/fp";
2
2
  import { fetchSource, clearSource } from "../routines";
3
3
 
4
4
  const pickFields = _.pick([
5
+ "active",
6
+ "config",
5
7
  "external_id",
8
+ "id",
9
+ "job_types",
6
10
  "type",
7
- "config",
8
- "active",
9
- "job_types"
10
11
  ]);
11
12
 
12
13
  const initialState = {};
@@ -4,7 +4,9 @@ import {
4
4
  createJob,
5
5
  createSource,
6
6
  deleteSource,
7
- updateSource
7
+ disableSource,
8
+ enableSource,
9
+ updateSource,
8
10
  } from "../routines";
9
11
 
10
12
  const initialState = "";
@@ -22,6 +24,10 @@ export const sourceRedirect = (state = initialState, { type, payload }) => {
22
24
  return SOURCES;
23
25
  case deleteSource.SUCCESS:
24
26
  return SOURCES;
27
+ case disableSource.SUCCESS:
28
+ return SOURCES;
29
+ case enableSource.SUCCESS:
30
+ return SOURCES;
25
31
  default:
26
32
  return state;
27
33
  }
@@ -1,10 +1,12 @@
1
1
  import { createRoutine } from "redux-saga-routines";
2
2
 
3
- export const fetchSource = createRoutine("FETCH_SOURCE");
4
- export const fetchSources = createRoutine("FETCH_SOURCES");
5
3
  export const clearSource = createRoutine("CLEAR_SOURCE");
6
4
  export const clearSources = createRoutine("CLEAR_SOURCES");
7
- export const deleteSource = createRoutine("DELETE_SOURCE");
5
+ export const createJob = createRoutine("CREATE_JOB");
8
6
  export const createSource = createRoutine("CREATE_SOURCE");
7
+ export const deleteSource = createRoutine("DELETE_SOURCE");
8
+ export const disableSource = createRoutine("DISABLE_SOURCE");
9
+ export const enableSource = createRoutine("ENABLE_SOURCE");
10
+ export const fetchSource = createRoutine("FETCH_SOURCE");
11
+ export const fetchSources = createRoutine("FETCH_SOURCES");
9
12
  export const updateSource = createRoutine("UPDATE_SOURCE");
10
- export const createJob = createRoutine("CREATE_JOB");
@@ -0,0 +1,82 @@
1
+ import { testSaga } from "redux-saga-test-plan";
2
+ import {
3
+ DISABLE_SOURCE,
4
+ disableSourceRequestSaga,
5
+ disableSourceSaga,
6
+ onSuccess,
7
+ } from "../disableSource";
8
+ import { disableSource } from "../../routines";
9
+
10
+ describe("sagas: disableSourceRequestSaga", () => {
11
+ it("should invoke disableSourceSaga on trigger", () => {
12
+ expect(() => {
13
+ testSaga(disableSourceRequestSaga)
14
+ .next()
15
+ .takeLatest(disableSource.TRIGGER, disableSourceSaga)
16
+ .finish()
17
+ .isDone();
18
+ }).not.toThrow();
19
+ });
20
+
21
+ it("should throw exception if an unhandled action is received", () => {
22
+ expect(() => {
23
+ testSaga(disableSourceRequestSaga)
24
+ .next()
25
+ .takeLatest("FOO", disableSourceSaga);
26
+ }).toThrow();
27
+ });
28
+ });
29
+
30
+ describe("sagas: disableSourceSaga", () => {
31
+ const id = 1;
32
+ const payload = { id };
33
+ const client = { mutate: jest.fn() };
34
+
35
+ it("should put a success action when a response is returned", () => {
36
+ expect(() => {
37
+ testSaga(disableSourceSaga, { payload })
38
+ .next()
39
+ .getContext("client")
40
+ .next(client)
41
+ .put(disableSource.request(payload))
42
+ .next()
43
+ .call(client.mutate, {
44
+ mutation: DISABLE_SOURCE,
45
+ update: onSuccess,
46
+ variables: payload,
47
+ })
48
+ .next({ data: payload })
49
+ .put(disableSource.success(payload))
50
+ .next()
51
+ .put(disableSource.fulfill())
52
+ .next()
53
+ .isDone();
54
+ }).not.toThrow();
55
+ });
56
+
57
+ it("should put a failure action when the call throws an error", () => {
58
+ const message = "Request failed";
59
+ const error = { message };
60
+ const client = { mutate: jest.fn() };
61
+
62
+ expect(() => {
63
+ testSaga(disableSourceSaga, { payload })
64
+ .next()
65
+ .getContext("client")
66
+ .next(client)
67
+ .put(disableSource.request(payload))
68
+ .next()
69
+ .call(client.mutate, {
70
+ mutation: DISABLE_SOURCE,
71
+ update: onSuccess,
72
+ variables: payload,
73
+ })
74
+ .throw(error)
75
+ .put(disableSource.failure(message))
76
+ .next()
77
+ .put(disableSource.fulfill())
78
+ .next()
79
+ .isDone();
80
+ }).not.toThrow();
81
+ });
82
+ });
@@ -0,0 +1,82 @@
1
+ import { testSaga } from "redux-saga-test-plan";
2
+ import {
3
+ ENABLE_SOURCE,
4
+ enableSourceRequestSaga,
5
+ enableSourceSaga,
6
+ onSuccess,
7
+ } from "../enableSource";
8
+ import { enableSource } from "../../routines";
9
+
10
+ describe("sagas: enableSourceRequestSaga", () => {
11
+ it("should invoke enableSourceSaga on trigger", () => {
12
+ expect(() => {
13
+ testSaga(enableSourceRequestSaga)
14
+ .next()
15
+ .takeLatest(enableSource.TRIGGER, enableSourceSaga)
16
+ .finish()
17
+ .isDone();
18
+ }).not.toThrow();
19
+ });
20
+
21
+ it("should throw exception if an unhandled action is received", () => {
22
+ expect(() => {
23
+ testSaga(enableSourceRequestSaga)
24
+ .next()
25
+ .takeLatest("FOO", enableSourceSaga);
26
+ }).toThrow();
27
+ });
28
+ });
29
+
30
+ describe("sagas: enableSourceSaga", () => {
31
+ const id = 1;
32
+ const payload = { id };
33
+ const client = { mutate: jest.fn() };
34
+
35
+ it("should put a success action when a response is returned", () => {
36
+ expect(() => {
37
+ testSaga(enableSourceSaga, { payload })
38
+ .next()
39
+ .getContext("client")
40
+ .next(client)
41
+ .put(enableSource.request(payload))
42
+ .next()
43
+ .call(client.mutate, {
44
+ mutation: ENABLE_SOURCE,
45
+ update: onSuccess,
46
+ variables: payload,
47
+ })
48
+ .next({ data: payload })
49
+ .put(enableSource.success(payload))
50
+ .next()
51
+ .put(enableSource.fulfill())
52
+ .next()
53
+ .isDone();
54
+ }).not.toThrow();
55
+ });
56
+
57
+ it("should put a failure action when the call throws an error", () => {
58
+ const message = "Request failed";
59
+ const error = { message };
60
+ const client = { mutate: jest.fn() };
61
+
62
+ expect(() => {
63
+ testSaga(enableSourceSaga, { payload })
64
+ .next()
65
+ .getContext("client")
66
+ .next(client)
67
+ .put(enableSource.request(payload))
68
+ .next()
69
+ .call(client.mutate, {
70
+ mutation: ENABLE_SOURCE,
71
+ update: onSuccess,
72
+ variables: payload,
73
+ })
74
+ .throw(error)
75
+ .put(enableSource.failure(message))
76
+ .next()
77
+ .put(enableSource.fulfill())
78
+ .next()
79
+ .isDone();
80
+ }).not.toThrow();
81
+ });
82
+ });
@@ -0,0 +1,39 @@
1
+ import { gql } from "@apollo/client";
2
+ import { call, put, takeLatest, getContext } from "redux-saga/effects";
3
+ import { disableSource } from "../routines";
4
+
5
+ export const DISABLE_SOURCE = gql`
6
+ mutation DisableSource($id: ID!) {
7
+ disableSource(id: $id) {
8
+ id
9
+ externalId
10
+ }
11
+ }
12
+ `;
13
+
14
+ export const onSuccess = (cache, { data: { disableSource } }) => {
15
+ cache.evict({ id: "ROOT_QUERY", fieldName: "sources" });
16
+ cache.evict({ id: cache.identify(disableSource) });
17
+ cache.gc();
18
+ };
19
+
20
+ export function* disableSourceSaga({ payload }) {
21
+ const client = yield getContext("client");
22
+ yield put(disableSource.request(payload));
23
+ try {
24
+ const { data } = yield call(client.mutate, {
25
+ mutation: DISABLE_SOURCE,
26
+ update: onSuccess,
27
+ variables: payload,
28
+ });
29
+ yield put(disableSource.success(data));
30
+ } catch (error) {
31
+ yield put(disableSource.failure(error.message));
32
+ } finally {
33
+ yield put(disableSource.fulfill());
34
+ }
35
+ }
36
+
37
+ export function* disableSourceRequestSaga() {
38
+ yield takeLatest(disableSource.TRIGGER, disableSourceSaga);
39
+ }
@@ -0,0 +1,39 @@
1
+ import { gql } from "@apollo/client";
2
+ import { call, put, takeLatest, getContext } from "redux-saga/effects";
3
+ import { enableSource } from "../routines";
4
+
5
+ export const ENABLE_SOURCE = gql`
6
+ mutation EnableSource($id: ID!) {
7
+ enableSource(id: $id) {
8
+ id
9
+ externalId
10
+ }
11
+ }
12
+ `;
13
+
14
+ export const onSuccess = (cache, { data: { enableSource } }) => {
15
+ cache.evict({ id: "ROOT_QUERY", fieldName: "sources" });
16
+ cache.evict({ id: cache.identify(enableSource) });
17
+ cache.gc();
18
+ };
19
+
20
+ export function* enableSourceSaga({ payload }) {
21
+ const client = yield getContext("client");
22
+ yield put(enableSource.request(payload));
23
+ try {
24
+ const { data } = yield call(client.mutate, {
25
+ mutation: ENABLE_SOURCE,
26
+ update: onSuccess,
27
+ variables: payload,
28
+ });
29
+ yield put(enableSource.success(data));
30
+ } catch (error) {
31
+ yield put(enableSource.failure(error.message));
32
+ } finally {
33
+ yield put(enableSource.fulfill());
34
+ }
35
+ }
36
+
37
+ export function* enableSourceRequestSaga() {
38
+ yield takeLatest(enableSource.TRIGGER, enableSourceSaga);
39
+ }
@@ -1,21 +1,27 @@
1
- import { fetchSourcesRequestSaga } from "./fetchSources";
2
- import { fetchSourceRequestSaga } from "./fetchSource";
3
- import { deleteSourceRequestSaga } from "./deleteSource";
4
1
  import { createSourceRequestSaga } from "./createSource";
2
+ import { deleteSourceRequestSaga } from "./deleteSource";
3
+ import { disableSourceRequestSaga } from "./disableSource";
4
+ import { enableSourceRequestSaga } from "./enableSource";
5
+ import { fetchSourceRequestSaga } from "./fetchSource";
6
+ import { fetchSourcesRequestSaga } from "./fetchSources";
5
7
  import { updateSourceRequestSaga } from "./updateSource";
6
8
 
7
9
  export {
10
+ createSourceRequestSaga,
8
11
  deleteSourceRequestSaga,
12
+ disableSourceRequestSaga,
13
+ enableSourceRequestSaga,
9
14
  fetchSourceRequestSaga,
10
15
  fetchSourcesRequestSaga,
11
- createSourceRequestSaga,
12
- updateSourceRequestSaga
16
+ updateSourceRequestSaga,
13
17
  };
14
18
 
15
19
  export default [
20
+ createSourceRequestSaga(),
16
21
  deleteSourceRequestSaga(),
22
+ disableSourceRequestSaga(),
23
+ enableSourceRequestSaga(),
17
24
  fetchSourceRequestSaga(),
18
25
  fetchSourcesRequestSaga(),
19
- createSourceRequestSaga(),
20
- updateSourceRequestSaga()
26
+ updateSourceRequestSaga(),
21
27
  ];
@@ -1,115 +0,0 @@
1
- import _ from "lodash/fp";
2
- import React from "react";
3
- import PropTypes from "prop-types";
4
- import { connect } from "react-redux";
5
- import { Button, Card, Icon, Message } from "semantic-ui-react";
6
- import { Link } from "react-router-dom";
7
- import { FormattedMessage } from "react-intl";
8
- import { ConfirmModal } from "@truedat/core/components";
9
- import { linkTo } from "@truedat/core/routes";
10
- import { useIntl } from "react-intl";
11
- import { deleteSource, updateSource } from "../routines";
12
-
13
- export const SourceCards = ({
14
- deleteSource,
15
- updateSource,
16
- sources,
17
- sourcesLoading,
18
- }) => {
19
- const { formatMessage } = useIntl();
20
- if (sourcesLoading) return <div />;
21
-
22
- return sources && !_.isEmpty(sources) ? (
23
- <Card.Group>
24
- {sources.map((source, i) => (
25
- <Card key={i}>
26
- <Card.Content>
27
- <Card.Header
28
- as={Link}
29
- to={linkTo.SOURCE({ external_id: source.external_id })}
30
- >
31
- <FormattedMessage
32
- id={`${"source"}.${source.external_id}`}
33
- defaultMessage={source.external_id}
34
- />
35
- </Card.Header>
36
- {!source.active && (
37
- <Card.Meta>
38
- <FormattedMessage id={`source.deactivated`} />
39
- </Card.Meta>
40
- )}
41
- <Card.Description>
42
- <FormattedMessage id={source.type} defaultMessage={source.type} />
43
- </Card.Description>
44
- </Card.Content>
45
- <Card.Content extra>
46
- <div className="ui actions">
47
- <Button
48
- icon={source.active ? "pause" : "play"}
49
- basic
50
- data-tooltip={
51
- source.active
52
- ? formatMessage({
53
- id: "sources.actions.deactivate.tooltip",
54
- })
55
- : formatMessage({ id: "sources.actions.activate.tooltip" })
56
- }
57
- onClick={() =>
58
- updateSource({
59
- source: {
60
- external_id: source.external_id,
61
- active: !source.active,
62
- },
63
- })
64
- }
65
- />
66
- <ConfirmModal
67
- icon="trash"
68
- trigger={<Button icon="trash" basic color="red" />}
69
- header={
70
- <FormattedMessage id="sources.actions.delete.confirmation.header" />
71
- }
72
- content={
73
- <FormattedMessage
74
- id="sources.actions.delete.confirmation.content"
75
- values={{ external_id: <b>{source.external_id}</b> }}
76
- />
77
- }
78
- handleSubmit={() =>
79
- deleteSource({ external_id: source.external_id })
80
- }
81
- />
82
- </div>
83
- </Card.Content>
84
- </Card>
85
- ))}
86
- </Card.Group>
87
- ) : (
88
- <Card.Group>
89
- <Message
90
- className="users-message"
91
- header={
92
- <div>
93
- <Icon name="search" />
94
- <FormattedMessage id="source.search.no_results" />
95
- </div>
96
- }
97
- />
98
- </Card.Group>
99
- );
100
- };
101
-
102
- SourceCards.propTypes = {
103
- deleteSource: PropTypes.func,
104
- updateSource: PropTypes.func,
105
- sources: PropTypes.array,
106
- sourcesLoading: PropTypes.bool,
107
- };
108
-
109
- const mapStateToProps = ({ sourcesLoading }) => ({
110
- sourcesLoading,
111
- });
112
-
113
- export default connect(mapStateToProps, { deleteSource, updateSource })(
114
- SourceCards
115
- );
@@ -1,45 +0,0 @@
1
- import React from "react";
2
- import { intl } from "@truedat/test/intl-stub";
3
- import { shallowWithIntl } from "@truedat/test/intl-stub";
4
- import { Card, Message } from "semantic-ui-react";
5
- import { SourceCards } from "../SourceCards";
6
-
7
- // workaround for enzyme issue with React.useContext
8
- // see https://github.com/airbnb/enzyme/issues/2176#issuecomment-532361526
9
- jest.spyOn(React, "useContext").mockImplementation(() => intl);
10
-
11
- describe("<SourceCards />", () => {
12
- const sources = [
13
- {
14
- external_id: "con_url",
15
- type: "a",
16
- config: {
17
- a: "aaa",
18
- lista: ["bbb", "ddd"],
19
- url_cx: [{ url_name: "google", url_value: "https://google.es" }]
20
- }
21
- },
22
- { external_id: "id1", type: "app-admin", config: {} },
23
- { external_id: "id2", type: "app-admin", config: { a: 1 } },
24
- { external_id: "id3", type: "app-admin", config: { a: "yyyyb" } },
25
- { external_id: "id4", type: "a", config: { lista: ["codigo6"] } }
26
- ];
27
-
28
- it("matches the latest snapshot", () => {
29
- const wrapper = shallowWithIntl(<SourceCards sources={sources} />);
30
- expect(wrapper).toMatchSnapshot();
31
- });
32
-
33
- it("contains a message when no sources are found", () => {
34
- const props = { sources: [] };
35
- const wrapper = shallowWithIntl(<SourceCards {...props} />);
36
- expect(wrapper.find(Card)).toHaveLength(0);
37
- expect(wrapper.find(Message)).toHaveLength(1);
38
- });
39
-
40
- it("contains a card for each source", () => {
41
- const props = { sources };
42
- const wrapper = shallowWithIntl(<SourceCards {...props} />);
43
- expect(wrapper.find(Card)).toHaveLength(5);
44
- });
45
- });