@truedat/dd 4.44.3 → 4.44.4
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 +10 -0
- package/package.json +6 -6
- package/src/api/mutations.js +27 -0
- package/src/api/queries.js +24 -0
- package/src/api.js +2 -0
- package/src/components/DictionaryRoutes.js +7 -5
- package/src/components/FilteredNav.js +9 -9
- package/src/components/GrantRequestApprovalPopup.js +0 -1
- package/src/components/ReferenceDataset.js +23 -0
- package/src/components/ReferenceDatasetActions.js +88 -0
- package/src/components/ReferenceDatasetBreadcrumbs.js +22 -0
- package/src/components/ReferenceDatasetCreate.js +36 -0
- package/src/components/ReferenceDatasetDetail.js +42 -0
- package/src/components/ReferenceDatasetForm.js +109 -0
- package/src/components/ReferenceDatasetHeader.js +32 -0
- package/src/components/ReferenceDatasetRoutes.js +56 -0
- package/src/components/ReferenceDatasetTable.js +42 -0
- package/src/components/ReferenceDatasets.js +61 -0
- package/src/components/ReferenceDatasetsTable.js +105 -0
- package/src/components/StructureTagsRoutes.js +0 -1
- package/src/components/StructureTypesCrumbs.js +0 -1
- package/src/components/StructureView.js +1 -3
- package/src/components/SystemForm.js +1 -1
- package/src/components/__tests__/ReferenceDataset.spec.js +64 -0
- package/src/components/__tests__/ReferenceDatasetActions.spec.js +17 -0
- package/src/components/__tests__/ReferenceDatasetBreadcrumbs.spec.js +12 -0
- package/src/components/__tests__/ReferenceDatasetCreate.spec.js +12 -0
- package/src/components/__tests__/ReferenceDatasetDetail.spec.js +37 -0
- package/src/components/__tests__/ReferenceDatasetForm.spec.js +51 -0
- package/src/components/__tests__/ReferenceDatasetHeader.spec.js +17 -0
- package/src/components/__tests__/ReferenceDatasetRoutes.spec.js +74 -0
- package/src/components/__tests__/ReferenceDatasetTable.spec.js +18 -0
- package/src/components/__tests__/ReferenceDatasets.spec.js +32 -0
- package/src/components/__tests__/ReferenceDatasetsTable.spec.js +22 -0
- package/src/components/__tests__/__snapshots__/DictionaryRoutes.spec.js.snap +4 -0
- package/src/components/__tests__/__snapshots__/ReferenceDataset.spec.js.snap +365 -0
- package/src/components/__tests__/__snapshots__/ReferenceDatasetActions.spec.js.snap +65 -0
- package/src/components/__tests__/__snapshots__/ReferenceDatasetBreadcrumbs.spec.js.snap +25 -0
- package/src/components/__tests__/__snapshots__/ReferenceDatasetCreate.spec.js.snap +98 -0
- package/src/components/__tests__/__snapshots__/ReferenceDatasetDetail.spec.js.snap +135 -0
- package/src/components/__tests__/__snapshots__/ReferenceDatasetForm.spec.js.snap +61 -0
- package/src/components/__tests__/__snapshots__/ReferenceDatasetHeader.spec.js.snap +95 -0
- package/src/components/__tests__/__snapshots__/ReferenceDatasetRoutes.spec.js.snap +414 -0
- package/src/components/__tests__/__snapshots__/ReferenceDatasetTable.spec.js.snap +75 -0
- package/src/components/__tests__/__snapshots__/ReferenceDatasets.spec.js.snap +128 -0
- package/src/components/__tests__/__snapshots__/ReferenceDatasetsTable.spec.js.snap +86 -0
- package/src/messages/en.js +18 -0
- package/src/messages/es.js +20 -0
- package/src/reducers/__tests__/ddMessage.spec.js +26 -5
- package/src/reducers/__tests__/graph.spec.js +1 -6
- package/src/reducers/__tests__/referenceDatasetSaving.spec.js +44 -0
- package/src/reducers/__tests__/structureRedirect.spec.js +37 -13
- package/src/reducers/ddMessage.js +26 -1
- package/src/reducers/index.js +2 -0
- package/src/reducers/referenceDatasetSaving.js +16 -0
- package/src/reducers/structureRedirect.js +36 -15
- package/src/reducers/structuresUploadEvents.js +0 -1
- package/src/routines.js +35 -74
- package/src/sagas/__tests__/createReferenceDataset.spec.js +90 -0
- package/src/sagas/__tests__/deleteReferenceDataset.spec.js +81 -0
- package/src/sagas/__tests__/updateReferenceDataset.spec.js +116 -0
- package/src/sagas/createReferenceDataset.js +34 -0
- package/src/sagas/deleteReferenceDataset.js +29 -0
- package/src/sagas/downloadReferenceDataset.js +44 -0
- package/src/sagas/index.js +31 -22
- package/src/sagas/updateReferenceDataset.js +35 -0
- package/src/selectors/getRelationSortingCriteria.js +3 -5
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truedat/dd",
|
|
3
|
-
"version": "4.44.
|
|
3
|
+
"version": "4.44.4",
|
|
4
4
|
"description": "Truedat Web Data Dictionary",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"jsnext:main": "src/index.js",
|
|
@@ -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.44.
|
|
37
|
+
"@truedat/test": "4.44.4",
|
|
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.44.
|
|
88
|
-
"@truedat/core": "4.44.
|
|
89
|
-
"@truedat/df": "4.44.
|
|
87
|
+
"@truedat/auth": "4.44.4",
|
|
88
|
+
"@truedat/core": "4.44.4",
|
|
89
|
+
"@truedat/df": "4.44.4",
|
|
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": "36fb183e1d22181e6a15b3bac2c01b39214eacdb"
|
|
111
111
|
}
|
package/src/api/mutations.js
CHANGED
|
@@ -1,6 +1,33 @@
|
|
|
1
1
|
import { gql } from "@apollo/client";
|
|
2
2
|
import { STRUCTURE_TAG_DETAIL } from "./fragments";
|
|
3
3
|
|
|
4
|
+
export const CREATE_REFERENCE_DATASET = gql`
|
|
5
|
+
mutation CreateReferenceDataset($dataset: CreateReferenceDatasetInput!) {
|
|
6
|
+
createReferenceDataset(dataset: $dataset) {
|
|
7
|
+
id
|
|
8
|
+
name
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
`;
|
|
12
|
+
|
|
13
|
+
export const UPDATE_REFERENCE_DATASET = gql`
|
|
14
|
+
mutation UpdateReferenceDataset($dataset: UpdateReferenceDatasetInput!) {
|
|
15
|
+
updateReferenceDataset(dataset: $dataset) {
|
|
16
|
+
id
|
|
17
|
+
name
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
`;
|
|
21
|
+
|
|
22
|
+
export const DELETE_REFERENCE_DATASET = gql`
|
|
23
|
+
mutation DeleteReferenceDataset($id: ID!) {
|
|
24
|
+
deleteReferenceDataset(id: $id) {
|
|
25
|
+
id
|
|
26
|
+
name
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
`;
|
|
30
|
+
|
|
4
31
|
export const CREATE_STRUCTURE_TAG = gql`
|
|
5
32
|
mutation CreateStructureTag($structureTag: StructureTagInput!) {
|
|
6
33
|
createStructureTag(structureTag: $structureTag) {
|
package/src/api/queries.js
CHANGED
|
@@ -18,3 +18,27 @@ export const STRUCTURE_TAGS_QUERY = gql`
|
|
|
18
18
|
}
|
|
19
19
|
${STRUCTURE_TAG_DETAIL}
|
|
20
20
|
`;
|
|
21
|
+
|
|
22
|
+
export const REFERENCE_DATASETS_QUERY = gql`
|
|
23
|
+
query ReferenceDatasets {
|
|
24
|
+
referenceDatasets {
|
|
25
|
+
id
|
|
26
|
+
name
|
|
27
|
+
headers
|
|
28
|
+
rowCount
|
|
29
|
+
updatedAt
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
export const REFERENCE_DATASET_QUERY = gql`
|
|
35
|
+
query ReferenceDataset($id: ID!) {
|
|
36
|
+
referenceDataset(id: $id) {
|
|
37
|
+
id
|
|
38
|
+
name
|
|
39
|
+
headers
|
|
40
|
+
rows
|
|
41
|
+
updatedAt
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
`;
|
package/src/api.js
CHANGED
|
@@ -7,6 +7,7 @@ const API_DATA_STRUCTURE_FILTERS_SEARCH = "/api/data_structure_filters/search";
|
|
|
7
7
|
const API_DATA_STRUCTURE_VERSION = "/api/data_structures/:id/versions/:version";
|
|
8
8
|
const API_GRANT_FILTERS_SEARCH = "/api/grant_filters/search";
|
|
9
9
|
const API_PROFILE_EXECUTION = "/api/profile_executions/:id";
|
|
10
|
+
const API_REFERENCE_DATA_DOWNLOAD = "/api/reference_data/:id/csv";
|
|
10
11
|
const API_GRANT_REQUEST = "/api/grant_requests/:id";
|
|
11
12
|
const API_GRANT_REQUEST_APPROVALS = "/api/grant_requests/:id/approvals";
|
|
12
13
|
const API_GRANT_REQUEST_GROUP = "/api/grant_request_groups";
|
|
@@ -71,6 +72,7 @@ export {
|
|
|
71
72
|
API_NODES,
|
|
72
73
|
API_PROFILE_GROUP,
|
|
73
74
|
API_PROFILE_GROUPS,
|
|
75
|
+
API_REFERENCE_DATA_DOWNLOAD,
|
|
74
76
|
API_SYSTEM,
|
|
75
77
|
API_SYSTEMS,
|
|
76
78
|
API_SYSTEM_STRUCTURES,
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
PENDING_STRUCTURE_NOTES,
|
|
6
6
|
PROFILE_EXECUTION,
|
|
7
7
|
PROFILE_GROUP,
|
|
8
|
+
REFERENCE_DATASETS,
|
|
8
9
|
STRUCTURE_TAGS,
|
|
9
10
|
STRUCTURE_TYPES,
|
|
10
11
|
STRUCTURES,
|
|
@@ -17,6 +18,7 @@ import ProfileExecutionBreadcrumbs from "./ProfileExecutionBreadcrumbs";
|
|
|
17
18
|
import ProfileExecutionLoader from "./ProfileExecutionLoader";
|
|
18
19
|
import ProfileGroupLoader from "./ProfileGroupLoader";
|
|
19
20
|
import ProfileGroup from "./ProfileGroup";
|
|
21
|
+
import ReferenceDatasetRoutes from "./ReferenceDatasetRoutes";
|
|
20
22
|
import StructureFiltersLoader from "./StructureFiltersLoader";
|
|
21
23
|
import StructuresLoader from "./StructuresLoader";
|
|
22
24
|
import StructuresRoutes from "./StructuresRoutes";
|
|
@@ -84,11 +86,7 @@ export const DictionaryRoutes = () => {
|
|
|
84
86
|
/>
|
|
85
87
|
<Route
|
|
86
88
|
path={STRUCTURES_UPLOAD_EVENTS}
|
|
87
|
-
render={() =>
|
|
88
|
-
<>
|
|
89
|
-
<StructuresUploadEvents />
|
|
90
|
-
</>
|
|
91
|
-
)}
|
|
89
|
+
render={() => <StructuresUploadEvents />}
|
|
92
90
|
/>
|
|
93
91
|
<Route
|
|
94
92
|
path={PENDING_STRUCTURE_NOTES}
|
|
@@ -100,6 +98,10 @@ export const DictionaryRoutes = () => {
|
|
|
100
98
|
</>
|
|
101
99
|
)}
|
|
102
100
|
/>
|
|
101
|
+
<Route
|
|
102
|
+
path={REFERENCE_DATASETS}
|
|
103
|
+
render={() => <ReferenceDatasetRoutes />}
|
|
104
|
+
/>
|
|
103
105
|
<Route
|
|
104
106
|
path={PROFILE_GROUP}
|
|
105
107
|
render={() => (
|
|
@@ -2,19 +2,19 @@ import _ from "lodash/fp";
|
|
|
2
2
|
import React, { useState } from "react";
|
|
3
3
|
import PropTypes from "prop-types";
|
|
4
4
|
import { connect } from "react-redux";
|
|
5
|
-
import {
|
|
5
|
+
import { lowerDeburrTrim } from "@truedat/core/services/sort";
|
|
6
6
|
import { getSortedStructureChildren, getStructureParent } from "../selectors";
|
|
7
7
|
import StructureNav from "./StructureNav";
|
|
8
8
|
import StructureSearch from "./StructureSearch";
|
|
9
9
|
|
|
10
10
|
export const FilteredNav = ({ childStructures, parentStructure }) => {
|
|
11
11
|
const [searchValue, setSearchValue] = useState("");
|
|
12
|
-
const onChange = searchValue => setSearchValue(searchValue);
|
|
12
|
+
const onChange = (searchValue) => setSearchValue(searchValue);
|
|
13
13
|
|
|
14
|
-
const filteredStructures = collection => {
|
|
15
|
-
const normalizedSearchValue =
|
|
16
|
-
return _.filter(structure =>
|
|
17
|
-
_.contains(normalizedSearchValue)(
|
|
14
|
+
const filteredStructures = (collection) => {
|
|
15
|
+
const normalizedSearchValue = lowerDeburrTrim(searchValue);
|
|
16
|
+
return _.filter((structure) =>
|
|
17
|
+
_.contains(normalizedSearchValue)(lowerDeburrTrim(structure.name))
|
|
18
18
|
)(collection);
|
|
19
19
|
};
|
|
20
20
|
|
|
@@ -31,12 +31,12 @@ export const FilteredNav = ({ childStructures, parentStructure }) => {
|
|
|
31
31
|
|
|
32
32
|
FilteredNav.propTypes = {
|
|
33
33
|
childStructures: PropTypes.array,
|
|
34
|
-
parentStructure: PropTypes.object
|
|
34
|
+
parentStructure: PropTypes.object,
|
|
35
35
|
};
|
|
36
36
|
|
|
37
|
-
const mapStateToProps = state => ({
|
|
37
|
+
const mapStateToProps = (state) => ({
|
|
38
38
|
parentStructure: getStructureParent(state),
|
|
39
|
-
childStructures: getSortedStructureChildren(state)
|
|
39
|
+
childStructures: getSortedStructureChildren(state),
|
|
40
40
|
});
|
|
41
41
|
|
|
42
42
|
export default connect(mapStateToProps)(FilteredNav);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { Divider, Segment } from "semantic-ui-react";
|
|
4
|
+
import ReferenceDatasetBreadcrumbs from "./ReferenceDatasetBreadcrumbs";
|
|
5
|
+
import ReferenceDatasetDetail from "./ReferenceDatasetDetail";
|
|
6
|
+
import ReferenceDatasetHeader from "./ReferenceDatasetHeader";
|
|
7
|
+
|
|
8
|
+
export const ReferenceDataset = ({ dataset }) => (
|
|
9
|
+
<>
|
|
10
|
+
<ReferenceDatasetBreadcrumbs text={dataset.name} />
|
|
11
|
+
<Segment>
|
|
12
|
+
<ReferenceDatasetHeader dataset={dataset} />
|
|
13
|
+
<Divider hidden />
|
|
14
|
+
<ReferenceDatasetDetail dataset={dataset} />
|
|
15
|
+
</Segment>
|
|
16
|
+
</>
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
ReferenceDataset.propTypes = {
|
|
20
|
+
dataset: PropTypes.object,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default ReferenceDataset;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { Link } from "react-router-dom";
|
|
4
|
+
import { connect } from "react-redux";
|
|
5
|
+
import { useIntl } from "react-intl";
|
|
6
|
+
import { Button } from "semantic-ui-react";
|
|
7
|
+
import { ConfirmModal, GroupActions } from "@truedat/core/components";
|
|
8
|
+
import { linkTo } from "@truedat/core/routes";
|
|
9
|
+
import { deleteReferenceDataset, downloadReferenceDataset } from "../routines";
|
|
10
|
+
|
|
11
|
+
export const ConfirmDeleteModal = ({ onConfirm, name, id }) => {
|
|
12
|
+
const { formatMessage } = useIntl();
|
|
13
|
+
return (
|
|
14
|
+
<ConfirmModal
|
|
15
|
+
icon="trash"
|
|
16
|
+
trigger={
|
|
17
|
+
<Button
|
|
18
|
+
icon="trash"
|
|
19
|
+
content={formatMessage({ id: "actions.delete" })}
|
|
20
|
+
/>
|
|
21
|
+
}
|
|
22
|
+
header={formatMessage({
|
|
23
|
+
id: "referenceDataset.actions.delete.confirmation.header",
|
|
24
|
+
})}
|
|
25
|
+
size="small"
|
|
26
|
+
content={formatMessage(
|
|
27
|
+
{ id: "referenceDataset.actions.delete.confirmation.content" },
|
|
28
|
+
{ name: <i>{name}</i> }
|
|
29
|
+
)}
|
|
30
|
+
onConfirm={() => onConfirm({ id })}
|
|
31
|
+
/>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
ConfirmDeleteModal.propTypes = {
|
|
36
|
+
onConfirm: PropTypes.func,
|
|
37
|
+
name: PropTypes.string,
|
|
38
|
+
id: PropTypes.string,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const ReferenceDatasetActions = ({
|
|
42
|
+
deleteReferenceDataset,
|
|
43
|
+
downloadReferenceDataset,
|
|
44
|
+
dataset,
|
|
45
|
+
}) => {
|
|
46
|
+
const { formatMessage } = useIntl();
|
|
47
|
+
const { id, name } = dataset || {};
|
|
48
|
+
const actions = [
|
|
49
|
+
{
|
|
50
|
+
key: "edit",
|
|
51
|
+
icon: "edit",
|
|
52
|
+
text: formatMessage({ id: "actions.edit" }),
|
|
53
|
+
value: "edit",
|
|
54
|
+
as: Link,
|
|
55
|
+
to: linkTo.REFERENCE_DATASET_EDIT({ id }),
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
key: "download",
|
|
59
|
+
icon: "download",
|
|
60
|
+
text: formatMessage({ id: "actions.download" }),
|
|
61
|
+
value: "download",
|
|
62
|
+
as: "a",
|
|
63
|
+
onClick: () => downloadReferenceDataset({ id, name }),
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
key: "delete",
|
|
67
|
+
icon: "trash",
|
|
68
|
+
value: "delete",
|
|
69
|
+
as: ConfirmDeleteModal,
|
|
70
|
+
onConfirm: deleteReferenceDataset,
|
|
71
|
+
name,
|
|
72
|
+
id,
|
|
73
|
+
},
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
return <GroupActions availableActions={actions} />;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
ReferenceDatasetActions.propTypes = {
|
|
80
|
+
deleteReferenceDataset: PropTypes.func,
|
|
81
|
+
downloadReferenceDataset: PropTypes.func,
|
|
82
|
+
dataset: PropTypes.object.isRequired,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export default connect(null, {
|
|
86
|
+
deleteReferenceDataset,
|
|
87
|
+
downloadReferenceDataset,
|
|
88
|
+
})(ReferenceDatasetActions);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { Breadcrumb } from "semantic-ui-react";
|
|
4
|
+
import { Link } from "react-router-dom";
|
|
5
|
+
import { FormattedMessage } from "react-intl";
|
|
6
|
+
import { REFERENCE_DATASETS } from "@truedat/core/routes";
|
|
7
|
+
|
|
8
|
+
export const ReferenceDatasetBreadcrumbs = ({ text }) => (
|
|
9
|
+
<Breadcrumb>
|
|
10
|
+
<Breadcrumb.Section as={Link} to={REFERENCE_DATASETS} active={false}>
|
|
11
|
+
<FormattedMessage id="sidemenu.referenceData" />
|
|
12
|
+
</Breadcrumb.Section>
|
|
13
|
+
<Breadcrumb.Divider icon="right angle" />
|
|
14
|
+
<Breadcrumb.Section active>{text}</Breadcrumb.Section>
|
|
15
|
+
</Breadcrumb>
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
ReferenceDatasetBreadcrumbs.propTypes = {
|
|
19
|
+
text: PropTypes.string,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default ReferenceDatasetBreadcrumbs;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { connect } from "react-redux";
|
|
4
|
+
import { Container, Header, Icon, Segment } from "semantic-ui-react";
|
|
5
|
+
import { FormattedMessage, useIntl } from "react-intl";
|
|
6
|
+
import { createReferenceDataset } from "../routines";
|
|
7
|
+
import ReferenceDatasetBreadcrumbs from "./ReferenceDatasetBreadcrumbs";
|
|
8
|
+
import ReferenceDatasetForm from "./ReferenceDatasetForm";
|
|
9
|
+
|
|
10
|
+
export const ReferenceDatasetCreate = ({ createReferenceDataset }) => {
|
|
11
|
+
const { formatMessage } = useIntl();
|
|
12
|
+
return (
|
|
13
|
+
<>
|
|
14
|
+
<ReferenceDatasetBreadcrumbs
|
|
15
|
+
text={formatMessage({ id: "referenceDatasets.actions.create" })}
|
|
16
|
+
/>
|
|
17
|
+
<Container as={Segment} text>
|
|
18
|
+
<Header as="h2">
|
|
19
|
+
<Icon name="list ol" />
|
|
20
|
+
<Header.Content>
|
|
21
|
+
<FormattedMessage id="referenceDatasets.actions.create" />
|
|
22
|
+
</Header.Content>
|
|
23
|
+
</Header>
|
|
24
|
+
<ReferenceDatasetForm onSubmit={createReferenceDataset} />
|
|
25
|
+
</Container>
|
|
26
|
+
</>
|
|
27
|
+
);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
ReferenceDatasetCreate.propTypes = {
|
|
31
|
+
createReferenceDataset: PropTypes.func.isRequired,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default connect(null, { createReferenceDataset })(
|
|
35
|
+
ReferenceDatasetCreate
|
|
36
|
+
);
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { connect } from "react-redux";
|
|
4
|
+
import { Switch, Route } from "react-router-dom";
|
|
5
|
+
import {
|
|
6
|
+
REFERENCE_DATASET_EDIT,
|
|
7
|
+
REFERENCE_DATASET,
|
|
8
|
+
} from "@truedat/core/routes";
|
|
9
|
+
import { updateReferenceDataset } from "../routines";
|
|
10
|
+
import ReferenceDatasetTable from "./ReferenceDatasetTable";
|
|
11
|
+
import ReferenceDatasetForm from "./ReferenceDatasetForm";
|
|
12
|
+
|
|
13
|
+
export const ReferenceDatasetDetail = ({ dataset, updateReferenceDataset }) => (
|
|
14
|
+
<Switch>
|
|
15
|
+
<Route
|
|
16
|
+
path={REFERENCE_DATASET_EDIT}
|
|
17
|
+
exact
|
|
18
|
+
render={() => (
|
|
19
|
+
<ReferenceDatasetForm
|
|
20
|
+
dataset={dataset}
|
|
21
|
+
onSubmit={(data) =>
|
|
22
|
+
updateReferenceDataset({ ...data, id: dataset.id })
|
|
23
|
+
}
|
|
24
|
+
/>
|
|
25
|
+
)}
|
|
26
|
+
/>
|
|
27
|
+
<Route
|
|
28
|
+
path={REFERENCE_DATASET}
|
|
29
|
+
exact
|
|
30
|
+
render={() => <ReferenceDatasetTable {...dataset} />}
|
|
31
|
+
/>
|
|
32
|
+
</Switch>
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
ReferenceDatasetDetail.propTypes = {
|
|
36
|
+
dataset: PropTypes.object.isRequired,
|
|
37
|
+
updateReferenceDataset: PropTypes.func,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export default connect(null, { updateReferenceDataset })(
|
|
41
|
+
ReferenceDatasetDetail
|
|
42
|
+
);
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import { useForm, Controller } from "react-hook-form";
|
|
5
|
+
import { connect } from "react-redux";
|
|
6
|
+
import { Button, Form } from "semantic-ui-react";
|
|
7
|
+
import { useIntl } from "react-intl";
|
|
8
|
+
import { HistoryBackButton } from "@truedat/core/components";
|
|
9
|
+
|
|
10
|
+
const MAX_SIZE_MB = 2;
|
|
11
|
+
const MAX_SIZE = MAX_SIZE_MB * 1024 * 1024; // 2MB
|
|
12
|
+
|
|
13
|
+
const datasetValidator = (formatMessage) => (value) =>
|
|
14
|
+
_.isNull(value)
|
|
15
|
+
? true
|
|
16
|
+
: value.size > MAX_SIZE
|
|
17
|
+
? formatMessage(
|
|
18
|
+
{ id: "widget.image.error.too_big" },
|
|
19
|
+
{ size_mb: MAX_SIZE_MB }
|
|
20
|
+
)
|
|
21
|
+
: true;
|
|
22
|
+
|
|
23
|
+
export const ReferenceDatasetForm = ({ saving, dataset = {}, onSubmit }) => {
|
|
24
|
+
const { formatMessage } = useIntl();
|
|
25
|
+
const { handleSubmit, control, formState } = useForm({
|
|
26
|
+
mode: "all",
|
|
27
|
+
defaultValues: { name: dataset?.name || "", file: null },
|
|
28
|
+
});
|
|
29
|
+
const { isDirty, isValid } = formState;
|
|
30
|
+
const disabled = saving || !isDirty || !isValid;
|
|
31
|
+
return (
|
|
32
|
+
<Form onSubmit={handleSubmit(onSubmit)}>
|
|
33
|
+
<Controller
|
|
34
|
+
control={control}
|
|
35
|
+
name="name"
|
|
36
|
+
rules={{
|
|
37
|
+
required: formatMessage(
|
|
38
|
+
{ id: "form.validation.required" },
|
|
39
|
+
{ prop: formatMessage({ id: "referenceDataset.name" }) }
|
|
40
|
+
),
|
|
41
|
+
}}
|
|
42
|
+
render={({
|
|
43
|
+
field: { onBlur, onChange, value },
|
|
44
|
+
fieldState: { error },
|
|
45
|
+
}) => (
|
|
46
|
+
<Form.Input
|
|
47
|
+
autoComplete="off"
|
|
48
|
+
error={!!error}
|
|
49
|
+
label={formatMessage({ id: "referenceDataset.name" })}
|
|
50
|
+
onBlur={onBlur}
|
|
51
|
+
onChange={(_e, { value }) => onChange(value)}
|
|
52
|
+
value={value || ""}
|
|
53
|
+
required
|
|
54
|
+
/>
|
|
55
|
+
)}
|
|
56
|
+
/>
|
|
57
|
+
<Controller
|
|
58
|
+
control={control}
|
|
59
|
+
name="file"
|
|
60
|
+
rules={{
|
|
61
|
+
validate: datasetValidator(formatMessage),
|
|
62
|
+
required: dataset?.id
|
|
63
|
+
? false
|
|
64
|
+
: formatMessage(
|
|
65
|
+
{ id: "form.validation.required" },
|
|
66
|
+
{ prop: formatMessage({ id: "referenceDataset.file" }) }
|
|
67
|
+
),
|
|
68
|
+
}}
|
|
69
|
+
render={({ field: { onBlur, onChange }, fieldState: { error } }) => (
|
|
70
|
+
<Form.Input
|
|
71
|
+
type="file"
|
|
72
|
+
error={error?.message}
|
|
73
|
+
label={formatMessage({ id: "referenceDataset.file" })}
|
|
74
|
+
onBlur={onBlur}
|
|
75
|
+
onChange={(e) => onChange(e.target.files[0])}
|
|
76
|
+
required={!dataset?.id}
|
|
77
|
+
input={{ accept: "text/*,.csv,.txt" }}
|
|
78
|
+
/>
|
|
79
|
+
)}
|
|
80
|
+
/>
|
|
81
|
+
<div className="actions">
|
|
82
|
+
<Button
|
|
83
|
+
floated="right"
|
|
84
|
+
type="submit"
|
|
85
|
+
primary
|
|
86
|
+
loading={saving}
|
|
87
|
+
disabled={disabled}
|
|
88
|
+
content={formatMessage({ id: "actions.save" })}
|
|
89
|
+
/>
|
|
90
|
+
<HistoryBackButton
|
|
91
|
+
content={formatMessage({ id: "actions.cancel" })}
|
|
92
|
+
disabled={saving}
|
|
93
|
+
/>
|
|
94
|
+
</div>
|
|
95
|
+
</Form>
|
|
96
|
+
);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
ReferenceDatasetForm.propTypes = {
|
|
100
|
+
onSubmit: PropTypes.func,
|
|
101
|
+
saving: PropTypes.bool,
|
|
102
|
+
dataset: PropTypes.object,
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export const mapStateToProps = ({ referenceDatasetSaving }) => ({
|
|
106
|
+
saving: !!referenceDatasetSaving,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
export default connect(mapStateToProps)(ReferenceDatasetForm);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import { FormattedMessage } from "react-intl";
|
|
5
|
+
import { Header, Icon, Grid } from "semantic-ui-react";
|
|
6
|
+
import ReferenceDatasetActions from "./ReferenceDatasetActions";
|
|
7
|
+
|
|
8
|
+
export const ReferenceDatasetHeader = ({ dataset }) =>
|
|
9
|
+
_.isEmpty(dataset) ? null : (
|
|
10
|
+
<Grid>
|
|
11
|
+
<Grid.Column width={8}>
|
|
12
|
+
<Header as="h2">
|
|
13
|
+
<Icon circular name="list ol" />
|
|
14
|
+
<Header.Content>
|
|
15
|
+
{dataset.name}
|
|
16
|
+
<Header.Subheader>
|
|
17
|
+
<FormattedMessage id="referenceDataset" />
|
|
18
|
+
</Header.Subheader>
|
|
19
|
+
</Header.Content>
|
|
20
|
+
</Header>
|
|
21
|
+
</Grid.Column>
|
|
22
|
+
<Grid.Column width={8} textAlign="right">
|
|
23
|
+
<ReferenceDatasetActions dataset={dataset} />
|
|
24
|
+
</Grid.Column>
|
|
25
|
+
</Grid>
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
ReferenceDatasetHeader.propTypes = {
|
|
29
|
+
dataset: PropTypes.object.isRequired,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export default ReferenceDatasetHeader;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { Route, Switch, useParams } from "react-router-dom";
|
|
4
|
+
import { useQuery } from "@apollo/client";
|
|
5
|
+
import { Unauthorized, Loading } from "@truedat/core/components";
|
|
6
|
+
import { useAuthorized } from "@truedat/core/hooks";
|
|
7
|
+
import {
|
|
8
|
+
REFERENCE_DATASETS,
|
|
9
|
+
REFERENCE_DATASET_NEW,
|
|
10
|
+
REFERENCE_DATASET,
|
|
11
|
+
} from "@truedat/core/routes";
|
|
12
|
+
import { REFERENCE_DATASET_QUERY } from "../api/queries";
|
|
13
|
+
import ReferenceDataset from "./ReferenceDataset";
|
|
14
|
+
import ReferenceDatasets from "./ReferenceDatasets";
|
|
15
|
+
import ReferenceDatasetCreate from "./ReferenceDatasetCreate";
|
|
16
|
+
|
|
17
|
+
export const DatasetLoader = () => {
|
|
18
|
+
const { id } = useParams();
|
|
19
|
+
const { loading, error, data } = useQuery(REFERENCE_DATASET_QUERY, {
|
|
20
|
+
variables: { id },
|
|
21
|
+
});
|
|
22
|
+
if (error) return null;
|
|
23
|
+
if (loading) return <Loading />;
|
|
24
|
+
const dataset = data?.referenceDataset;
|
|
25
|
+
return _.isEmpty(dataset) ? null : <ReferenceDataset dataset={dataset} />;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const AuthorizedReferenceDatasetRoutes = () => (
|
|
29
|
+
<Switch>
|
|
30
|
+
<Route
|
|
31
|
+
path={REFERENCE_DATASET_NEW}
|
|
32
|
+
exact
|
|
33
|
+
render={() => <ReferenceDatasetCreate />}
|
|
34
|
+
/>
|
|
35
|
+
<Route
|
|
36
|
+
path={REFERENCE_DATASETS}
|
|
37
|
+
exact
|
|
38
|
+
render={() => <ReferenceDatasets />}
|
|
39
|
+
/>
|
|
40
|
+
<Route path={REFERENCE_DATASET} render={() => <DatasetLoader />} />
|
|
41
|
+
</Switch>
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
export const ReferenceDatasetRoutes = () => {
|
|
45
|
+
const authorized = useAuthorized();
|
|
46
|
+
return (
|
|
47
|
+
<Route
|
|
48
|
+
path={REFERENCE_DATASETS}
|
|
49
|
+
render={() =>
|
|
50
|
+
authorized ? <AuthorizedReferenceDatasetRoutes /> : <Unauthorized />
|
|
51
|
+
}
|
|
52
|
+
/>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export default ReferenceDatasetRoutes;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import { Table } from "semantic-ui-react";
|
|
5
|
+
|
|
6
|
+
const truncateOpts = { length: 100 };
|
|
7
|
+
|
|
8
|
+
export const DataRow = ({ values }) => (
|
|
9
|
+
<Table.Row>
|
|
10
|
+
{values.map((value, key) => (
|
|
11
|
+
<Table.Cell key={key}>{_.truncate(truncateOpts)(value)}</Table.Cell>
|
|
12
|
+
))}
|
|
13
|
+
</Table.Row>
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
DataRow.propTypes = {
|
|
17
|
+
values: PropTypes.arrayOf(PropTypes.string),
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const ReferenceDatasetTable = ({ headers = [], rows = [] }) => (
|
|
21
|
+
<Table compact basic="very">
|
|
22
|
+
<Table.Header>
|
|
23
|
+
<Table.Row>
|
|
24
|
+
{headers.map((text, key) => (
|
|
25
|
+
<Table.HeaderCell key={key} content={text} />
|
|
26
|
+
))}
|
|
27
|
+
</Table.Row>
|
|
28
|
+
</Table.Header>
|
|
29
|
+
<Table.Body>
|
|
30
|
+
{rows.map((values, key) => (
|
|
31
|
+
<DataRow key={key} values={values} />
|
|
32
|
+
))}
|
|
33
|
+
</Table.Body>
|
|
34
|
+
</Table>
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
ReferenceDatasetTable.propTypes = {
|
|
38
|
+
headers: PropTypes.arrayOf(PropTypes.string).isRequired,
|
|
39
|
+
rows: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string)).isRequired,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export default ReferenceDatasetTable;
|