@truedat/dd 4.28.4 → 4.28.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/package.json +8 -8
- package/src/api.js +4 -0
- package/src/components/DictionaryRoutes.js +27 -0
- package/src/components/EditDomainForm.js +1 -0
- package/src/components/GrantFiltersLoader.js +9 -4
- package/src/components/Grants.js +9 -4
- package/src/components/GrantsLoader.js +9 -3
- package/src/components/GrantsTable.js +2 -2
- package/src/components/StructureFieldsDropdown.js +68 -49
- package/src/components/__tests__/ValueConditionStructure.spec.js +1 -1
- package/src/components/__tests__/__snapshots__/DictionaryRoutes.spec.js.snap +8 -0
- package/src/components/__tests__/__snapshots__/GrantsLoader.spec.js.snap +4 -1
- package/src/components/__tests__/__snapshots__/GrantsTable.spec.js.snap +1 -1
- package/src/components/index.js +0 -2
- package/src/messages/en.js +5 -3
- package/src/messages/es.js +6 -4
- package/src/reducers/grantActiveFilters.js +2 -0
- package/src/sagas/__tests__/fetchGrantFilters.spec.js +97 -0
- package/src/sagas/__tests__/fetchGrants.spec.js +15 -3
- package/src/sagas/fetchGrantFilters.js +6 -4
- package/src/sagas/fetchGrants.js +3 -3
- package/src/selectors/getGrantsColumns.js +6 -4
- package/src/components/GrantsRoutes.js +0 -33
- package/src/components/__tests__/GrantsRoutes.spec.js +0 -19
- package/src/components/__tests__/__snapshots__/GrantsRoutes.spec.js.snap +0 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [4.28.8] 2021-09-20
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- [TD-3970] `StructureFieldsDropdown` support for cast type and modifier
|
|
8
|
+
|
|
9
|
+
## [4.28.6] 2021-09-20
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- [TD-3950] My grants table
|
|
14
|
+
|
|
3
15
|
## [4.28.4] 2021-09-15
|
|
4
16
|
|
|
5
17
|
### Added
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truedat/dd",
|
|
3
|
-
"version": "4.28.
|
|
3
|
+
"version": "4.28.8",
|
|
4
4
|
"description": "Truedat Web Data Dictionary",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"jsnext:main": "src/index.js",
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
"scripts": {
|
|
17
17
|
"clean": "rimraf yarn-error.log",
|
|
18
18
|
"debug": "node --inspect-brk node_modules/.bin/jest --runInBand",
|
|
19
|
-
"test": "jest --coverage",
|
|
20
|
-
"test:watch": "jest --watch",
|
|
19
|
+
"test": "TZ=UTC jest --coverage",
|
|
20
|
+
"test:watch": "TZ=UTC jest --watch",
|
|
21
21
|
"eslint": "eslint src/**",
|
|
22
22
|
"eslint:fix": "eslint --fix src/**"
|
|
23
23
|
},
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"@testing-library/jest-dom": "^5.14.1",
|
|
35
35
|
"@testing-library/react": "^12.0.0",
|
|
36
36
|
"@testing-library/user-event": "^13.2.1",
|
|
37
|
-
"@truedat/test": "4.28.
|
|
37
|
+
"@truedat/test": "4.28.8",
|
|
38
38
|
"babel-jest": "^27.0.6",
|
|
39
39
|
"babel-plugin-dynamic-import-node": "^2.3.3",
|
|
40
40
|
"babel-plugin-lodash": "^3.3.4",
|
|
@@ -84,9 +84,9 @@
|
|
|
84
84
|
]
|
|
85
85
|
},
|
|
86
86
|
"dependencies": {
|
|
87
|
-
"@truedat/auth": "4.28.
|
|
88
|
-
"@truedat/core": "4.28.
|
|
89
|
-
"@truedat/df": "4.28.
|
|
87
|
+
"@truedat/auth": "4.28.8",
|
|
88
|
+
"@truedat/core": "4.28.8",
|
|
89
|
+
"@truedat/df": "4.28.8",
|
|
90
90
|
"lodash": "^4.17.21",
|
|
91
91
|
"path-to-regexp": "^1.7.0",
|
|
92
92
|
"prop-types": "^15.7.2",
|
|
@@ -107,5 +107,5 @@
|
|
|
107
107
|
"react-dom": ">= 16.8.6 < 17",
|
|
108
108
|
"semantic-ui-react": ">= 0.88.2 < 2.1"
|
|
109
109
|
},
|
|
110
|
-
"gitHead": "
|
|
110
|
+
"gitHead": "33a7f73dd4ffbd31d1df270c8453c3a876412990"
|
|
111
111
|
}
|
package/src/api.js
CHANGED
|
@@ -11,6 +11,8 @@ const API_GRANTS_SEARCH = "/api/grants/search";
|
|
|
11
11
|
const API_GRAPH = "/api/graphs/:id";
|
|
12
12
|
const API_GRAPHS = "/api/graphs";
|
|
13
13
|
const API_GRAPH_CSV = "/api/graphs/csv";
|
|
14
|
+
const API_MY_GRANT_FILTERS_SEARCH = "/api/grant_filters/search/mine";
|
|
15
|
+
const API_MY_GRANTS_SEARCH = "/api/grants/search/mine";
|
|
14
16
|
const API_NODE = "/api/nodes/:id";
|
|
15
17
|
const API_NODES = "/api/nodes";
|
|
16
18
|
const API_PROFILE_GROUP = "/api/profile_execution_groups/:id";
|
|
@@ -48,6 +50,8 @@ export {
|
|
|
48
50
|
API_GRAPH,
|
|
49
51
|
API_GRAPHS,
|
|
50
52
|
API_GRAPH_CSV,
|
|
53
|
+
API_MY_GRANTS_SEARCH,
|
|
54
|
+
API_MY_GRANT_FILTERS_SEARCH,
|
|
51
55
|
API_NODE,
|
|
52
56
|
API_NODES,
|
|
53
57
|
API_PROFILE_GROUP,
|
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
STRUCTURE_TYPES,
|
|
10
10
|
SYSTEMS,
|
|
11
11
|
GRANTS_REQUESTS_CHECKOUT,
|
|
12
|
+
GRANTS,
|
|
13
|
+
MY_GRANTS,
|
|
12
14
|
} from "@truedat/core/routes";
|
|
13
15
|
import ProfileExecution from "./ProfileExecution";
|
|
14
16
|
import ProfileExecutionBreadcrumbs from "./ProfileExecutionBreadcrumbs";
|
|
@@ -24,6 +26,9 @@ import StructureTypesRoutes from "./StructureTypesRoutes";
|
|
|
24
26
|
import SystemsRoutes from "./SystemsRoutes";
|
|
25
27
|
import SystemsLoader from "./SystemsLoader";
|
|
26
28
|
import StructureGrantCartCheckout from "./StructureGrantCartCheckout";
|
|
29
|
+
import GrantFiltersLoader from "./GrantFiltersLoader";
|
|
30
|
+
import GrantsLoader from "./GrantsLoader";
|
|
31
|
+
import Grants from "./Grants";
|
|
27
32
|
|
|
28
33
|
const TemplatesLoader = React.lazy(() =>
|
|
29
34
|
import("@truedat/df/templates/components/TemplatesLoader")
|
|
@@ -69,6 +74,28 @@ export const DictionaryRoutes = () => {
|
|
|
69
74
|
path={GRANTS_REQUESTS_CHECKOUT}
|
|
70
75
|
render={() => <StructureGrantCartCheckout />}
|
|
71
76
|
/>
|
|
77
|
+
<Route
|
|
78
|
+
path={GRANTS}
|
|
79
|
+
render={() => (
|
|
80
|
+
<>
|
|
81
|
+
<GrantsLoader />
|
|
82
|
+
<GrantFiltersLoader />
|
|
83
|
+
<Grants />
|
|
84
|
+
</>
|
|
85
|
+
)}
|
|
86
|
+
/>
|
|
87
|
+
<Route
|
|
88
|
+
path={MY_GRANTS}
|
|
89
|
+
render={() => {
|
|
90
|
+
return (
|
|
91
|
+
<>
|
|
92
|
+
<GrantsLoader onlyMyGrants />
|
|
93
|
+
<GrantFiltersLoader onlyMyGrants />
|
|
94
|
+
<Grants onlyMyGrants />
|
|
95
|
+
</>
|
|
96
|
+
);
|
|
97
|
+
}}
|
|
98
|
+
/>
|
|
72
99
|
<Route path={STRUCTURE_TAGS} render={() => <StructureTagsRoutes />} />
|
|
73
100
|
<Route path={STRUCTURE_TYPES} render={() => <StructureTypesRoutes />} />
|
|
74
101
|
<Route
|
|
@@ -27,6 +27,7 @@ export const EditDomainForm = ({ title, updateStructure, structure }) => {
|
|
|
27
27
|
<Container style={{ width: "400px" }}>
|
|
28
28
|
<Header as="h2" content={title} />
|
|
29
29
|
<DomainDropdownSelector
|
|
30
|
+
clearable={false}
|
|
30
31
|
onChange={handleDomainSelected}
|
|
31
32
|
name="domain"
|
|
32
33
|
value={domainId || structure?.domain_id}
|
|
@@ -4,13 +4,18 @@ import { FiltersLoader } from "@truedat/core/components";
|
|
|
4
4
|
import { makeActiveFiltersSelector } from "@truedat/core/selectors";
|
|
5
5
|
import { clearGrantFilters, fetchGrantFilters } from "../routines";
|
|
6
6
|
|
|
7
|
-
const mapDispatchToProps = (dispatch) =>
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
const mapDispatchToProps = (dispatch, props) => {
|
|
8
|
+
const { onlyMyGrants } = props;
|
|
9
|
+
const fetchMyGrantsFilters = (payload) => {
|
|
10
|
+
return fetchGrantFilters({ payload, onlyMyGrants });
|
|
11
|
+
};
|
|
12
|
+
return bindActionCreators(
|
|
13
|
+
{ clearFilters: clearGrantFilters, fetchFilters: fetchMyGrantsFilters },
|
|
10
14
|
dispatch
|
|
11
15
|
);
|
|
16
|
+
};
|
|
12
17
|
|
|
13
|
-
const makeMapStateToProps = () => {
|
|
18
|
+
const makeMapStateToProps = ({}) => {
|
|
14
19
|
const activeFiltersSelector = makeActiveFiltersSelector("grantActiveFilters");
|
|
15
20
|
const mapStateToProps = (state, props) => {
|
|
16
21
|
return {
|
package/src/components/Grants.js
CHANGED
|
@@ -13,14 +13,18 @@ import GrantsLabelResults from "./GrantsLabelResults";
|
|
|
13
13
|
import GrantSelectedFilters from "./GrantSelectedFilters";
|
|
14
14
|
import GrantsPagination from "./GrantsPagination";
|
|
15
15
|
|
|
16
|
-
export const Grants = ({ grantsLoading }) => (
|
|
16
|
+
export const Grants = ({ grantsLoading, onlyMyGrants }) => (
|
|
17
17
|
<Segment>
|
|
18
18
|
<Header as="h2">
|
|
19
19
|
<Icon circular name="cogs" />
|
|
20
20
|
<Header.Content>
|
|
21
|
-
<FormattedMessage
|
|
21
|
+
<FormattedMessage
|
|
22
|
+
id={onlyMyGrants ? "grants.mine.header" : "grants.header"}
|
|
23
|
+
/>
|
|
22
24
|
<Header.Subheader>
|
|
23
|
-
<FormattedMessage
|
|
25
|
+
<FormattedMessage
|
|
26
|
+
id={onlyMyGrants ? "grants.mine.subheader" : "grants.subheader"}
|
|
27
|
+
/>
|
|
24
28
|
</Header.Subheader>
|
|
25
29
|
</Header.Content>
|
|
26
30
|
</Header>
|
|
@@ -34,7 +38,7 @@ export const Grants = ({ grantsLoading }) => (
|
|
|
34
38
|
</Dimmer>
|
|
35
39
|
</Dimmer.Dimmable>
|
|
36
40
|
<GrantsLabelResults />
|
|
37
|
-
<GrantsTable />
|
|
41
|
+
<GrantsTable onlyMyGrants={onlyMyGrants} />
|
|
38
42
|
<GrantsPagination />
|
|
39
43
|
</Segment>
|
|
40
44
|
</Segment>
|
|
@@ -42,6 +46,7 @@ export const Grants = ({ grantsLoading }) => (
|
|
|
42
46
|
|
|
43
47
|
Grants.propTypes = {
|
|
44
48
|
grantsLoading: PropTypes.bool,
|
|
49
|
+
onlyMyGrants: PropTypes.bool,
|
|
45
50
|
};
|
|
46
51
|
|
|
47
52
|
const mapStateToProps = ({ grantsLoading }) => ({ grantsLoading });
|
|
@@ -4,15 +4,20 @@ import { connect } from "react-redux";
|
|
|
4
4
|
import { makeSearchQuerySelector } from "@truedat/core/selectors";
|
|
5
5
|
import { clearGrants, fetchGrants } from "../routines";
|
|
6
6
|
|
|
7
|
-
export const GrantsLoader = ({
|
|
7
|
+
export const GrantsLoader = ({
|
|
8
|
+
clearGrants,
|
|
9
|
+
fetchGrants,
|
|
10
|
+
payload,
|
|
11
|
+
onlyMyGrants = false,
|
|
12
|
+
}) => {
|
|
8
13
|
useEffect(() => {
|
|
9
14
|
return () => {
|
|
10
15
|
clearGrants();
|
|
11
16
|
};
|
|
12
17
|
}, [clearGrants]);
|
|
13
18
|
useEffect(() => {
|
|
14
|
-
fetchGrants(payload);
|
|
15
|
-
}, [payload, fetchGrants]);
|
|
19
|
+
fetchGrants({ payload, onlyMyGrants });
|
|
20
|
+
}, [payload, fetchGrants, onlyMyGrants]);
|
|
16
21
|
return null;
|
|
17
22
|
};
|
|
18
23
|
|
|
@@ -20,6 +25,7 @@ GrantsLoader.propTypes = {
|
|
|
20
25
|
clearGrants: PropTypes.func,
|
|
21
26
|
fetchGrants: PropTypes.func,
|
|
22
27
|
payload: PropTypes.object,
|
|
28
|
+
onlyMyGrants: PropTypes.bool,
|
|
23
29
|
};
|
|
24
30
|
|
|
25
31
|
const makeMapStateToProps = () => {
|
|
@@ -102,8 +102,8 @@ GrantsTable.propTypes = {
|
|
|
102
102
|
grantsSorting: PropTypes.array,
|
|
103
103
|
};
|
|
104
104
|
|
|
105
|
-
const mapStateToProps = (state) => ({
|
|
106
|
-
columns: getGrantsTableColumns(state),
|
|
105
|
+
const mapStateToProps = (state, { onlyMyGrants }) => ({
|
|
106
|
+
columns: getGrantsTableColumns({ ...state, onlyMyGrants }),
|
|
107
107
|
grants: state.grants,
|
|
108
108
|
grantsLoading: state.grantsLoading,
|
|
109
109
|
grantsSorting: _.path("grantQuery.sort")(state),
|
|
@@ -6,52 +6,6 @@ import { OptionGroup } from "@truedat/core/components";
|
|
|
6
6
|
import { useIntl } from "react-intl";
|
|
7
7
|
import { getStructuresFields } from "../selectors/getStructuresFields";
|
|
8
8
|
|
|
9
|
-
const withFilters = (structureFields, filters) =>
|
|
10
|
-
filters
|
|
11
|
-
? _.filter((f) =>
|
|
12
|
-
_.every.convert({ cap: false })((v, k) => v.includes(_.prop(k)(f)))(
|
|
13
|
-
filters
|
|
14
|
-
)
|
|
15
|
-
)(structureFields)
|
|
16
|
-
: structureFields;
|
|
17
|
-
|
|
18
|
-
const getOptions = (structureFields, formatMessage) =>
|
|
19
|
-
_.flow(
|
|
20
|
-
_.sortBy(_.flow(_.prop("name"), _.toLower)),
|
|
21
|
-
_.groupBy("label"),
|
|
22
|
-
_.reduce.convert({ cap: false })(
|
|
23
|
-
(acc, v, k) =>
|
|
24
|
-
_.isNil(k) || k === "undefined"
|
|
25
|
-
? [...acc, ...v]
|
|
26
|
-
: [...acc, { label: k, options: v }],
|
|
27
|
-
[]
|
|
28
|
-
),
|
|
29
|
-
_.map.convert({ cap: false })((field) =>
|
|
30
|
-
toFieldOption(field, formatMessage)
|
|
31
|
-
)
|
|
32
|
-
)(structureFields);
|
|
33
|
-
|
|
34
|
-
const toFieldOption = (field, formatMessage) =>
|
|
35
|
-
_.has("options")(field)
|
|
36
|
-
? {
|
|
37
|
-
icon: "table",
|
|
38
|
-
label: field.label,
|
|
39
|
-
options: _.map((field) => formatOption(field, formatMessage))(
|
|
40
|
-
field.options
|
|
41
|
-
),
|
|
42
|
-
}
|
|
43
|
-
: formatOption(field, formatMessage);
|
|
44
|
-
|
|
45
|
-
const formatOption = (field, formatMessage) => ({
|
|
46
|
-
key: field.data_structure_id,
|
|
47
|
-
text: field.name,
|
|
48
|
-
value: field.data_structure_id,
|
|
49
|
-
icon: formatMessage({
|
|
50
|
-
id: `field_type.icon.${field.field_type}`,
|
|
51
|
-
defaultMessage: "hashtag",
|
|
52
|
-
}),
|
|
53
|
-
});
|
|
54
|
-
|
|
55
9
|
export const StructureFieldsDropdown = ({
|
|
56
10
|
label,
|
|
57
11
|
inline,
|
|
@@ -59,13 +13,77 @@ export const StructureFieldsDropdown = ({
|
|
|
59
13
|
structureFields,
|
|
60
14
|
filters,
|
|
61
15
|
value,
|
|
16
|
+
typeCastModifiers,
|
|
62
17
|
}) => {
|
|
63
18
|
const { formatMessage } = useIntl();
|
|
64
|
-
const onClick = ({ value }) => {
|
|
19
|
+
const onClick = ({ value, modifier }) => {
|
|
65
20
|
const field = _.find(_.propEq("data_structure_id", value))(structureFields);
|
|
66
|
-
onSelectField(field);
|
|
21
|
+
onSelectField(field, modifier);
|
|
67
22
|
};
|
|
68
23
|
|
|
24
|
+
const formatOption = (field) => {
|
|
25
|
+
const modifier = _.find({sourceType: field.field_type})(typeCastModifiers)
|
|
26
|
+
if(modifier){
|
|
27
|
+
return({
|
|
28
|
+
key: field.data_structure_id,
|
|
29
|
+
text: `${field.name} (${formatMessage({
|
|
30
|
+
id: `filtersGrid.field.modifier.${modifier.name}`
|
|
31
|
+
})})`,
|
|
32
|
+
modifier,
|
|
33
|
+
value: field.data_structure_id,
|
|
34
|
+
icon: formatMessage({
|
|
35
|
+
id: `field_type.icon.${field.field_type}`,
|
|
36
|
+
defaultMessage: "hashtag",
|
|
37
|
+
}),
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return({
|
|
42
|
+
key: field.data_structure_id,
|
|
43
|
+
text: field.name,
|
|
44
|
+
value: field.data_structure_id,
|
|
45
|
+
icon: formatMessage({
|
|
46
|
+
id: `field_type.icon.${field.field_type}`,
|
|
47
|
+
defaultMessage: "hashtag",
|
|
48
|
+
}),
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
};
|
|
52
|
+
const toFieldOption = (field) =>
|
|
53
|
+
_.has("options")(field)
|
|
54
|
+
? {
|
|
55
|
+
icon: "table",
|
|
56
|
+
label: field.label,
|
|
57
|
+
options: _.map(formatOption)(field.options),
|
|
58
|
+
}
|
|
59
|
+
: formatOption(field);
|
|
60
|
+
|
|
61
|
+
const getOptions = _.flow(
|
|
62
|
+
_.sortBy(_.flow(_.prop("name"), _.toLower)),
|
|
63
|
+
_.groupBy("label"),
|
|
64
|
+
_.reduce.convert({ cap: false })(
|
|
65
|
+
(acc, v, k) =>
|
|
66
|
+
_.isNil(k) || k === "undefined"
|
|
67
|
+
? [...acc, ...v]
|
|
68
|
+
: [...acc, { label: k, options: v }],
|
|
69
|
+
[]
|
|
70
|
+
),
|
|
71
|
+
_.map(toFieldOption),
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
const castSourceTypes = _.flow(
|
|
75
|
+
_.map(({sourceType})=>sourceType),
|
|
76
|
+
_.uniq
|
|
77
|
+
)(typeCastModifiers)
|
|
78
|
+
const options = _.flow(
|
|
79
|
+
_.filter((f) =>
|
|
80
|
+
_.every.convert({ cap: false })((v, k) => v.includes(_.prop(k)(f)))(
|
|
81
|
+
filters
|
|
82
|
+
) || castSourceTypes.includes(f.field_type)
|
|
83
|
+
),
|
|
84
|
+
getOptions
|
|
85
|
+
)(structureFields);
|
|
86
|
+
|
|
69
87
|
return (
|
|
70
88
|
<OptionGroup
|
|
71
89
|
inline={inline}
|
|
@@ -75,7 +93,7 @@ export const StructureFieldsDropdown = ({
|
|
|
75
93
|
placeholder={formatMessage({
|
|
76
94
|
id: "structureFields.dropdown.placeholder",
|
|
77
95
|
})}
|
|
78
|
-
options={
|
|
96
|
+
options={options}
|
|
79
97
|
/>
|
|
80
98
|
);
|
|
81
99
|
};
|
|
@@ -87,6 +105,7 @@ StructureFieldsDropdown.propTypes = {
|
|
|
87
105
|
structureFields: PropTypes.array,
|
|
88
106
|
onSelectField: PropTypes.func,
|
|
89
107
|
filters: PropTypes.object,
|
|
108
|
+
typeCastModifiers: PropTypes.array,
|
|
90
109
|
};
|
|
91
110
|
|
|
92
111
|
const mapStateToProps = (state, props) => ({
|
|
@@ -17,6 +17,14 @@ exports[`<DictionaryRoutes /> matches the latest snapshot 1`] = `
|
|
|
17
17
|
path="/grants_requests/checkout"
|
|
18
18
|
render={[Function]}
|
|
19
19
|
/>
|
|
20
|
+
<Route
|
|
21
|
+
path="/grants"
|
|
22
|
+
render={[Function]}
|
|
23
|
+
/>
|
|
24
|
+
<Route
|
|
25
|
+
path="/my_grants"
|
|
26
|
+
render={[Function]}
|
|
27
|
+
/>
|
|
20
28
|
<Route
|
|
21
29
|
path="/structure_tags"
|
|
22
30
|
render={[Function]}
|
package/src/components/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import DictionaryRoutes from "./DictionaryRoutes";
|
|
2
2
|
import FilteredNav from "./FilteredNav";
|
|
3
3
|
import GrantSelectedFilters from "./GrantSelectedFilters";
|
|
4
|
-
import GrantsRoutes from "./GrantsRoutes";
|
|
5
4
|
import GrantsTable from "./GrantsTable";
|
|
6
5
|
import LineageDefs from "./LineageDefs";
|
|
7
6
|
import LineageDownloadButton from "./LineageDownloadButton";
|
|
@@ -57,7 +56,6 @@ import ValueConditionStructure from "./ValueConditionStructure";
|
|
|
57
56
|
export {
|
|
58
57
|
DictionaryRoutes,
|
|
59
58
|
FilteredNav,
|
|
60
|
-
GrantsRoutes,
|
|
61
59
|
GrantSelectedFilters,
|
|
62
60
|
GrantsTable,
|
|
63
61
|
LineageDefs,
|
package/src/messages/en.js
CHANGED
|
@@ -34,15 +34,17 @@ export default {
|
|
|
34
34
|
"grant.cell.end_date.null": "No expiration set",
|
|
35
35
|
"grant.cell.end_date.same_user": "It's you",
|
|
36
36
|
"grant.header.user": "Account",
|
|
37
|
-
"grant.header.
|
|
37
|
+
"grant.header.data_structure_version": "Structure",
|
|
38
38
|
"grant.header.end_date": "Expires",
|
|
39
39
|
"grant.header.start_date": "Access granted",
|
|
40
40
|
"grant.updated_at": "Last changed",
|
|
41
41
|
"grants.header": "Grants",
|
|
42
|
+
"grants.mine.header": "My grants",
|
|
43
|
+
"grants.mine.subheader": "Structures granted to me",
|
|
42
44
|
"grants.retrieved.results": "{count} grants found",
|
|
43
|
-
"grants.search.placeholder": "
|
|
45
|
+
"grants.search.placeholder": "Search grants...",
|
|
44
46
|
"grants.search.results.empty": "No grants found",
|
|
45
|
-
"grants.subheader": "
|
|
47
|
+
"grants.subheader": "Granted access to structures",
|
|
46
48
|
"filters.with_content.raw.true": "Extra Info",
|
|
47
49
|
"graph.actions.download.popup": "Select a graph",
|
|
48
50
|
"graph.actions.download.tooltip": "Download to csv",
|
package/src/messages/es.js
CHANGED
|
@@ -34,16 +34,18 @@ export default {
|
|
|
34
34
|
"grant.cell.direct_access": "Acceso Directo",
|
|
35
35
|
"grant.cell.end_date.null": "Sin fecha de expiración",
|
|
36
36
|
"grant.cell.end_date.same_user": "Eres tú",
|
|
37
|
-
"grant.header.
|
|
37
|
+
"grant.header.data_structure_version": "Estructura",
|
|
38
38
|
"grant.header.end_date": "Expira",
|
|
39
39
|
"grant.header.start_date": "Acceso desde",
|
|
40
40
|
"grant.header.user": "Cuenta",
|
|
41
41
|
"grant.updated_at": "Actualizada",
|
|
42
|
-
"grants.header": "
|
|
42
|
+
"grants.header": "Accesos",
|
|
43
|
+
"grants.mine.header": "Mis accesos",
|
|
44
|
+
"grants.mine.subheader": "Estructuras a las que tengo acceso",
|
|
43
45
|
"grants.retrieved.results": "{count} grants encontrados",
|
|
44
|
-
"grants.search.placeholder": "
|
|
46
|
+
"grants.search.placeholder": "Buscar accesos...",
|
|
45
47
|
"grants.search.results.empty": "Ningún grant encontrado",
|
|
46
|
-
"grants.subheader": "
|
|
48
|
+
"grants.subheader": "Accesos a estructuras",
|
|
47
49
|
"filters.with_content.raw.true": "Contiene información extra",
|
|
48
50
|
"graph.actions.download.popup": "Seleccione un grafo",
|
|
49
51
|
"graph.actions.download.tooltip": "Descargar en csv",
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
removeGrantFilter,
|
|
6
6
|
resetGrantFilters,
|
|
7
7
|
toggleGrantFilterValue,
|
|
8
|
+
clearGrantFilters,
|
|
8
9
|
} from "../routines";
|
|
9
10
|
|
|
10
11
|
export const initialState = {};
|
|
@@ -26,6 +27,7 @@ export const grantActiveFilters = (state = initialState, { type, payload }) => {
|
|
|
26
27
|
const { filter } = payload;
|
|
27
28
|
return _.omit(filter)(state);
|
|
28
29
|
}
|
|
30
|
+
case clearGrantFilters.TRIGGER:
|
|
29
31
|
case resetGrantFilters.TRIGGER: {
|
|
30
32
|
return initialState;
|
|
31
33
|
}
|
|
@@ -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
|
+
});
|
|
@@ -3,7 +3,7 @@ import { testSaga } from "redux-saga-test-plan";
|
|
|
3
3
|
import { apiJsonPost, JSON_OPTS } from "@truedat/core/services/api";
|
|
4
4
|
import { fetchGrantsRequestSaga, fetchGrantsSaga } from "../fetchGrants";
|
|
5
5
|
import { fetchGrants } from "../../routines";
|
|
6
|
-
import { API_GRANTS_SEARCH } from "../../api";
|
|
6
|
+
import { API_GRANTS_SEARCH, API_MY_GRANTS_SEARCH } from "../../api";
|
|
7
7
|
|
|
8
8
|
describe("sagas: fetchGrantsRequestSaga", () => {
|
|
9
9
|
it("should invoke fetchGrantsSaga on trigger", () => {
|
|
@@ -39,7 +39,7 @@ describe("sagas: fetchGrantsSaga", () => {
|
|
|
39
39
|
|
|
40
40
|
it("should put a success action when a response is returned", () => {
|
|
41
41
|
expect(() => {
|
|
42
|
-
testSaga(fetchGrantsSaga, { payload: grantQuery })
|
|
42
|
+
testSaga(fetchGrantsSaga, { payload: { payload: grantQuery } })
|
|
43
43
|
.next()
|
|
44
44
|
.put(fetchGrants.request(grantQuery))
|
|
45
45
|
.next()
|
|
@@ -53,12 +53,24 @@ describe("sagas: fetchGrantsSaga", () => {
|
|
|
53
53
|
}).not.toThrow();
|
|
54
54
|
});
|
|
55
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
|
+
|
|
56
68
|
it("should put a failure action when the call returns an error", () => {
|
|
57
69
|
const message = "Request failed";
|
|
58
70
|
const error = { message };
|
|
59
71
|
|
|
60
72
|
expect(() => {
|
|
61
|
-
testSaga(fetchGrantsSaga, { payload: grantQuery })
|
|
73
|
+
testSaga(fetchGrantsSaga, { payload: { payload: grantQuery } })
|
|
62
74
|
.next()
|
|
63
75
|
.put(fetchGrants.request(grantQuery))
|
|
64
76
|
.next()
|
|
@@ -2,13 +2,15 @@ import _ from "lodash/fp";
|
|
|
2
2
|
import { call, put, takeLatest } from "redux-saga/effects";
|
|
3
3
|
import { apiJsonPost, JSON_OPTS } from "@truedat/core/services/api";
|
|
4
4
|
import { fetchGrantFilters } from "../routines";
|
|
5
|
-
import { API_GRANT_FILTERS_SEARCH } from "../api";
|
|
5
|
+
import { API_GRANT_FILTERS_SEARCH, API_MY_GRANT_FILTERS_SEARCH } from "../api";
|
|
6
6
|
|
|
7
|
-
export function* fetchGrantFiltersSaga(payload) {
|
|
7
|
+
export function* fetchGrantFiltersSaga({ payload: { payload, onlyMyGrants } }) {
|
|
8
8
|
try {
|
|
9
9
|
yield put(fetchGrantFilters.request());
|
|
10
|
-
const url =
|
|
11
|
-
|
|
10
|
+
const url = onlyMyGrants
|
|
11
|
+
? API_MY_GRANT_FILTERS_SEARCH
|
|
12
|
+
: API_GRANT_FILTERS_SEARCH;
|
|
13
|
+
const filters = _.propOr({}, "filters")(payload);
|
|
12
14
|
const body = { filters };
|
|
13
15
|
const { data } = yield call(apiJsonPost, url, body, JSON_OPTS);
|
|
14
16
|
yield put(fetchGrantFilters.success({ data }));
|
package/src/sagas/fetchGrants.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { call, put, debounce } from "redux-saga/effects";
|
|
2
2
|
import { apiJsonPost, JSON_OPTS } from "@truedat/core/services/api";
|
|
3
3
|
import { fetchGrants } from "../routines";
|
|
4
|
-
import { API_GRANTS_SEARCH } from "../api";
|
|
4
|
+
import { API_GRANTS_SEARCH, API_MY_GRANTS_SEARCH } from "../api";
|
|
5
5
|
|
|
6
|
-
export function* fetchGrantsSaga({ payload: body }) {
|
|
6
|
+
export function* fetchGrantsSaga({ payload: { payload: body, onlyMyGrants } }) {
|
|
7
7
|
try {
|
|
8
|
-
const url = API_GRANTS_SEARCH;
|
|
8
|
+
const url = onlyMyGrants ? API_MY_GRANTS_SEARCH : API_GRANTS_SEARCH;
|
|
9
9
|
yield put(fetchGrants.request(body));
|
|
10
10
|
const { data, headers } = yield call(apiJsonPost, url, body, JSON_OPTS);
|
|
11
11
|
yield put(fetchGrants.success({ data, headers }));
|
|
@@ -226,14 +226,16 @@ export const defaultGrantsTableColumns = [
|
|
|
226
226
|
];
|
|
227
227
|
|
|
228
228
|
export const getGrantsTableColumns = createSelector(
|
|
229
|
-
[_.prop("grantsColumns"), _.prop("authentication")],
|
|
230
|
-
(grantsColumns, authentication) =>
|
|
231
|
-
_.flow(
|
|
229
|
+
[_.prop("grantsColumns"), _.prop("authentication"), _.prop("onlyMyGrants")],
|
|
230
|
+
(grantsColumns, authentication, onlyMyGrants) => {
|
|
231
|
+
return _.flow(
|
|
232
232
|
_.defaultTo(defaultGrantsTableColumns),
|
|
233
|
+
_.reject((c) => (onlyMyGrants ? c.name === "user" : false)),
|
|
233
234
|
_.map((c) => {
|
|
234
235
|
return c.name === "user"
|
|
235
236
|
? { ...c, fieldDecorator: c.fieldDecorator(authentication) }
|
|
236
237
|
: c;
|
|
237
238
|
})
|
|
238
|
-
)(grantsColumns)
|
|
239
|
+
)(grantsColumns);
|
|
240
|
+
}
|
|
239
241
|
);
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { Route } from "react-router-dom";
|
|
3
|
-
import { Unauthorized } from "@truedat/core/components";
|
|
4
|
-
import { useAuthorized } from "@truedat/core/hooks";
|
|
5
|
-
import { GRANTS } from "@truedat/core/routes";
|
|
6
|
-
import GrantsTable from "./GrantsTable";
|
|
7
|
-
import GrantFiltersLoader from "./GrantFiltersLoader";
|
|
8
|
-
import GrantsLoader from "./GrantsLoader";
|
|
9
|
-
import StructureGrants from "./StructureGrants";
|
|
10
|
-
import GrantFilters from "./GrantFilters";
|
|
11
|
-
import Grants from "./Grants";
|
|
12
|
-
|
|
13
|
-
export const GrantsRoutes = () => {
|
|
14
|
-
const authorized = true; //useAuthorized("grants");
|
|
15
|
-
return (
|
|
16
|
-
<Route
|
|
17
|
-
path={GRANTS}
|
|
18
|
-
render={() =>
|
|
19
|
-
authorized ? (
|
|
20
|
-
<>
|
|
21
|
-
<GrantsLoader />
|
|
22
|
-
<GrantFiltersLoader />
|
|
23
|
-
<Grants />
|
|
24
|
-
</>
|
|
25
|
-
) : (
|
|
26
|
-
<Unauthorized />
|
|
27
|
-
)
|
|
28
|
-
}
|
|
29
|
-
/>
|
|
30
|
-
);
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export default GrantsRoutes;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { shallow } from "enzyme";
|
|
3
|
-
import { intl } from "@truedat/test/intl-stub";
|
|
4
|
-
import { GrantsRoutes } from "../GrantsRoutes";
|
|
5
|
-
|
|
6
|
-
// workaround for enzyme issue with React.useContext
|
|
7
|
-
// see https://github.com/airbnb/enzyme/issues/2176#issuecomment-532361526
|
|
8
|
-
jest.spyOn(React, "useContext").mockImplementation(() => intl);
|
|
9
|
-
|
|
10
|
-
jest.mock("@truedat/core/hooks", () => ({
|
|
11
|
-
useAuthorized: jest.fn(() => true),
|
|
12
|
-
}));
|
|
13
|
-
|
|
14
|
-
describe("<GrantsRoutes />", () => {
|
|
15
|
-
it("matches the latest snapshot", () => {
|
|
16
|
-
const wrapper = shallow(<GrantsRoutes />);
|
|
17
|
-
expect(wrapper).toMatchSnapshot();
|
|
18
|
-
});
|
|
19
|
-
});
|