@truedat/dd 4.43.2 → 4.43.5
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 +7 -7
- package/src/api.js +3 -0
- package/src/components/DictionaryRoutes.js +10 -0
- package/src/components/GrantRequestApprovalForm.js +10 -4
- package/src/components/LinkStructureTagForm.js +21 -15
- package/src/components/MetadataFiltersInput.js +1 -1
- package/src/components/MetadataViewForm.js +2 -2
- package/src/components/MyGrantRequests.js +1 -1
- package/src/components/PendingStructureNotes.js +3 -3
- package/src/components/StructureTagForm.js +5 -2
- package/src/components/StructureTypeForm.js +2 -2
- package/src/components/StructuresUploadEvents.js +38 -0
- package/src/components/StructuresUploadEventsTable.js +183 -0
- package/src/components/__tests__/StructuresUploadEventsTable.spec.js +84 -0
- package/src/components/__tests__/__snapshots__/DictionaryRoutes.spec.js.snap +4 -0
- package/src/components/__tests__/__snapshots__/StructuresUploadEventsTable.spec.js.snap +130 -0
- package/src/messages/en.js +17 -0
- package/src/messages/es.js +18 -0
- package/src/reducers/__tests__/structuresUploadEvents.spec.js +46 -0
- package/src/reducers/__tests__/structuresUploadEventsLoading.spec.js +26 -0
- package/src/reducers/ddMessage.js +54 -30
- package/src/reducers/index.js +4 -0
- package/src/reducers/structuresUploadEvents.js +16 -0
- package/src/reducers/structuresUploadEventsLoading.js +16 -0
- package/src/routines.js +1 -0
- package/src/sagas/__tests__/fetchStructuresUploadEvents.spec.js +79 -0
- package/src/sagas/__tests__/uploadStructures.spec.js +3 -2
- package/src/sagas/fetchStructuresUploadEvents.js +29 -0
- package/src/sagas/index.js +3 -0
- package/src/sagas/uploadStructures.js +2 -2
- package/src/selectors/__tests__/getStructuresUploadEventColumns.spec.js +20 -0
- package/src/selectors/getStructuresUploadEventColumns.js +74 -0
- package/src/selectors/index.js +4 -0
- package/src/styles/structuresUploadEventColumns.less +24 -0
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truedat/dd",
|
|
3
|
-
"version": "4.43.
|
|
3
|
+
"version": "4.43.5",
|
|
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.43.
|
|
37
|
+
"@truedat/test": "4.43.5",
|
|
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,13 +84,13 @@
|
|
|
84
84
|
]
|
|
85
85
|
},
|
|
86
86
|
"dependencies": {
|
|
87
|
-
"@truedat/auth": "4.43.
|
|
88
|
-
"@truedat/core": "4.43.
|
|
89
|
-
"@truedat/df": "4.43.
|
|
87
|
+
"@truedat/auth": "4.43.5",
|
|
88
|
+
"@truedat/core": "4.43.5",
|
|
89
|
+
"@truedat/df": "4.43.5",
|
|
90
90
|
"lodash": "^4.17.21",
|
|
91
91
|
"path-to-regexp": "^1.7.0",
|
|
92
92
|
"prop-types": "^15.7.2",
|
|
93
|
-
"react-hook-form": "^
|
|
93
|
+
"react-hook-form": "^7.30.0",
|
|
94
94
|
"react-intl": "^5.20.10",
|
|
95
95
|
"react-moment": "^0.9.7",
|
|
96
96
|
"react-redux": "^7.2.4",
|
|
@@ -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": "ab63882af7d0c31643f56b9c7eafca813763dd9e"
|
|
111
111
|
}
|
package/src/api.js
CHANGED
|
@@ -40,6 +40,8 @@ const API_USER_SEARCH_FILTER = "/api/user_search_filters/:id";
|
|
|
40
40
|
const API_GET_USER_SEARCH_FILTERS = "/api/user_search_filters/me";
|
|
41
41
|
const API_STRUCTURES_UPLOAD =
|
|
42
42
|
"/api/data_structures/bulk_update_template_content";
|
|
43
|
+
const API_STRUCTURES_UPLOAD_EVENTS =
|
|
44
|
+
"/api/data_structures/bulk_update_template_content_events";
|
|
43
45
|
const API_STRUCTURE_NOTE = "/api/data_structures/:data_structure_id/notes/:id";
|
|
44
46
|
const API_STRUCTURE_NOTES = "/api/data_structures/:data_structure_id/notes";
|
|
45
47
|
const API_UNIT_DOMAINS = "/api/unit_domains";
|
|
@@ -85,6 +87,7 @@ export {
|
|
|
85
87
|
API_STRUCTURES_TAG,
|
|
86
88
|
API_STRUCTURES_TAGS,
|
|
87
89
|
API_STRUCTURES_UPLOAD,
|
|
90
|
+
API_STRUCTURES_UPLOAD_EVENTS,
|
|
88
91
|
API_STRUCTURE_NOTE,
|
|
89
92
|
API_STRUCTURE_NOTES,
|
|
90
93
|
API_UNIT_DOMAINS,
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
STRUCTURE_TAGS,
|
|
9
9
|
STRUCTURE_TYPES,
|
|
10
10
|
STRUCTURES,
|
|
11
|
+
STRUCTURES_UPLOAD_EVENTS,
|
|
11
12
|
SYSTEMS,
|
|
12
13
|
} from "@truedat/core/routes";
|
|
13
14
|
import PendingStructureNotes from "./PendingStructureNotes";
|
|
@@ -19,6 +20,7 @@ import ProfileGroup from "./ProfileGroup";
|
|
|
19
20
|
import StructureFiltersLoader from "./StructureFiltersLoader";
|
|
20
21
|
import StructuresLoader from "./StructuresLoader";
|
|
21
22
|
import StructuresRoutes from "./StructuresRoutes";
|
|
23
|
+
import StructuresUploadEvents from "./StructuresUploadEvents";
|
|
22
24
|
import StructureTypesLoader from "./StructureTypesLoader";
|
|
23
25
|
import StructureTagsRoutes from "./StructureTagsRoutes";
|
|
24
26
|
import StructureTypesRoutes from "./StructureTypesRoutes";
|
|
@@ -88,6 +90,14 @@ export const DictionaryRoutes = () => {
|
|
|
88
90
|
</>
|
|
89
91
|
)}
|
|
90
92
|
/>
|
|
93
|
+
<Route
|
|
94
|
+
path={STRUCTURES_UPLOAD_EVENTS}
|
|
95
|
+
render={() => (
|
|
96
|
+
<>
|
|
97
|
+
<StructuresUploadEvents />
|
|
98
|
+
</>
|
|
99
|
+
)}
|
|
100
|
+
/>
|
|
91
101
|
<Route
|
|
92
102
|
path={PENDING_STRUCTURE_NOTES}
|
|
93
103
|
render={() => (
|
|
@@ -55,7 +55,10 @@ export const GrantRequestApprovalForm = ({
|
|
|
55
55
|
control={control}
|
|
56
56
|
name="role"
|
|
57
57
|
rules={{ validate: (v) => !_.isEmpty(v) }}
|
|
58
|
-
render={({
|
|
58
|
+
render={({
|
|
59
|
+
field: { onBlur, onChange, value },
|
|
60
|
+
fieldState: { error },
|
|
61
|
+
}) => (
|
|
59
62
|
<Form.Dropdown
|
|
60
63
|
placeholder={formatMessage({
|
|
61
64
|
id: "grantRequestApproval.form.role.placeholder",
|
|
@@ -63,7 +66,7 @@ export const GrantRequestApprovalForm = ({
|
|
|
63
66
|
label={formatMessage({
|
|
64
67
|
id: "grantRequestApproval.form.role.label",
|
|
65
68
|
})}
|
|
66
|
-
error={
|
|
69
|
+
error={!!error}
|
|
67
70
|
onBlur={onBlur}
|
|
68
71
|
value={value}
|
|
69
72
|
onChange={(_, { value }) => onChange(value)}
|
|
@@ -76,7 +79,10 @@ export const GrantRequestApprovalForm = ({
|
|
|
76
79
|
<Controller
|
|
77
80
|
control={control}
|
|
78
81
|
name="comment"
|
|
79
|
-
render={({
|
|
82
|
+
render={({
|
|
83
|
+
field: { onBlur, onChange, value },
|
|
84
|
+
fieldState: { error },
|
|
85
|
+
}) => (
|
|
80
86
|
<Form.TextArea
|
|
81
87
|
data-testid="comment-id"
|
|
82
88
|
label={formatMessage({
|
|
@@ -87,7 +93,7 @@ export const GrantRequestApprovalForm = ({
|
|
|
87
93
|
})}
|
|
88
94
|
value={value}
|
|
89
95
|
onBlur={onBlur}
|
|
90
|
-
error={
|
|
96
|
+
error={!!error}
|
|
91
97
|
onChange={(_, { value }) => onChange(value)}
|
|
92
98
|
/>
|
|
93
99
|
)}
|
|
@@ -16,7 +16,7 @@ export const LinkStructureTagForm = ({
|
|
|
16
16
|
linkStructureTag,
|
|
17
17
|
structureId,
|
|
18
18
|
structureTags,
|
|
19
|
-
tagId
|
|
19
|
+
tagId,
|
|
20
20
|
}) => {
|
|
21
21
|
const { formatMessage } = useIntl();
|
|
22
22
|
const allTags = _.map("id")(structureTags);
|
|
@@ -39,11 +39,11 @@ export const LinkStructureTagForm = ({
|
|
|
39
39
|
const submitTitle = _.isNil(tagId)
|
|
40
40
|
? "structure.tag.add"
|
|
41
41
|
: "structure.tag.edit";
|
|
42
|
-
const onSubmit = params => {
|
|
42
|
+
const onSubmit = (params) => {
|
|
43
43
|
const payload = {
|
|
44
44
|
structureId,
|
|
45
45
|
tagId: params.tag,
|
|
46
|
-
tag: { description: params.description }
|
|
46
|
+
tag: { description: params.description },
|
|
47
47
|
};
|
|
48
48
|
linkStructureTag(payload);
|
|
49
49
|
};
|
|
@@ -52,8 +52,8 @@ export const LinkStructureTagForm = ({
|
|
|
52
52
|
mode: "all",
|
|
53
53
|
defaultValues: {
|
|
54
54
|
description: description || "",
|
|
55
|
-
tag: defaultTag
|
|
56
|
-
}
|
|
55
|
+
tag: defaultTag,
|
|
56
|
+
},
|
|
57
57
|
});
|
|
58
58
|
const { isDirty, isValid } = formState;
|
|
59
59
|
return (
|
|
@@ -63,13 +63,16 @@ export const LinkStructureTagForm = ({
|
|
|
63
63
|
control={control}
|
|
64
64
|
name="tag"
|
|
65
65
|
rules={{ required: true }}
|
|
66
|
-
render={({
|
|
66
|
+
render={({
|
|
67
|
+
field: { onBlur, onChange, value },
|
|
68
|
+
fieldState: { error },
|
|
69
|
+
}) => (
|
|
67
70
|
<Form.Dropdown
|
|
68
71
|
name="tag"
|
|
69
72
|
disabled={_.negate(_.isNil)(tagId)}
|
|
70
|
-
error={
|
|
73
|
+
error={!!error}
|
|
71
74
|
placeholder={formatMessage({
|
|
72
|
-
id: "structure.tag.dropdown.placeholder"
|
|
75
|
+
id: "structure.tag.dropdown.placeholder",
|
|
73
76
|
})}
|
|
74
77
|
label={formatMessage({ id: "structure.tag.dropdown.label" })}
|
|
75
78
|
onBlur={onBlur}
|
|
@@ -86,14 +89,17 @@ export const LinkStructureTagForm = ({
|
|
|
86
89
|
control={control}
|
|
87
90
|
name="description"
|
|
88
91
|
rules={{ required: true }}
|
|
89
|
-
render={({
|
|
92
|
+
render={({
|
|
93
|
+
field: { onBlur, onChange, value },
|
|
94
|
+
fieldState: { error },
|
|
95
|
+
}) => (
|
|
90
96
|
<Form.TextArea
|
|
91
97
|
data-testid="description-id"
|
|
92
|
-
error={
|
|
98
|
+
error={!!error}
|
|
93
99
|
name="description"
|
|
94
100
|
label={formatMessage({ id: "structure.tag.textArea.label" })}
|
|
95
101
|
placeholder={formatMessage({
|
|
96
|
-
id: "structure.tag.textArea.placeholder"
|
|
102
|
+
id: "structure.tag.textArea.placeholder",
|
|
97
103
|
})}
|
|
98
104
|
onBlur={onBlur}
|
|
99
105
|
onChange={(_e, { value }) => onChange(value)}
|
|
@@ -130,22 +136,22 @@ LinkStructureTagForm.propTypes = {
|
|
|
130
136
|
linkStructureTag: PropTypes.func,
|
|
131
137
|
structureId: PropTypes.number,
|
|
132
138
|
structureTags: PropTypes.array,
|
|
133
|
-
tagId: PropTypes.number
|
|
139
|
+
tagId: PropTypes.number,
|
|
134
140
|
};
|
|
135
141
|
|
|
136
142
|
const mapStateToProps = ({
|
|
137
143
|
linkedStructureTags,
|
|
138
144
|
structure,
|
|
139
|
-
structureTags
|
|
145
|
+
structureTags,
|
|
140
146
|
}) => ({
|
|
141
147
|
linkedStructureTags,
|
|
142
148
|
structureId: _.prop("id")(structure),
|
|
143
|
-
structureTags
|
|
149
|
+
structureTags,
|
|
144
150
|
});
|
|
145
151
|
|
|
146
152
|
const mapDispatchToProps = {
|
|
147
153
|
deleteLinkStructureTag,
|
|
148
|
-
linkStructureTag
|
|
154
|
+
linkStructureTag,
|
|
149
155
|
};
|
|
150
156
|
|
|
151
157
|
export default connect(
|
|
@@ -12,7 +12,7 @@ export const MetadataFiltersInput = ({ control, fieldOptions, fields }) => {
|
|
|
12
12
|
control={control}
|
|
13
13
|
name="filters"
|
|
14
14
|
defaultValue={_.isArray(fields) ? fields : []}
|
|
15
|
-
render={({ onBlur, onChange, value }) => (
|
|
15
|
+
render={({ field: { onBlur, onChange, value } }) => (
|
|
16
16
|
<Form.Dropdown
|
|
17
17
|
name="filters"
|
|
18
18
|
label={formatMessage({ id: "structureType.filters" })}
|
|
@@ -26,7 +26,7 @@ export const MetadataViewForm = ({
|
|
|
26
26
|
control={control}
|
|
27
27
|
name={`metadata_views.${idx}.name`}
|
|
28
28
|
defaultValue={name || ""}
|
|
29
|
-
render={({ onBlur, onChange, value }) => (
|
|
29
|
+
render={({ field: { onBlur, onChange, value } }) => (
|
|
30
30
|
<Form.Input
|
|
31
31
|
autoComplete="off"
|
|
32
32
|
name={`metadata_views.${idx}.name`}
|
|
@@ -45,7 +45,7 @@ export const MetadataViewForm = ({
|
|
|
45
45
|
control={control}
|
|
46
46
|
name={`metadata_views.${idx}.fields`}
|
|
47
47
|
defaultValue={_.isArray(fields) ? fields : []}
|
|
48
|
-
render={({ onBlur, onChange, value }) => (
|
|
48
|
+
render={({ field: { onBlur, onChange, value } }) => (
|
|
49
49
|
<Form.Dropdown
|
|
50
50
|
name={`metadata_views.${idx}.fields`}
|
|
51
51
|
label={formatMessage({ id: "metadataView.fields" })}
|
|
@@ -50,7 +50,7 @@ export const MyGrantRequests = ({
|
|
|
50
50
|
<Controller
|
|
51
51
|
control={control}
|
|
52
52
|
name="status"
|
|
53
|
-
render={({ onBlur, onChange, value }) => (
|
|
53
|
+
render={({ field: { onBlur, onChange, value } }) => (
|
|
54
54
|
<Form.Field className="subscriptions-checkbox-filters">
|
|
55
55
|
<label>
|
|
56
56
|
{formatMessage({ id: "grantRequest.header.status" })}
|
|
@@ -74,7 +74,7 @@ export const PendingStructureNotes = () => {
|
|
|
74
74
|
<Controller
|
|
75
75
|
control={control}
|
|
76
76
|
name="status"
|
|
77
|
-
render={({ onBlur, onChange, value }) => (
|
|
77
|
+
render={({ field: { onBlur, onChange, value } }) => (
|
|
78
78
|
<Form.Field className="subscriptions-checkbox-filters">
|
|
79
79
|
<label>
|
|
80
80
|
{formatMessage({ id: "pendingStructureNotes.props.status" })}
|
|
@@ -104,7 +104,7 @@ export const PendingStructureNotes = () => {
|
|
|
104
104
|
<Controller
|
|
105
105
|
control={control}
|
|
106
106
|
name="system_ids"
|
|
107
|
-
render={({ onBlur, onChange, value }) => (
|
|
107
|
+
render={({ field: { onBlur, onChange, value } }) => (
|
|
108
108
|
<Form.Dropdown
|
|
109
109
|
label={formatMessage({
|
|
110
110
|
id: "pendingStructureNotes.props.system",
|
|
@@ -129,7 +129,7 @@ export const PendingStructureNotes = () => {
|
|
|
129
129
|
<Controller
|
|
130
130
|
control={control}
|
|
131
131
|
name="domain_ids"
|
|
132
|
-
render={({ onChange, value }) => (
|
|
132
|
+
render={({ field: { onChange, value } }) => (
|
|
133
133
|
<DomainDropdownSelector
|
|
134
134
|
value={value}
|
|
135
135
|
onChange={(_e, { value }) => {
|
|
@@ -37,10 +37,13 @@ export const StructureTagForm = ({
|
|
|
37
37
|
control={control}
|
|
38
38
|
name="name"
|
|
39
39
|
rules={{ required: true }}
|
|
40
|
-
render={({
|
|
40
|
+
render={({
|
|
41
|
+
field: { onBlur, onChange, value },
|
|
42
|
+
fieldState: { error },
|
|
43
|
+
}) => (
|
|
41
44
|
<Form.Input
|
|
42
45
|
autoComplete="off"
|
|
43
|
-
error={
|
|
46
|
+
error={!!error}
|
|
44
47
|
id="name"
|
|
45
48
|
label={formatMessage({ id: "structureTagForm.props.name" })}
|
|
46
49
|
onBlur={onBlur}
|
|
@@ -62,7 +62,7 @@ export const StructureTypeForm = ({
|
|
|
62
62
|
control={control}
|
|
63
63
|
defaultValue=""
|
|
64
64
|
name="translation"
|
|
65
|
-
render={({ onBlur, onChange, value }) => (
|
|
65
|
+
render={({ field: { onBlur, onChange, value } }) => (
|
|
66
66
|
<Form.Input
|
|
67
67
|
autoComplete="off"
|
|
68
68
|
label={formatMessage({ id: "structureType.translation" })}
|
|
@@ -77,7 +77,7 @@ export const StructureTypeForm = ({
|
|
|
77
77
|
control={control}
|
|
78
78
|
name="template_id"
|
|
79
79
|
defaultValue=""
|
|
80
|
-
render={({ onBlur, onChange, value }) => (
|
|
80
|
+
render={({ field: { onBlur, onChange, value } }) => (
|
|
81
81
|
<Form.Dropdown
|
|
82
82
|
label={formatMessage({ id: "structureType.template" })}
|
|
83
83
|
name="template_id"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { connect } from "react-redux";
|
|
4
|
+
import { Header, Icon, Segment, Dimmer, Loader } from "semantic-ui-react";
|
|
5
|
+
import { FormattedMessage } from "react-intl";
|
|
6
|
+
import StructuresUploadEventsTable from "./StructuresUploadEventsTable";
|
|
7
|
+
|
|
8
|
+
export const StructuresUploadEvents = ({ structuresUploadEventsLoading }) => (
|
|
9
|
+
<Segment>
|
|
10
|
+
<Header as="h2">
|
|
11
|
+
<Icon circular name="cogs" />
|
|
12
|
+
<Header.Content>
|
|
13
|
+
<FormattedMessage id="structures.bulkUploadEvents.header" />
|
|
14
|
+
<Header.Subheader>
|
|
15
|
+
<FormattedMessage id="structures.bulkUploadEvents.subheader" />
|
|
16
|
+
</Header.Subheader>
|
|
17
|
+
</Header.Content>
|
|
18
|
+
</Header>
|
|
19
|
+
<Dimmer.Dimmable dimmed={structuresUploadEventsLoading}>
|
|
20
|
+
<Segment attached="bottom">
|
|
21
|
+
<StructuresUploadEventsTable />
|
|
22
|
+
<Dimmer inverted active={structuresUploadEventsLoading}>
|
|
23
|
+
<Loader />
|
|
24
|
+
</Dimmer>
|
|
25
|
+
</Segment>
|
|
26
|
+
</Dimmer.Dimmable>
|
|
27
|
+
</Segment>
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
StructuresUploadEvents.propTypes = {
|
|
31
|
+
structuresUploadEventsLoading: PropTypes.bool,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const mapStateToProps = ({ structuresUploadEventsLoading }) => ({
|
|
35
|
+
structuresUploadEventsLoading,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export default connect(mapStateToProps)(StructuresUploadEvents);
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import React, { useEffect, useState } from "react";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import { FormattedMessage } from "react-intl";
|
|
5
|
+
import { Header, Icon, Table } from "semantic-ui-react";
|
|
6
|
+
import { connect } from "react-redux";
|
|
7
|
+
import { useIntl } from "react-intl";
|
|
8
|
+
import { columnDecorator } from "@truedat/core/services";
|
|
9
|
+
import { fetchStructuresUploadEvents } from "../routines";
|
|
10
|
+
import { getStructuresUploadEventColumns } from "../selectors";
|
|
11
|
+
|
|
12
|
+
import "../styles/structuresUploadEventColumns.less";
|
|
13
|
+
|
|
14
|
+
export const getColumnsWithData = (ruleResults, columns) =>
|
|
15
|
+
_.filter((column) =>
|
|
16
|
+
_.any(_.flow(columnDecorator(column), _.negate(_.isEmpty)))(ruleResults)
|
|
17
|
+
)(columns);
|
|
18
|
+
|
|
19
|
+
export const StructuresUploadEventsTable = ({
|
|
20
|
+
columns,
|
|
21
|
+
fetchStructuresUploadEvents,
|
|
22
|
+
structuresUploadEvents,
|
|
23
|
+
structuresUploadEventsLoading,
|
|
24
|
+
}) => {
|
|
25
|
+
const { formatMessage } = useIntl();
|
|
26
|
+
const [events, setEvents] = useState();
|
|
27
|
+
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
fetchStructuresUploadEvents();
|
|
30
|
+
}, [fetchStructuresUploadEvents]);
|
|
31
|
+
|
|
32
|
+
const messagesImp = (data) => {
|
|
33
|
+
return _.has("errors")(data)
|
|
34
|
+
? _.flow(
|
|
35
|
+
_.propOr([], "errors"),
|
|
36
|
+
_.map((error) => ({
|
|
37
|
+
id: `structures.bulkUpdateStructures.failed.note.${error.message}`,
|
|
38
|
+
fields: {
|
|
39
|
+
row: error.row,
|
|
40
|
+
id: error.id,
|
|
41
|
+
field: error.field,
|
|
42
|
+
externalId: error.external_id,
|
|
43
|
+
message: error.message,
|
|
44
|
+
},
|
|
45
|
+
defaultMessage: "structures.bulkUploadStructures.success.errors",
|
|
46
|
+
}))
|
|
47
|
+
)(data)
|
|
48
|
+
: [];
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
const events = _.reduce(
|
|
53
|
+
(acc, event) => ({
|
|
54
|
+
...acc,
|
|
55
|
+
[`${event.task_reference}_${event.status}`]: {
|
|
56
|
+
...event,
|
|
57
|
+
response: {
|
|
58
|
+
...event.response,
|
|
59
|
+
translatedHeader: !event.response
|
|
60
|
+
? ""
|
|
61
|
+
: formatMessage(
|
|
62
|
+
{ id: "structures.bulkUpdateStructures.success.header" },
|
|
63
|
+
{
|
|
64
|
+
count_ids: event.response.ids.length,
|
|
65
|
+
count_errors: event.response.errors.length,
|
|
66
|
+
}
|
|
67
|
+
),
|
|
68
|
+
translatedErrors: _.map((error) => {
|
|
69
|
+
return formatMessage({ id: error.id }, error.fields);
|
|
70
|
+
})(messagesImp(event.response)),
|
|
71
|
+
},
|
|
72
|
+
expanded: false,
|
|
73
|
+
},
|
|
74
|
+
}),
|
|
75
|
+
{},
|
|
76
|
+
structuresUploadEvents
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
setEvents(events);
|
|
80
|
+
}, [structuresUploadEvents, formatMessage]);
|
|
81
|
+
|
|
82
|
+
const toggleExpanded = (eventKey) => {
|
|
83
|
+
setEvents({
|
|
84
|
+
...events,
|
|
85
|
+
[eventKey]: {
|
|
86
|
+
...events[eventKey],
|
|
87
|
+
expanded: !events[eventKey].expanded,
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<>
|
|
94
|
+
{!_.isEmpty(events) && (
|
|
95
|
+
<Table sortable selectable>
|
|
96
|
+
<Table.Header>
|
|
97
|
+
<Table.Row>
|
|
98
|
+
{columns.map((column, i) => {
|
|
99
|
+
return (
|
|
100
|
+
<Table.HeaderCell
|
|
101
|
+
key={i}
|
|
102
|
+
width={column.width}
|
|
103
|
+
content={formatMessage({
|
|
104
|
+
id: `structures.bulkUploadEvents.props.${column.name}`,
|
|
105
|
+
defaultMessage: column.name,
|
|
106
|
+
})}
|
|
107
|
+
/>
|
|
108
|
+
);
|
|
109
|
+
})}
|
|
110
|
+
</Table.Row>
|
|
111
|
+
</Table.Header>
|
|
112
|
+
<Table.Body>
|
|
113
|
+
{_.map((eventKey) => {
|
|
114
|
+
return (
|
|
115
|
+
<Table.Row
|
|
116
|
+
className={
|
|
117
|
+
events[eventKey].expanded ? "expanded" : "contracted"
|
|
118
|
+
}
|
|
119
|
+
key={eventKey}
|
|
120
|
+
onClick={() => toggleExpanded(eventKey)}
|
|
121
|
+
>
|
|
122
|
+
{!events[eventKey].expanded ? (
|
|
123
|
+
columns &&
|
|
124
|
+
columns.map((column, key) => (
|
|
125
|
+
<Table.Cell
|
|
126
|
+
key={key}
|
|
127
|
+
textAlign={column.textAlign}
|
|
128
|
+
content={columnDecorator(column)({
|
|
129
|
+
...events[eventKey],
|
|
130
|
+
formatMessage,
|
|
131
|
+
})}
|
|
132
|
+
/>
|
|
133
|
+
))
|
|
134
|
+
) : (
|
|
135
|
+
<Table.Cell
|
|
136
|
+
colSpan={columns.length}
|
|
137
|
+
content={columns.map((column, key) => (
|
|
138
|
+
<div key={key}>
|
|
139
|
+
{columnDecorator(column)({
|
|
140
|
+
...events[eventKey],
|
|
141
|
+
formatMessage,
|
|
142
|
+
})}
|
|
143
|
+
</div>
|
|
144
|
+
))}
|
|
145
|
+
/>
|
|
146
|
+
)}
|
|
147
|
+
</Table.Row>
|
|
148
|
+
);
|
|
149
|
+
}, Object.keys(events))}
|
|
150
|
+
</Table.Body>
|
|
151
|
+
</Table>
|
|
152
|
+
)}
|
|
153
|
+
{_.isEmpty(structuresUploadEvents) && !structuresUploadEventsLoading && (
|
|
154
|
+
<Header as="h4">
|
|
155
|
+
<Icon name="search" />
|
|
156
|
+
<Header.Content>
|
|
157
|
+
<FormattedMessage id="structures.bulkUploadEvents.results.empty" />
|
|
158
|
+
</Header.Content>
|
|
159
|
+
</Header>
|
|
160
|
+
)}
|
|
161
|
+
</>
|
|
162
|
+
);
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
StructuresUploadEventsTable.propTypes = {
|
|
166
|
+
columns: PropTypes.array,
|
|
167
|
+
structuresUploadEvents: PropTypes.array,
|
|
168
|
+
fetchStructuresUploadEvents: PropTypes.func,
|
|
169
|
+
structuresUploadEventsLoading: PropTypes.bool,
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const mapStateToProps = (state) => ({
|
|
173
|
+
columns: getColumnsWithData(
|
|
174
|
+
state.structuresUploadEvents,
|
|
175
|
+
getStructuresUploadEventColumns(state)
|
|
176
|
+
),
|
|
177
|
+
structuresUploadEvents: state.structuresUploadEvents,
|
|
178
|
+
structuresUploadEventsLoading: state.structuresUploadEventsLoading,
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
export default connect(mapStateToProps, { fetchStructuresUploadEvents })(
|
|
182
|
+
StructuresUploadEventsTable
|
|
183
|
+
);
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import userEvent from "@testing-library/user-event";
|
|
4
|
+
import { render } from "@truedat/test/render";
|
|
5
|
+
import en from "../../messages/en";
|
|
6
|
+
import StructuresUploadEventsTable from "../StructuresUploadEventsTable";
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
const events = [
|
|
11
|
+
{
|
|
12
|
+
"csv_hash": "99E400B91D164F8F0A39F400CA323C8F",
|
|
13
|
+
"inserted_at": "2022-04-23T15:53:24.638484Z",
|
|
14
|
+
"message": null,
|
|
15
|
+
"response": {
|
|
16
|
+
"errors": [],
|
|
17
|
+
"ids": [
|
|
18
|
+
4825521,
|
|
19
|
+
4825561,
|
|
20
|
+
4825593
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
"status": "COMPLETED",
|
|
24
|
+
"task_reference": "0.3225053307.1609564164.100549",
|
|
25
|
+
"user_id": 467
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"csv_hash": "47D90FDF1AD967BD7DBBDAE28664278E",
|
|
29
|
+
"inserted_at": "2022-04-23T15:14:48.770275Z",
|
|
30
|
+
"message": null,
|
|
31
|
+
"response": {
|
|
32
|
+
"errors": [
|
|
33
|
+
{
|
|
34
|
+
"external_id": "file://corporate-landing-s3/cep-pro-ld-cor/batch/SAP/FSCM/vendor_issue/SAP_FSCM_CM_VENDOR_ISUE/ZFSCM_AC",
|
|
35
|
+
"field": "gdpr",
|
|
36
|
+
"message": "df_content.inclusion",
|
|
37
|
+
"row": 4
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"external_id": "file://corporate-landing-s3/cep-pro-ld-cor/batch/SAP/FSCM/vendor_issue/SAP_FSCM_CM_VENDOR_ISUE/ZFSCM_FN",
|
|
41
|
+
"field": "business_description",
|
|
42
|
+
"message": "df_content.required",
|
|
43
|
+
"row": 2
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"external_id": "file://corporate-landing-s3/cep-pro-ld-cor/batch/SAP/FSCM/vendor_issue/SAP_FSCM_CM_VENDOR_ISUE/ZFSCM_PC",
|
|
47
|
+
"field": "business_description",
|
|
48
|
+
"message": "df_content.required",
|
|
49
|
+
"row": 3
|
|
50
|
+
}
|
|
51
|
+
],
|
|
52
|
+
"ids": []
|
|
53
|
+
},
|
|
54
|
+
"status": "COMPLETED",
|
|
55
|
+
"task_reference": "0.3225053307.1609564162.101463",
|
|
56
|
+
"user_id": 467
|
|
57
|
+
}
|
|
58
|
+
];
|
|
59
|
+
|
|
60
|
+
const renderOpts = {
|
|
61
|
+
messages: { en },
|
|
62
|
+
state: { structuresUploadEvents: events },
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
describe("<StructuresUploadEventsTable />", () => {
|
|
67
|
+
it("matches the latest snapshot", () => {
|
|
68
|
+
const { container } = render(<StructuresUploadEventsTable />, renderOpts);
|
|
69
|
+
expect(container).toMatchSnapshot();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("toggles row horizontal view when row is clicked", () => {
|
|
73
|
+
const { getAllByRole } = render(
|
|
74
|
+
<StructuresUploadEventsTable />,
|
|
75
|
+
renderOpts
|
|
76
|
+
);
|
|
77
|
+
const dataRow = getAllByRole("row")[1];
|
|
78
|
+
expect(dataRow).toHaveClass("contracted");
|
|
79
|
+
userEvent.click(dataRow);
|
|
80
|
+
expect(dataRow).toHaveClass("expanded");
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
});
|
|
@@ -21,6 +21,10 @@ exports[`<DictionaryRoutes /> matches the latest snapshot 1`] = `
|
|
|
21
21
|
path="/structure_types"
|
|
22
22
|
render={[Function]}
|
|
23
23
|
/>
|
|
24
|
+
<Route
|
|
25
|
+
path="/bulk_update_template_content_events"
|
|
26
|
+
render={[Function]}
|
|
27
|
+
/>
|
|
24
28
|
<Route
|
|
25
29
|
path="/structure_notes"
|
|
26
30
|
render={[Function]}
|