@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.
Files changed (35) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/package.json +7 -7
  3. package/src/api.js +3 -0
  4. package/src/components/DictionaryRoutes.js +10 -0
  5. package/src/components/GrantRequestApprovalForm.js +10 -4
  6. package/src/components/LinkStructureTagForm.js +21 -15
  7. package/src/components/MetadataFiltersInput.js +1 -1
  8. package/src/components/MetadataViewForm.js +2 -2
  9. package/src/components/MyGrantRequests.js +1 -1
  10. package/src/components/PendingStructureNotes.js +3 -3
  11. package/src/components/StructureTagForm.js +5 -2
  12. package/src/components/StructureTypeForm.js +2 -2
  13. package/src/components/StructuresUploadEvents.js +38 -0
  14. package/src/components/StructuresUploadEventsTable.js +183 -0
  15. package/src/components/__tests__/StructuresUploadEventsTable.spec.js +84 -0
  16. package/src/components/__tests__/__snapshots__/DictionaryRoutes.spec.js.snap +4 -0
  17. package/src/components/__tests__/__snapshots__/StructuresUploadEventsTable.spec.js.snap +130 -0
  18. package/src/messages/en.js +17 -0
  19. package/src/messages/es.js +18 -0
  20. package/src/reducers/__tests__/structuresUploadEvents.spec.js +46 -0
  21. package/src/reducers/__tests__/structuresUploadEventsLoading.spec.js +26 -0
  22. package/src/reducers/ddMessage.js +54 -30
  23. package/src/reducers/index.js +4 -0
  24. package/src/reducers/structuresUploadEvents.js +16 -0
  25. package/src/reducers/structuresUploadEventsLoading.js +16 -0
  26. package/src/routines.js +1 -0
  27. package/src/sagas/__tests__/fetchStructuresUploadEvents.spec.js +79 -0
  28. package/src/sagas/__tests__/uploadStructures.spec.js +3 -2
  29. package/src/sagas/fetchStructuresUploadEvents.js +29 -0
  30. package/src/sagas/index.js +3 -0
  31. package/src/sagas/uploadStructures.js +2 -2
  32. package/src/selectors/__tests__/getStructuresUploadEventColumns.spec.js +20 -0
  33. package/src/selectors/getStructuresUploadEventColumns.js +74 -0
  34. package/src/selectors/index.js +4 -0
  35. package/src/styles/structuresUploadEventColumns.less +24 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.43.4] 2022-05-05
4
+
5
+ ### Added
6
+
7
+ - [TD-4586] CSV bulk update events table
8
+
9
+ ## [4.43.3] 2022-05-04
10
+
11
+ ### Changed
12
+
13
+ - [TD-3936] Updated `react-hook-form`
14
+
3
15
  ## [4.43.0] 2022-04-26
4
16
 
5
17
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/dd",
3
- "version": "4.43.2",
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.2",
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.2",
88
- "@truedat/core": "4.43.2",
89
- "@truedat/df": "4.43.2",
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": "^6.15.8",
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": "26f59c4d36ab1ecfae705bbce4320ff443cce304"
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={({ onBlur, onChange, value }, { invalid }) => (
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={invalid}
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={({ onBlur, onChange, value }, { invalid }) => (
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={invalid}
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={({ onBlur, onChange, value }, { invalid }) => (
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={invalid}
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={({ onBlur, onChange, value }, { invalid }) => (
92
+ render={({
93
+ field: { onBlur, onChange, value },
94
+ fieldState: { error },
95
+ }) => (
90
96
  <Form.TextArea
91
97
  data-testid="description-id"
92
- error={invalid}
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={({ onBlur, onChange, value }, { invalid }) => (
40
+ render={({
41
+ field: { onBlur, onChange, value },
42
+ fieldState: { error },
43
+ }) => (
41
44
  <Form.Input
42
45
  autoComplete="off"
43
- error={invalid}
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]}