@truedat/dd 4.28.3 → 4.28.7

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 (72) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/package.json +6 -6
  3. package/src/api.js +8 -0
  4. package/src/components/DictionaryRoutes.js +27 -0
  5. package/src/components/EditDomainForm.js +1 -0
  6. package/src/components/GrantDateFilter.js +30 -0
  7. package/src/components/GrantFilters.js +28 -0
  8. package/src/components/GrantFiltersLoader.js +29 -0
  9. package/src/components/GrantSelectedFilters.js +63 -0
  10. package/src/components/Grants.js +54 -0
  11. package/src/components/GrantsLabelResults.js +32 -0
  12. package/src/components/GrantsLoader.js +47 -0
  13. package/src/components/GrantsPagination.js +14 -0
  14. package/src/components/GrantsSearch.js +51 -0
  15. package/src/components/GrantsTable.js +112 -0
  16. package/src/components/StructureGrantCart.js +16 -14
  17. package/src/components/StructureGrantCartCheckout.js +9 -9
  18. package/src/components/StructureSummary.js +5 -5
  19. package/src/components/StructureTabPane.js +3 -3
  20. package/src/components/StructureView.js +14 -6
  21. package/src/components/__tests__/GrantDateFilter.spec.js +11 -0
  22. package/src/components/__tests__/GrantsLabelResults.js +17 -0
  23. package/src/components/__tests__/GrantsLoader.spec.js +41 -0
  24. package/src/components/__tests__/GrantsTable.spec.js +185 -0
  25. package/src/components/__tests__/StructureGrantRequestButton.spec.js +20 -9
  26. package/src/components/__tests__/StructureSummary.spec.js +1 -1
  27. package/src/components/__tests__/__snapshots__/DictionaryRoutes.spec.js.snap +8 -0
  28. package/src/components/__tests__/__snapshots__/GrantDateFilter.spec.js.snap +16 -0
  29. package/src/components/__tests__/__snapshots__/GrantsLabelResults.js.snap +16 -0
  30. package/src/components/__tests__/__snapshots__/GrantsLoader.spec.js.snap +27 -0
  31. package/src/components/__tests__/__snapshots__/GrantsTable.spec.js.snap +231 -0
  32. package/src/components/index.js +4 -0
  33. package/src/messages/en.js +12 -2
  34. package/src/messages/es.js +12 -2
  35. package/src/reducers/__tests__/grantDateFilter.spec.js +54 -0
  36. package/src/reducers/__tests__/grantFilters.spec.js +37 -0
  37. package/src/reducers/__tests__/grantQuery.spec.js +113 -0
  38. package/src/reducers/__tests__/grants.spec.js +102 -0
  39. package/src/reducers/grantActiveFilters.js +48 -0
  40. package/src/reducers/grantCount.js +20 -0
  41. package/src/reducers/grantDateFilter.js +31 -0
  42. package/src/reducers/grantFilters.js +19 -0
  43. package/src/reducers/grantLoading.js +16 -0
  44. package/src/reducers/grantQuery.js +62 -0
  45. package/src/reducers/grantSelectedFilter.js +34 -0
  46. package/src/reducers/grants.js +24 -0
  47. package/src/reducers/grantsFilters.js +19 -0
  48. package/src/reducers/grantsPageSize.js +15 -0
  49. package/src/reducers/index.js +18 -0
  50. package/src/reducers/structureDateFilter.js +2 -2
  51. package/src/reducers/structureQuery.js +2 -2
  52. package/src/routines.js +20 -0
  53. package/src/sagas/__tests__/fetchGrantFilters.spec.js +97 -0
  54. package/src/sagas/__tests__/fetchGrants.spec.js +86 -0
  55. package/src/sagas/fetchGrantFilters.js +31 -0
  56. package/src/sagas/fetchGrants.js +26 -0
  57. package/src/sagas/index.js +6 -0
  58. package/src/selectors/__tests__/__snapshots__/getGrantsColumns.spec.js.snap +10 -0
  59. package/src/selectors/__tests__/getGrantAvailableFilters.spec.js +15 -0
  60. package/src/selectors/__tests__/getGrantSelectedFilterActiveValues.spec.js +16 -0
  61. package/src/selectors/__tests__/getGrantSelectedFilterValues.spec.js +15 -0
  62. package/src/selectors/__tests__/getGrantSelectedFilters.spec.js +15 -0
  63. package/src/selectors/__tests__/getGrantsColumns.spec.js +40 -0
  64. package/src/selectors/__tests__/getTabVisibility.spec.js +30 -30
  65. package/src/selectors/getGrantAvailableFilters.js +17 -0
  66. package/src/selectors/getGrantSelectedFilterActiveValues.js +8 -0
  67. package/src/selectors/getGrantSelectedFilterValues.js +13 -0
  68. package/src/selectors/getGrantSelectedFilters.js +7 -0
  69. package/src/selectors/getGrantsColumns.js +84 -8
  70. package/src/selectors/getStructureSelectedFilterValues.js +5 -3
  71. package/src/selectors/getTabVisibility.js +7 -7
  72. package/src/selectors/index.js +4 -0
@@ -0,0 +1,20 @@
1
+ import _ from "lodash/fp";
2
+ import { fetchGrants, clearGrants } from "../routines";
3
+
4
+ const initialState = 0;
5
+
6
+ const grantCount = (state = initialState, { type, payload }) => {
7
+ switch (type) {
8
+ case clearGrants.TRIGGER:
9
+ return initialState;
10
+ case fetchGrants.SUCCESS: {
11
+ const headers = _.propOr({}, "headers")(payload);
12
+ const count = _.propOr("0", "x-total-count")(headers);
13
+ return parseInt(count);
14
+ }
15
+ default:
16
+ return state;
17
+ }
18
+ };
19
+
20
+ export { grantCount };
@@ -0,0 +1,31 @@
1
+ import {
2
+ applyGrantDateFilter,
3
+ clearGrantFilters,
4
+ toggleGrantDateFilter,
5
+ } from "../routines";
6
+
7
+ export const initialState = {
8
+ active: false,
9
+ name: "start_date,end_date",
10
+ type: "range",
11
+ range: "",
12
+ unit: "d",
13
+ value: "1",
14
+ };
15
+
16
+ export const grantDateFilter = (state = initialState, { type, payload }) => {
17
+ switch (type) {
18
+ case clearGrantFilters.TRIGGER:
19
+ return initialState;
20
+ case toggleGrantDateFilter.TRIGGER: {
21
+ const { active } = state;
22
+ return { ...state, active: !active };
23
+ }
24
+ case applyGrantDateFilter.TRIGGER: {
25
+ const { active } = state;
26
+ return { ...payload, active };
27
+ }
28
+ default:
29
+ return state;
30
+ }
31
+ };
@@ -0,0 +1,19 @@
1
+ import _ from "lodash/fp";
2
+ import { clearGrantFilters, fetchGrantFilters } from "../routines";
3
+
4
+ const initialState = {};
5
+
6
+ const grantFilters = (state = initialState, { type, payload }) => {
7
+ switch (type) {
8
+ case clearGrantFilters.TRIGGER:
9
+ return initialState;
10
+ case fetchGrantFilters.REQUEST:
11
+ return initialState;
12
+ case fetchGrantFilters.SUCCESS:
13
+ return _.flow(_.propOr({}, "data.data"), _.omitBy(_.isEmpty))(payload);
14
+ default:
15
+ return state;
16
+ }
17
+ };
18
+
19
+ export { grantFilters };
@@ -0,0 +1,16 @@
1
+ import { fetchGrant } from "../routines";
2
+
3
+ const grantLoading = (state = false, { type }) => {
4
+ switch (type) {
5
+ case fetchGrant.REQUEST:
6
+ return true;
7
+ case fetchGrant.SUCCESS:
8
+ return false;
9
+ case fetchGrant.FAILURE:
10
+ return false;
11
+ default:
12
+ return state;
13
+ }
14
+ };
15
+
16
+ export { grantLoading };
@@ -0,0 +1,62 @@
1
+ import _ from "lodash/fp";
2
+ import {
3
+ clearGrantFilters,
4
+ removeGrantFilter,
5
+ searchGrants,
6
+ selectGrantPage,
7
+ sortGrants,
8
+ toggleGrantFilterValue,
9
+ clearGrantsSort,
10
+ } from "../routines";
11
+
12
+ const defaultPage = 1;
13
+ const defaultSize = 20;
14
+ const defaultSearchSort = [
15
+ { _score: "desc" },
16
+ { "data_structure_version.name.raw": "asc" },
17
+ ];
18
+ const byNameSort = [{ "data_structure_version.name.raw": "asc" }];
19
+
20
+ export const initialState = {
21
+ query: "",
22
+ page: defaultPage,
23
+ size: defaultSize,
24
+ sort: byNameSort,
25
+ };
26
+
27
+ const grantQuery = (state = initialState, { type, payload }) => {
28
+ switch (type) {
29
+ case clearGrantFilters.TRIGGER:
30
+ const page = defaultPage;
31
+ return { ...state, page, query: "" };
32
+ case removeGrantFilter.TRIGGER: {
33
+ const page = defaultPage;
34
+ return { ...state, page };
35
+ }
36
+ case toggleGrantFilterValue.TRIGGER: {
37
+ const page = defaultPage;
38
+ return { ...state, page };
39
+ }
40
+ case searchGrants.TRIGGER: {
41
+ const page = defaultPage;
42
+ const query = _.propOr("", "query")(payload);
43
+ const sort = query != "" ? defaultSearchSort : byNameSort;
44
+ return { ...state, query, page, sort };
45
+ }
46
+ case selectGrantPage.TRIGGER: {
47
+ const { activePage } = payload;
48
+ return { ...state, page: activePage };
49
+ }
50
+ case sortGrants.TRIGGER: {
51
+ const sort = payload;
52
+ return { ...state, sort, page: defaultPage };
53
+ }
54
+ case clearGrantsSort.TRIGGER: {
55
+ return { ...state, sort: byNameSort };
56
+ }
57
+ default:
58
+ return state;
59
+ }
60
+ };
61
+
62
+ export { grantQuery };
@@ -0,0 +1,34 @@
1
+ import {
2
+ addGrantFilter,
3
+ closeGrantFilter,
4
+ openGrantFilter,
5
+ removeGrantFilter,
6
+ resetGrantFilters,
7
+ } from "../routines";
8
+
9
+ /** @type {string} */
10
+ export const initialState = null;
11
+
12
+ export const grantSelectedFilter = (
13
+ state = initialState,
14
+ { type, payload }
15
+ ) => {
16
+ switch (type) {
17
+ case addGrantFilter.TRIGGER: {
18
+ const { filter } = payload;
19
+ return filter;
20
+ }
21
+ case closeGrantFilter.TRIGGER:
22
+ return initialState;
23
+ case openGrantFilter.TRIGGER: {
24
+ const { filter } = payload;
25
+ return filter;
26
+ }
27
+ case removeGrantFilter.TRIGGER:
28
+ return initialState;
29
+ case resetGrantFilters.TRIGGER:
30
+ return initialState;
31
+ default:
32
+ return state;
33
+ }
34
+ };
@@ -0,0 +1,24 @@
1
+ import _ from "lodash/fp";
2
+ import { clearGrants, fetchGrants, updateGrant } from "../routines";
3
+
4
+ export const initialState = [];
5
+
6
+ const pickFields = _.pick(["id", "user_id", "end_date"]);
7
+
8
+ const grants = (state = initialState, { type, payload }) => {
9
+ switch (type) {
10
+ case clearGrants.TRIGGER:
11
+ return initialState;
12
+ case fetchGrants.SUCCESS:
13
+ return _.pathOr({}, "data.data")(payload);
14
+ case updateGrant.SUCCESS:
15
+ const data = payload?.data;
16
+ return data?.id
17
+ ? _.map((o) => (o?.id == data.id ? pickFields(data) : o))(state)
18
+ : state;
19
+ default:
20
+ return state;
21
+ }
22
+ };
23
+
24
+ export { grants };
@@ -0,0 +1,19 @@
1
+ import _ from "lodash/fp";
2
+ import { clearGrantFilters, fetchGrantFilters } from "../routines";
3
+
4
+ const initialState = {};
5
+
6
+ const grantFilters = (state = initialState, { type, payload }) => {
7
+ switch (type) {
8
+ case clearGrantFilters.TRIGGER:
9
+ return initialState;
10
+ case fetchGrantFilters.REQUEST:
11
+ return initialState;
12
+ case fetchGrantFilters.SUCCESS:
13
+ return _.flow(_.propOr({}, "data.data"), _.omitBy(_.isEmpty))(payload);
14
+ default:
15
+ return state;
16
+ }
17
+ };
18
+
19
+ export { grantFilters };
@@ -0,0 +1,15 @@
1
+ import { fetchGrants } from "../routines";
2
+
3
+ const defaultPageSize = 20;
4
+
5
+ const grantsPageSize = (state = defaultPageSize, { type, payload }) => {
6
+ switch (type) {
7
+ case fetchGrants.TRIGGER:
8
+ const { size } = payload;
9
+ return size || state;
10
+ default:
11
+ return state;
12
+ }
13
+ };
14
+
15
+ export { grantsPageSize };
@@ -3,6 +3,15 @@ import { childrenRelations, parentRelations } from "./structureRelations";
3
3
  import { csvGraphDownloading } from "./csvGraphDownloading";
4
4
  import { ddMessage } from "./ddMessage";
5
5
  import { deletingStructureTags } from "./deletingStructureTags";
6
+ import { grantActiveFilters } from "./grantActiveFilters";
7
+ import { grantCount } from "./grantCount";
8
+ import { grantDateFilter } from "./grantDateFilter";
9
+ import { grantFilters } from "./grantFilters";
10
+ import { grantLoading } from "./grantLoading";
11
+ import { grantQuery } from "./grantQuery";
12
+ import { grants } from "./grants";
13
+ import { grantSelectedFilter } from "./grantSelectedFilter";
14
+ import { grantsPageSize } from "./grantsPageSize";
6
15
  import { graph } from "./graph";
7
16
  import { graphLoading } from "./graphLoading";
8
17
  import { graphRedirect } from "./graphRedirect";
@@ -80,6 +89,15 @@ export {
80
89
  csvGraphDownloading,
81
90
  ddMessage,
82
91
  deletingStructureTags,
92
+ grantActiveFilters,
93
+ grantCount,
94
+ grantDateFilter,
95
+ grantFilters,
96
+ grantLoading,
97
+ grantQuery,
98
+ grants,
99
+ grantSelectedFilter,
100
+ grantsPageSize,
83
101
  graph,
84
102
  graphLoading,
85
103
  graphRedirect,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  applyStructureDateFilter,
3
3
  clearStructureFilters,
4
- toggleStructureDateFilter
4
+ toggleStructureDateFilter,
5
5
  } from "../routines";
6
6
 
7
7
  export const initialState = {
@@ -9,7 +9,7 @@ export const initialState = {
9
9
  name: "updated_at",
10
10
  type: "since",
11
11
  unit: "d",
12
- value: "1"
12
+ value: "1",
13
13
  };
14
14
 
15
15
  export const structureDateFilter = (
@@ -7,7 +7,7 @@ import {
7
7
  selectStructurePage,
8
8
  sortStructures,
9
9
  toggleStructureFilterValue,
10
- clearStructuresSort
10
+ clearStructuresSort,
11
11
  } from "../routines";
12
12
 
13
13
  const defaultPage = 1;
@@ -19,7 +19,7 @@ export const initialState = {
19
19
  query: "",
20
20
  page: defaultPage,
21
21
  size: defaultSize,
22
- sort: byNameSort
22
+ sort: byNameSort,
23
23
  };
24
24
 
25
25
  const structureQuery = (state = initialState, { type, payload }) => {
package/src/routines.js CHANGED
@@ -1,9 +1,11 @@
1
1
  import { createRoutine } from "redux-saga-routines";
2
2
 
3
+ export const addGrantFilter = createRoutine("ADD_GRANT_FILTER");
3
4
  export const addStructureFilter = createRoutine("ADD_STRUCTURE_FILTER");
4
5
  export const addStructureSelectedFilter = createRoutine(
5
6
  "ADD_STRUCTURE_SELECTED_FILTER"
6
7
  );
8
+ export const applyGrantDateFilter = createRoutine("APPLY_GRANT_DATE_FILTER");
7
9
  export const applyStructureDateFilter = createRoutine(
8
10
  "APPLY_STRUCTURE_DATE_FILTER"
9
11
  );
@@ -11,6 +13,9 @@ export const applyStructureUserFilter = createRoutine(
11
13
  "APPLY_STRUCTURE_USER_FILTER"
12
14
  );
13
15
  export const bulkUpdateStructures = createRoutine("BULK_UPDATE_STRUCTURES");
16
+ export const clearGrantFilters = createRoutine("CLEAR_GRANT_FILTERS");
17
+ export const clearGrants = createRoutine("CLEAR_GRANTS");
18
+ export const clearGrantsSort = createRoutine("CLEAR_GRANTS_SORT");
14
19
  export const clearGraph = createRoutine("CLEAR_GRAPH");
15
20
  export const clearGroups = createRoutine("CLEAR_GROUPS");
16
21
  export const clearMetadataFields = createRoutine("CLEAR_METADATA_FIELDS");
@@ -34,6 +39,7 @@ export const clearStructuresSort = createRoutine("CLEAR_STRUCTURES_SORT");
34
39
  export const clearSystem = createRoutine("CLEAR_SYSTEM");
35
40
  export const clearSystemStructures = createRoutine("CLEAR_SYSTEM_STRUCTURES");
36
41
  export const clearSystems = createRoutine("CLEAR_SYSTEMS");
42
+ export const closeGrantFilter = createRoutine("CLOSE_GRANT_FILTER");
37
43
  export const closeStructureFilter = createRoutine("CLOSE_STRUCTURE_FILTER");
38
44
  export const createGraph = createRoutine("CREATE_GRAPH");
39
45
  export const createProfileGroup = createRoutine("CREATE_PROFILE_GROUP");
@@ -54,6 +60,9 @@ export const downloadCsvGraph = createRoutine("DOWNLOAD_CSV_GRAPH");
54
60
  export const downloadStructures = createRoutine("DOWNLOAD_STRUCTURES");
55
61
  export const excludeNode = createRoutine("EXCLUDE_NODE");
56
62
  export const fetchDomains = createRoutine("FETCH_DOMAINS"); // TODO: Is there a way to avoid repeating this routine here?
63
+ export const fetchGrant = createRoutine("FETCH_GRANT");
64
+ export const fetchGrantFilters = createRoutine("FETCH_GRANT_FILTERS");
65
+ export const fetchGrants = createRoutine("FETCH_GRANTS");
57
66
  export const fetchGraph = createRoutine("FETCH_GRAPH");
58
67
  export const fetchLinksStructureTags = createRoutine(
59
68
  "FETCH_LINKS_STRUCTURE_TAGS"
@@ -81,29 +90,40 @@ export const filterStructures = createRoutine("FILTER_STRUCTURES");
81
90
  export const hoverNode = createRoutine("HOVER_NODE");
82
91
  export const initSvg = createRoutine("INIT_SVG");
83
92
  export const linkStructureTag = createRoutine("LINK_STRUCTURE_TAG");
93
+ export const openGrantFilter = createRoutine("OPEN_GRANT_FILTER");
84
94
  export const openStructureFilter = createRoutine("OPEN_STRUCTURE_FILTER");
95
+ export const removeGrantFilter = createRoutine("REMOVE_GRANT_FILTER");
85
96
  export const removeStructureFilter = createRoutine("REMOVE_STRUCTURE_FILTER");
86
97
  export const removeStructureSelectedFilter = createRoutine(
87
98
  "REMOVE_STRUCTURE_SELECTED_FILTER"
88
99
  );
100
+ export const resetGrantFilters = createRoutine("RESET_GRANT_FILTERS");
89
101
  export const resetStructureFilters = createRoutine("RESET_STRUCTURE_FILTERS");
90
102
  export const saveStructureUserFilters = createRoutine(
91
103
  "SAVE_STRUCTURE_USER_FILTERS"
92
104
  );
105
+ export const searchGrants = createRoutine("SEARCH_GRANTS");
93
106
  export const searchStructures = createRoutine("SEARCH_STRUCTURES");
107
+ export const selectGrantPage = createRoutine("SELECT_GRANT_PAGE");
94
108
  export const selectGroup = createRoutine("SELECT_GROUP");
95
109
  export const selectNode = createRoutine("SELECT_NODE");
96
110
  export const selectPath = createRoutine("SELECT_PATH");
97
111
  export const selectResources = createRoutine("SELECT_RESOURCES");
98
112
  export const selectStructure = createRoutine("SELECT_STRUCTURE");
99
113
  export const selectStructurePage = createRoutine("SELECT_STRUCTURE_PAGE");
114
+ export const sortGrants = createRoutine("SORT_GRANTS");
100
115
  export const sortStructures = createRoutine("SORT_STRUCTURES");
116
+ export const toggleGrantDateFilter = createRoutine("TOGGLE_GRANT_DATE_FILTER");
117
+ export const toggleGrantFilterValue = createRoutine(
118
+ "TOGGLE_GRANT_FILTER_VALUE"
119
+ );
101
120
  export const toggleStructureDateFilter = createRoutine(
102
121
  "TOGGLE_STRUCTURE_DATE_FILTER"
103
122
  );
104
123
  export const toggleStructureFilterValue = createRoutine(
105
124
  "TOGGLE_STRUCTURE_FILTER_VALUE"
106
125
  );
126
+ export const updateGrant = createRoutine("UPDATE_GRANT");
107
127
  export const updateStructure = createRoutine("UPDATE_STRUCTURE");
108
128
  export const updateStructureTag = createRoutine("UPDATE_STRUCTURE_TAG");
109
129
  export const updateStructureType = createRoutine("UPDATE_STRUCTURE_TYPE");
@@ -0,0 +1,97 @@
1
+ import { debounce } from "redux-saga/effects";
2
+ import { testSaga } from "redux-saga-test-plan";
3
+ import { apiJsonPost, JSON_OPTS } from "@truedat/core/services/api";
4
+ import {
5
+ fetchGrantFiltersRequestSaga,
6
+ fetchGrantFiltersSaga,
7
+ } from "../fetchGrantFilters";
8
+ import { fetchGrantFilters } from "../../routines";
9
+ import {
10
+ API_GRANT_FILTERS_SEARCH,
11
+ API_MY_GRANT_FILTERS_SEARCH,
12
+ } from "../../api";
13
+
14
+ describe("sagas: fetchGrantFiltersRequestSaga", () => {
15
+ it("should invoke fetchGrantFiltersSaga on trigger", () => {
16
+ expect(() => {
17
+ testSaga(fetchGrantFiltersRequestSaga)
18
+ .next()
19
+ .takeLatest(fetchGrantFilters.TRIGGER, fetchGrantFiltersSaga)
20
+ .finish()
21
+ .isDone();
22
+ }).not.toThrow();
23
+ });
24
+
25
+ it("should throw exception if an unhandled action is received", () => {
26
+ expect(() => {
27
+ testSaga(fetchGrantFiltersRequestSaga)
28
+ .next()
29
+ .takeLatest("FOO", fetchGrantFiltersSaga);
30
+ }).toThrow();
31
+ });
32
+ });
33
+
34
+ describe("sagas: fetchGrantFiltersSaga", () => {
35
+ const grantFilters = { filters: ["filtro1", "filtro2"] };
36
+ const data = {
37
+ collection: [
38
+ { id: 1, user_id: 1, data_structure_id: 1, description: "desc1" },
39
+ { id: 2, user_id: 1, data_structure_id: 1, description: "desc2" },
40
+ ],
41
+ };
42
+ const headers = {
43
+ "x-total-count": "123",
44
+ };
45
+
46
+ it("should put a success action when a response is returned", () => {
47
+ expect(() => {
48
+ testSaga(fetchGrantFiltersSaga, { payload: { payload: grantFilters } })
49
+ .next()
50
+ .put(fetchGrantFilters.request())
51
+ .next()
52
+ .call(apiJsonPost, API_GRANT_FILTERS_SEARCH, grantFilters, JSON_OPTS)
53
+ .next({ data })
54
+ .put(fetchGrantFilters.success({ data }))
55
+ .next()
56
+ .put(fetchGrantFilters.fulfill())
57
+ .next()
58
+ .isDone();
59
+ }).not.toThrow();
60
+ });
61
+
62
+ it("should call API_MY_GRANTS_URL when onlyMyGrants is true", () => {
63
+ expect(() => {
64
+ testSaga(fetchGrantFiltersSaga, {
65
+ payload: { payload: grantFilters, onlyMyGrants: true },
66
+ })
67
+ .next()
68
+ .put(fetchGrantFilters.request())
69
+ .next()
70
+ .call(
71
+ apiJsonPost,
72
+ API_MY_GRANT_FILTERS_SEARCH,
73
+ grantFilters,
74
+ JSON_OPTS
75
+ );
76
+ }).not.toThrow();
77
+ });
78
+
79
+ it("should put a failure action when the call returns an error", () => {
80
+ const message = "Request failed";
81
+ const error = { message };
82
+
83
+ expect(() => {
84
+ testSaga(fetchGrantFiltersSaga, { payload: { payload: grantFilters } })
85
+ .next()
86
+ .put(fetchGrantFilters.request())
87
+ .next()
88
+ .call(apiJsonPost, API_GRANT_FILTERS_SEARCH, grantFilters, JSON_OPTS)
89
+ .throw(error)
90
+ .put(fetchGrantFilters.failure(message))
91
+ .next()
92
+ .put(fetchGrantFilters.fulfill())
93
+ .next()
94
+ .isDone();
95
+ }).not.toThrow();
96
+ });
97
+ });
@@ -0,0 +1,86 @@
1
+ import { debounce } from "redux-saga/effects";
2
+ import { testSaga } from "redux-saga-test-plan";
3
+ import { apiJsonPost, JSON_OPTS } from "@truedat/core/services/api";
4
+ import { fetchGrantsRequestSaga, fetchGrantsSaga } from "../fetchGrants";
5
+ import { fetchGrants } from "../../routines";
6
+ import { API_GRANTS_SEARCH, API_MY_GRANTS_SEARCH } from "../../api";
7
+
8
+ describe("sagas: fetchGrantsRequestSaga", () => {
9
+ it("should invoke fetchGrantsSaga on trigger", () => {
10
+ expect(() => {
11
+ testSaga(fetchGrantsRequestSaga)
12
+ .next()
13
+ .is(debounce(200, fetchGrants.TRIGGER, fetchGrantsSaga))
14
+ .finish()
15
+ .isDone();
16
+ }).not.toThrow();
17
+ });
18
+
19
+ it("should throw exception if an unhandled action is received", () => {
20
+ expect(() => {
21
+ testSaga(fetchGrantsRequestSaga)
22
+ .next()
23
+ .takeLatest("FOO", fetchGrantsSaga);
24
+ }).toThrow();
25
+ });
26
+ });
27
+
28
+ describe("sagas: fetchGrantsSaga", () => {
29
+ const grantQuery = {};
30
+ const data = {
31
+ collection: [
32
+ { id: 1, user_id: 1, data_structure_id: 1, description: "desc1" },
33
+ { id: 2, user_id: 1, data_structure_id: 1, description: "desc2" },
34
+ ],
35
+ };
36
+ const headers = {
37
+ "x-total-count": "123",
38
+ };
39
+
40
+ it("should put a success action when a response is returned", () => {
41
+ expect(() => {
42
+ testSaga(fetchGrantsSaga, { payload: { payload: grantQuery } })
43
+ .next()
44
+ .put(fetchGrants.request(grantQuery))
45
+ .next()
46
+ .call(apiJsonPost, API_GRANTS_SEARCH, grantQuery, JSON_OPTS)
47
+ .next({ data, headers })
48
+ .put(fetchGrants.success({ data, headers }))
49
+ .next()
50
+ .put(fetchGrants.fulfill())
51
+ .next()
52
+ .isDone();
53
+ }).not.toThrow();
54
+ });
55
+
56
+ it("should call API_MY_GRANTS_URL when onlyMyGrants is true", () => {
57
+ expect(() => {
58
+ testSaga(fetchGrantsSaga, {
59
+ payload: { payload: grantQuery, onlyMyGrants: true },
60
+ })
61
+ .next()
62
+ .put(fetchGrants.request(grantQuery))
63
+ .next()
64
+ .call(apiJsonPost, API_MY_GRANTS_SEARCH, grantQuery, JSON_OPTS);
65
+ }).not.toThrow();
66
+ });
67
+
68
+ it("should put a failure action when the call returns an error", () => {
69
+ const message = "Request failed";
70
+ const error = { message };
71
+
72
+ expect(() => {
73
+ testSaga(fetchGrantsSaga, { payload: { payload: grantQuery } })
74
+ .next()
75
+ .put(fetchGrants.request(grantQuery))
76
+ .next()
77
+ .call(apiJsonPost, API_GRANTS_SEARCH, grantQuery, JSON_OPTS)
78
+ .throw(error)
79
+ .put(fetchGrants.failure(message))
80
+ .next()
81
+ .put(fetchGrants.fulfill())
82
+ .next()
83
+ .isDone();
84
+ }).not.toThrow();
85
+ });
86
+ });
@@ -0,0 +1,31 @@
1
+ import _ from "lodash/fp";
2
+ import { call, put, takeLatest } from "redux-saga/effects";
3
+ import { apiJsonPost, JSON_OPTS } from "@truedat/core/services/api";
4
+ import { fetchGrantFilters } from "../routines";
5
+ import { API_GRANT_FILTERS_SEARCH, API_MY_GRANT_FILTERS_SEARCH } from "../api";
6
+
7
+ export function* fetchGrantFiltersSaga({ payload: { payload, onlyMyGrants } }) {
8
+ try {
9
+ yield put(fetchGrantFilters.request());
10
+ const url = onlyMyGrants
11
+ ? API_MY_GRANT_FILTERS_SEARCH
12
+ : API_GRANT_FILTERS_SEARCH;
13
+ const filters = _.propOr({}, "filters")(payload);
14
+ const body = { filters };
15
+ const { data } = yield call(apiJsonPost, url, body, JSON_OPTS);
16
+ yield put(fetchGrantFilters.success({ data }));
17
+ } catch (error) {
18
+ if (error.response) {
19
+ const { status, data } = error.response;
20
+ yield put(fetchGrantFilters.failure({ status, data }));
21
+ } else {
22
+ yield put(fetchGrantFilters.failure(error.message));
23
+ }
24
+ } finally {
25
+ yield put(fetchGrantFilters.fulfill());
26
+ }
27
+ }
28
+
29
+ export function* fetchGrantFiltersRequestSaga() {
30
+ yield takeLatest(fetchGrantFilters.TRIGGER, fetchGrantFiltersSaga);
31
+ }
@@ -0,0 +1,26 @@
1
+ import { call, put, debounce } from "redux-saga/effects";
2
+ import { apiJsonPost, JSON_OPTS } from "@truedat/core/services/api";
3
+ import { fetchGrants } from "../routines";
4
+ import { API_GRANTS_SEARCH, API_MY_GRANTS_SEARCH } from "../api";
5
+
6
+ export function* fetchGrantsSaga({ payload: { payload: body, onlyMyGrants } }) {
7
+ try {
8
+ const url = onlyMyGrants ? API_MY_GRANTS_SEARCH : API_GRANTS_SEARCH;
9
+ yield put(fetchGrants.request(body));
10
+ const { data, headers } = yield call(apiJsonPost, url, body, JSON_OPTS);
11
+ yield put(fetchGrants.success({ data, headers }));
12
+ } catch (error) {
13
+ if (error.response) {
14
+ const { status, data } = error.response;
15
+ yield put(fetchGrants.failure({ status, data }));
16
+ } else {
17
+ yield put(fetchGrants.failure(error.message));
18
+ }
19
+ } finally {
20
+ yield put(fetchGrants.fulfill());
21
+ }
22
+ }
23
+
24
+ export function* fetchGrantsRequestSaga() {
25
+ yield debounce(200, fetchGrants.TRIGGER, fetchGrantsSaga);
26
+ }
@@ -11,6 +11,8 @@ import { deleteStructureUserFilterRequestSaga } from "./deleteStructureUserFilte
11
11
  import { doStructureNoteActionRequestSaga } from "./doStructureNoteAction";
12
12
  import { downloadCsvGraphRequestSaga } from "./downloadCsvGraph";
13
13
  import { downloadStructuresRequestSaga } from "./downloadStructures";
14
+ import { fetchGrantFiltersRequestSaga } from "./fetchGrantFilters";
15
+ import { fetchGrantsRequestSaga } from "./fetchGrants";
14
16
  import { fetchGraphRequestSaga } from "./fetchGraph";
15
17
  import { fetchLinksStructureTagsRequestSaga } from "./fetchLinksStructureTags";
16
18
  import { fetchNodesRequestSaga } from "./fetchNodes";
@@ -53,6 +55,8 @@ export {
53
55
  doStructureNoteActionRequestSaga,
54
56
  downloadCsvGraphRequestSaga,
55
57
  downloadStructuresRequestSaga,
58
+ fetchGrantFiltersRequestSaga,
59
+ fetchGrantsRequestSaga,
56
60
  fetchGraphRequestSaga,
57
61
  fetchLinksStructureTagsRequestSaga,
58
62
  fetchNodesRequestSaga,
@@ -96,6 +100,8 @@ export default [
96
100
  doStructureNoteActionRequestSaga(),
97
101
  downloadCsvGraphRequestSaga(),
98
102
  downloadStructuresRequestSaga(),
103
+ fetchGrantFiltersRequestSaga(),
104
+ fetchGrantsRequestSaga(),
99
105
  fetchGraphRequestSaga(),
100
106
  fetchLinksStructureTagsRequestSaga(),
101
107
  fetchNodesRequestSaga(),