@truedat/bg 5.7.1 → 5.7.3
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/package.json +6 -6
- package/src/concepts/components/ConceptsBulkUpdate.js +243 -180
- package/src/concepts/components/ConceptsUpdateButton.js +5 -2
- package/src/concepts/components/__tests__/ConceptsBulkUpdate.spec.js +31 -26
- package/src/concepts/components/__tests__/ConceptsUpdateButton.spec.js +8 -3
- package/src/concepts/components/__tests__/__snapshots__/ConceptsBulkUpdate.spec.js.snap +0 -1
- package/src/concepts/components/__tests__/__snapshots__/ConceptsUpdateButton.spec.js.snap +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truedat/bg",
|
|
3
|
-
"version": "5.7.
|
|
3
|
+
"version": "5.7.3",
|
|
4
4
|
"description": "Truedat Web Business Glossary",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"jsnext:main": "src/index.js",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"@testing-library/jest-dom": "^5.16.5",
|
|
35
35
|
"@testing-library/react": "^12.0.0",
|
|
36
36
|
"@testing-library/user-event": "^13.2.1",
|
|
37
|
-
"@truedat/test": "5.7.
|
|
37
|
+
"@truedat/test": "5.7.3",
|
|
38
38
|
"babel-jest": "^28.1.0",
|
|
39
39
|
"babel-plugin-dynamic-import-node": "^2.3.3",
|
|
40
40
|
"babel-plugin-lodash": "^3.3.4",
|
|
@@ -86,9 +86,9 @@
|
|
|
86
86
|
]
|
|
87
87
|
},
|
|
88
88
|
"dependencies": {
|
|
89
|
-
"@truedat/core": "5.7.
|
|
90
|
-
"@truedat/df": "5.7.
|
|
91
|
-
"@truedat/lm": "5.7.
|
|
89
|
+
"@truedat/core": "5.7.3",
|
|
90
|
+
"@truedat/df": "5.7.3",
|
|
91
|
+
"@truedat/lm": "5.7.3",
|
|
92
92
|
"decode-uri-component": "^0.2.2",
|
|
93
93
|
"file-saver": "^2.0.5",
|
|
94
94
|
"moment": "^2.29.4",
|
|
@@ -111,5 +111,5 @@
|
|
|
111
111
|
"react-dom": ">= 16.8.6 < 17",
|
|
112
112
|
"semantic-ui-react": ">= 2.0.3 < 2.2"
|
|
113
113
|
},
|
|
114
|
-
"gitHead": "
|
|
114
|
+
"gitHead": "adaa367000214d1d4200c98b62aadfc84a29da07"
|
|
115
115
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import _ from "lodash/fp";
|
|
2
|
-
import React from "react";
|
|
2
|
+
import React, { useState, useEffect } from "react";
|
|
3
3
|
import PropTypes from "prop-types";
|
|
4
|
+
import { FormattedMessage } from "react-intl";
|
|
5
|
+
import { useLocation } from "react-router-dom";
|
|
6
|
+
import { connect } from "react-redux";
|
|
4
7
|
import {
|
|
5
8
|
Button,
|
|
6
9
|
Container,
|
|
@@ -10,217 +13,277 @@ import {
|
|
|
10
13
|
Segment,
|
|
11
14
|
Message,
|
|
12
15
|
} from "semantic-ui-react";
|
|
13
|
-
|
|
14
|
-
import { FormattedMessage } from "react-intl";
|
|
16
|
+
|
|
15
17
|
import {
|
|
16
18
|
ConfirmModal,
|
|
17
19
|
DomainSelector,
|
|
18
20
|
HistoryBackButton,
|
|
21
|
+
Loading,
|
|
19
22
|
} from "@truedat/core/components";
|
|
20
|
-
import {
|
|
23
|
+
import { useTemplate } from "@truedat/core/hooks";
|
|
24
|
+
import { makeSearchQuerySelector } from "@truedat/core/selectors";
|
|
25
|
+
|
|
21
26
|
import { applyTemplateWithoutDefaults } from "@truedat/df/utils";
|
|
22
|
-
import { bulkUpdate } from "../routines";
|
|
27
|
+
import { bulkUpdate, fetchConcepts } from "../routines";
|
|
23
28
|
|
|
24
29
|
const DynamicForm = React.lazy(() =>
|
|
25
30
|
import("@truedat/df/components/DynamicForm")
|
|
26
31
|
);
|
|
27
|
-
const TemplateLoader = React.lazy(() =>
|
|
28
|
-
import("@truedat/df/templates/components/TemplateLoader")
|
|
29
|
-
);
|
|
30
32
|
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
const isEmptyValue = (value) => !_.isNumber(value) && _.isEmpty(value);
|
|
34
|
+
const fieldsToOmit = ["_confidential"];
|
|
35
|
+
const pendingConceptsFilters = {
|
|
36
|
+
status: ["pending_approval", "draft", "rejected"],
|
|
37
|
+
};
|
|
38
|
+
const conceptFilters = {
|
|
39
|
+
status: ["published"],
|
|
36
40
|
};
|
|
37
41
|
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
const TemplateLoader = ({
|
|
43
|
+
templateName,
|
|
44
|
+
domainId,
|
|
45
|
+
onChange,
|
|
46
|
+
content,
|
|
47
|
+
fieldsToOmit,
|
|
48
|
+
setTemplate,
|
|
49
|
+
}) => {
|
|
50
|
+
const { data, loading } = useTemplate({
|
|
51
|
+
name: templateName,
|
|
52
|
+
domainIds: [domainId],
|
|
53
|
+
});
|
|
41
54
|
|
|
42
|
-
const
|
|
55
|
+
const template = _.prop("template")(data);
|
|
43
56
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
secondary: true,
|
|
48
|
-
content: <FormattedMessage id="confirmation.no" />,
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
key: "yes",
|
|
52
|
-
primary: true,
|
|
53
|
-
content: <FormattedMessage id="confirmation.yes" />,
|
|
54
|
-
onClick: handleSubmit,
|
|
55
|
-
},
|
|
56
|
-
];
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
setTemplate(template);
|
|
59
|
+
}, [template]);
|
|
57
60
|
|
|
58
|
-
|
|
61
|
+
return loading || !template ? (
|
|
62
|
+
<Loading />
|
|
63
|
+
) : template ? (
|
|
64
|
+
<DynamicForm
|
|
65
|
+
onChange={onChange}
|
|
66
|
+
template={template}
|
|
67
|
+
applyTemplate={applyTemplateWithoutDefaults}
|
|
68
|
+
content={content}
|
|
69
|
+
fieldsToOmit={fieldsToOmit}
|
|
70
|
+
/>
|
|
71
|
+
) : null;
|
|
72
|
+
};
|
|
59
73
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
applyTemplate: PropTypes.func,
|
|
69
|
-
bulkUpdate: PropTypes.func,
|
|
70
|
-
};
|
|
74
|
+
TemplateLoader.propTypes = {
|
|
75
|
+
templateName: PropTypes.string,
|
|
76
|
+
domainId: PropTypes.number,
|
|
77
|
+
onChange: PropTypes.func,
|
|
78
|
+
content: PropTypes.object,
|
|
79
|
+
fieldsToOmit: PropTypes.array,
|
|
80
|
+
setTemplate: PropTypes.func,
|
|
81
|
+
};
|
|
71
82
|
|
|
72
|
-
|
|
83
|
+
export const ConceptsBulkUpdate = ({
|
|
84
|
+
loading,
|
|
85
|
+
conceptCount,
|
|
86
|
+
concepts,
|
|
87
|
+
templateName,
|
|
88
|
+
bulkUpdate,
|
|
89
|
+
fetchConcepts,
|
|
90
|
+
conceptPayload,
|
|
91
|
+
}) => {
|
|
92
|
+
const [content, setContent] = useState({});
|
|
93
|
+
const [domains, setDomains] = useState([]);
|
|
94
|
+
const [domainsLoading, setDomainsLoading] = useState(true);
|
|
95
|
+
const [selectedDomain, setSelectedDomain] = useState();
|
|
96
|
+
const [domainId, setDomainId] = useState(null);
|
|
97
|
+
const [template, setTemplate] = useState(null);
|
|
73
98
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
selectTemplate({ id: templateId });
|
|
77
|
-
}
|
|
99
|
+
const { search } = useLocation();
|
|
100
|
+
const path = search.split("?").pop();
|
|
78
101
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
const defaultFilters =
|
|
104
|
+
path === "pendingConcepts" ? pendingConceptsFilters : conceptFilters;
|
|
105
|
+
const subscope =
|
|
106
|
+
path !== "concepts" && path !== "pendingConcepts" ? [path] : "";
|
|
107
|
+
fetchConcepts({
|
|
108
|
+
...conceptPayload,
|
|
109
|
+
filters: {
|
|
110
|
+
...conceptPayload.filters,
|
|
111
|
+
...defaultFilters,
|
|
112
|
+
"template.subscope": subscope,
|
|
113
|
+
},
|
|
114
|
+
size: 20,
|
|
115
|
+
});
|
|
116
|
+
}, []);
|
|
82
117
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
118
|
+
const handleDomainsLoaded = (domains) => {
|
|
119
|
+
setDomainsLoading(false);
|
|
120
|
+
setDomains(domains);
|
|
121
|
+
};
|
|
122
|
+
const handleDomainSelected = (value) => {
|
|
123
|
+
const domain = _.find({ id: value })(domains);
|
|
124
|
+
if (domain && domain.id !== selectedDomain) {
|
|
125
|
+
const intDomainId = domain ? _.toInteger(domain.id) : null;
|
|
126
|
+
setSelectedDomain(domain);
|
|
127
|
+
setDomainId(intDomainId);
|
|
128
|
+
} else {
|
|
129
|
+
setSelectedDomain([]);
|
|
130
|
+
setDomainId(null);
|
|
89
131
|
}
|
|
90
132
|
};
|
|
91
133
|
|
|
92
|
-
handleContentChange = (content) =>
|
|
93
|
-
|
|
94
|
-
|
|
134
|
+
const handleContentChange = (content) => {
|
|
135
|
+
setContent(content);
|
|
136
|
+
};
|
|
95
137
|
|
|
96
|
-
handleSubmit = (e) => {
|
|
138
|
+
const handleSubmit = (e) => {
|
|
97
139
|
e.preventDefault();
|
|
98
|
-
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
_.prop("content"),
|
|
102
|
-
(content) => applyTemplate(content, domain_id),
|
|
140
|
+
|
|
141
|
+
const parsedContent = _.flow(
|
|
142
|
+
applyTemplateWithoutDefaults(template, domainId),
|
|
103
143
|
_.omit(fieldsToOmit),
|
|
104
144
|
_.omitBy(isEmptyValue)
|
|
105
|
-
)(
|
|
106
|
-
|
|
145
|
+
)(content);
|
|
146
|
+
|
|
147
|
+
bulkUpdate({
|
|
148
|
+
update_attributes: { content: parsedContent, domain_id: domainId },
|
|
149
|
+
});
|
|
107
150
|
};
|
|
108
151
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
152
|
+
const validConcepts = _.size(_.uniq(_.map(_.prop("type"))(concepts))) == 1;
|
|
153
|
+
|
|
154
|
+
const isInvalid = () => !_.isFinite(domainId);
|
|
155
|
+
|
|
156
|
+
const actions = (handleSubmit) => [
|
|
157
|
+
{
|
|
158
|
+
key: "no",
|
|
159
|
+
secondary: true,
|
|
160
|
+
content: <FormattedMessage id="confirmation.no" />,
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
key: "yes",
|
|
164
|
+
primary: true,
|
|
165
|
+
content: <FormattedMessage id="confirmation.yes" />,
|
|
166
|
+
onClick: handleSubmit,
|
|
167
|
+
},
|
|
168
|
+
];
|
|
169
|
+
|
|
170
|
+
return (
|
|
171
|
+
<Container as={Segment} text>
|
|
172
|
+
<Header as="h2">
|
|
173
|
+
<Icon name="book" />
|
|
174
|
+
<Header.Content>
|
|
175
|
+
<FormattedMessage id="concepts.header.edit.bulk" />
|
|
176
|
+
</Header.Content>
|
|
177
|
+
</Header>
|
|
178
|
+
<Header as="h3">
|
|
179
|
+
<Header.Content>
|
|
180
|
+
<FormattedMessage
|
|
181
|
+
id="concepts.header.edit.bulk.concepts_count"
|
|
182
|
+
values={{ concepts_count: validConcepts ? conceptCount : 0 }}
|
|
183
|
+
/>
|
|
184
|
+
</Header.Content>
|
|
185
|
+
</Header>
|
|
186
|
+
|
|
187
|
+
{validConcepts && conceptCount != 0 ? (
|
|
188
|
+
<>
|
|
189
|
+
<Header as="h4">
|
|
190
|
+
<Header.Content>
|
|
191
|
+
<FormattedMessage id="concepts.header.edit.bulk.info_message" />
|
|
192
|
+
</Header.Content>
|
|
193
|
+
</Header>
|
|
194
|
+
<Form loading={loading || domainsLoading}>
|
|
195
|
+
<DomainSelector
|
|
196
|
+
action="manageConcept"
|
|
197
|
+
onChange={(_e, { value }) => handleDomainSelected(value)}
|
|
198
|
+
onLoad={(data) => handleDomainsLoaded(data.domains)}
|
|
199
|
+
required
|
|
200
|
+
value={domainId}
|
|
201
|
+
labels
|
|
128
202
|
/>
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
<FormattedMessage id="concepts.header.edit.bulk.info_message" />
|
|
138
|
-
</Header.Content>
|
|
139
|
-
</Header>
|
|
140
|
-
<Form loading={loading || domainsLoading}>
|
|
141
|
-
<DomainSelector
|
|
142
|
-
action="manageConcept"
|
|
143
|
-
onChange={this.handleDomainSelected}
|
|
144
|
-
onLoad={this.handleDomainsLoaded}
|
|
145
|
-
required
|
|
146
|
-
value={domain_id}
|
|
147
|
-
labels
|
|
203
|
+
{templateName && !_.isEmpty(selectedDomain) ? (
|
|
204
|
+
<TemplateLoader
|
|
205
|
+
onChange={handleContentChange}
|
|
206
|
+
templateName={templateName}
|
|
207
|
+
content={content}
|
|
208
|
+
domainId={domainId}
|
|
209
|
+
fieldsToOmit={fieldsToOmit}
|
|
210
|
+
setTemplate={setTemplate}
|
|
148
211
|
/>
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
212
|
+
) : null}
|
|
213
|
+
|
|
214
|
+
<ConfirmModal
|
|
215
|
+
actions={actions(handleSubmit)}
|
|
216
|
+
trigger={
|
|
217
|
+
<Button
|
|
218
|
+
primary
|
|
219
|
+
disabled={isInvalid()}
|
|
220
|
+
content={<FormattedMessage id="actions.save" />}
|
|
155
221
|
/>
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
<FormattedMessage id="bulkUpdate.no.concepts.header" />
|
|
186
|
-
</Message.Header>
|
|
187
|
-
<p>
|
|
188
|
-
<FormattedMessage id="bulkUpdate.no.concepts.body" />
|
|
189
|
-
</p>
|
|
190
|
-
</Message>
|
|
191
|
-
)}
|
|
192
|
-
</Container>
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const mapStateToProps = (
|
|
198
|
-
{
|
|
199
|
-
bulkUpdateLoading,
|
|
200
|
-
templateLoading,
|
|
201
|
-
conceptCount,
|
|
202
|
-
templates,
|
|
203
|
-
template,
|
|
204
|
-
concepts,
|
|
205
|
-
},
|
|
206
|
-
{ applyTemplate } // ownProps only used for testing
|
|
207
|
-
) => {
|
|
208
|
-
const concept = _.head(concepts);
|
|
209
|
-
const templateId =
|
|
210
|
-
templates && concept?.type
|
|
211
|
-
? _.flow(_.find(_.propEq("name", concept.type)), _.prop("id"))(templates)
|
|
212
|
-
: null;
|
|
213
|
-
return {
|
|
214
|
-
loading: templateLoading || bulkUpdateLoading,
|
|
215
|
-
template,
|
|
216
|
-
templateId,
|
|
217
|
-
applyTemplate: applyTemplate || applyTemplateWithoutDefaults(template),
|
|
218
|
-
concepts,
|
|
219
|
-
conceptCount,
|
|
220
|
-
};
|
|
222
|
+
}
|
|
223
|
+
header={
|
|
224
|
+
<FormattedMessage id="concepts.edit.bulk.confirmation.header" />
|
|
225
|
+
}
|
|
226
|
+
content={
|
|
227
|
+
<FormattedMessage
|
|
228
|
+
id="concepts.edit.bulk.confirmation.content"
|
|
229
|
+
values={{ concepts_count: conceptCount }}
|
|
230
|
+
/>
|
|
231
|
+
}
|
|
232
|
+
onConfirm={handleSubmit}
|
|
233
|
+
/>
|
|
234
|
+
<HistoryBackButton
|
|
235
|
+
content={<FormattedMessage id="actions.cancel" />}
|
|
236
|
+
/>
|
|
237
|
+
</Form>
|
|
238
|
+
</>
|
|
239
|
+
) : (
|
|
240
|
+
<Message>
|
|
241
|
+
<Message.Header>
|
|
242
|
+
<FormattedMessage id="bulkUpdate.no.concepts.header" />
|
|
243
|
+
</Message.Header>
|
|
244
|
+
<p>
|
|
245
|
+
<FormattedMessage id="bulkUpdate.no.concepts.body" />
|
|
246
|
+
</p>
|
|
247
|
+
</Message>
|
|
248
|
+
)}
|
|
249
|
+
</Container>
|
|
250
|
+
);
|
|
221
251
|
};
|
|
222
252
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
253
|
+
ConceptsBulkUpdate.propTypes = {
|
|
254
|
+
loading: PropTypes.bool,
|
|
255
|
+
conceptCount: PropTypes.number,
|
|
256
|
+
concepts: PropTypes.array,
|
|
257
|
+
templateName: PropTypes.string,
|
|
258
|
+
bulkUpdate: PropTypes.func,
|
|
259
|
+
fetchConcepts: PropTypes.func,
|
|
260
|
+
conceptPayload: PropTypes.object,
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
const makeMapStateToProps = () => {
|
|
264
|
+
const searchQuerySelector = makeSearchQuerySelector(
|
|
265
|
+
"conceptQuery",
|
|
266
|
+
"conceptActiveFilters"
|
|
267
|
+
);
|
|
268
|
+
const mapStateToProps = (state, props) => {
|
|
269
|
+
const concept = _.head(state.concepts);
|
|
270
|
+
const templateName =
|
|
271
|
+
state.templates && concept?.type
|
|
272
|
+
? _.flow(
|
|
273
|
+
_.find(_.propEq("name", concept.type)),
|
|
274
|
+
_.prop("name")
|
|
275
|
+
)(state.templates)
|
|
276
|
+
: null;
|
|
277
|
+
return {
|
|
278
|
+
conceptPayload: searchQuerySelector(state, props),
|
|
279
|
+
loading: state.templateLoading || state.bulkUpdateLoading,
|
|
280
|
+
templateName,
|
|
281
|
+
concepts: state.concepts,
|
|
282
|
+
conceptCount: state.conceptCount,
|
|
283
|
+
};
|
|
284
|
+
};
|
|
285
|
+
return mapStateToProps;
|
|
286
|
+
};
|
|
287
|
+
export default connect(makeMapStateToProps, { bulkUpdate, fetchConcepts })(
|
|
288
|
+
ConceptsBulkUpdate
|
|
289
|
+
);
|
|
@@ -3,13 +3,16 @@ import React from "react";
|
|
|
3
3
|
import PropTypes from "prop-types";
|
|
4
4
|
import { connect } from "react-redux";
|
|
5
5
|
import { Button, Popup } from "semantic-ui-react";
|
|
6
|
-
import { Link } from "react-router-dom";
|
|
6
|
+
import { Link, useLocation } from "react-router-dom";
|
|
7
7
|
import { FormattedMessage } from "react-intl";
|
|
8
8
|
import { useAuthorized } from "@truedat/core/hooks";
|
|
9
9
|
import { CONCEPTS_BULK_UPDATE } from "@truedat/core/routes";
|
|
10
10
|
|
|
11
11
|
export const ConceptsUpdateButton = ({ updateUrl }) => {
|
|
12
|
+
const { pathname } = useLocation();
|
|
12
13
|
const authorized = useAuthorized();
|
|
14
|
+
const pathNameWithoutSlash = pathname.split("/").pop();
|
|
15
|
+
|
|
13
16
|
return authorized ? (
|
|
14
17
|
<Popup
|
|
15
18
|
content={<FormattedMessage id="concepts.actions.bulk_update.popup" />}
|
|
@@ -20,7 +23,7 @@ export const ConceptsUpdateButton = ({ updateUrl }) => {
|
|
|
20
23
|
<Button
|
|
21
24
|
primary
|
|
22
25
|
as={Link}
|
|
23
|
-
to={updateUrl || ""}
|
|
26
|
+
to={updateUrl + `?${pathNameWithoutSlash}` || ""}
|
|
24
27
|
content={<FormattedMessage id="actions.update" />}
|
|
25
28
|
disabled={_.isEmpty(updateUrl)}
|
|
26
29
|
/>
|
|
@@ -2,25 +2,40 @@ import React from "react";
|
|
|
2
2
|
import { waitFor } from "@testing-library/react";
|
|
3
3
|
import userEvent from "@testing-library/user-event";
|
|
4
4
|
import { render } from "@truedat/test/render";
|
|
5
|
-
import { domainsMock } from "@truedat/test/mocks";
|
|
5
|
+
import { domainsMock, templateByNameMock } from "@truedat/test/mocks";
|
|
6
6
|
import { bulkUpdate } from "../../routines";
|
|
7
7
|
import ConceptsBulkUpdate from "../ConceptsBulkUpdate";
|
|
8
8
|
|
|
9
|
+
jest.mock("react-router-dom", () => ({
|
|
10
|
+
...jest.requireActual("react-router-dom"),
|
|
11
|
+
useLocation: () => ({ search: "?concepts" }),
|
|
12
|
+
}));
|
|
13
|
+
|
|
9
14
|
const content = [
|
|
10
|
-
{
|
|
15
|
+
{
|
|
16
|
+
name: "g1",
|
|
17
|
+
fields: [{ name: "field1", label: "field1", placeholder: "field1" }],
|
|
18
|
+
},
|
|
11
19
|
];
|
|
12
|
-
const template = { name: "
|
|
20
|
+
const template = { name: "template1", id: 1, content: content };
|
|
21
|
+
|
|
13
22
|
const state = {
|
|
14
23
|
conceptCount: 1,
|
|
15
|
-
concepts: [{ type: "
|
|
16
|
-
template,
|
|
24
|
+
concepts: [{ type: "template1" }],
|
|
17
25
|
templates: [template],
|
|
26
|
+
loading: false,
|
|
27
|
+
templateLoading: false,
|
|
28
|
+
bulkUpdateLoading: false,
|
|
29
|
+
domainsLoading: false,
|
|
18
30
|
};
|
|
19
31
|
|
|
20
32
|
const renderOpts = {
|
|
21
|
-
|
|
22
|
-
|
|
33
|
+
mocks: [
|
|
34
|
+
domainsMock({ action: "manageConcept" }),
|
|
35
|
+
templateByNameMock({ name: "template1", domainIds: [1] }),
|
|
36
|
+
],
|
|
23
37
|
state,
|
|
38
|
+
fallback: "lazy",
|
|
24
39
|
};
|
|
25
40
|
|
|
26
41
|
describe("<ConceptsBulkUpdate />", () => {
|
|
@@ -29,23 +44,13 @@ describe("<ConceptsBulkUpdate />", () => {
|
|
|
29
44
|
<ConceptsBulkUpdate />,
|
|
30
45
|
renderOpts
|
|
31
46
|
);
|
|
32
|
-
await waitFor(() => expect(queryByText(/lazy/i)).not.toBeInTheDocument());
|
|
33
|
-
expect(container).toMatchSnapshot();
|
|
34
|
-
});
|
|
35
47
|
|
|
36
|
-
it("calls applyTemplate when selectedDomain changes", async () => {
|
|
37
|
-
const applyTemplate = jest.fn();
|
|
38
|
-
const { findByText, queryByText } = render(
|
|
39
|
-
<ConceptsBulkUpdate applyTemplate={applyTemplate} />,
|
|
40
|
-
renderOpts
|
|
41
|
-
);
|
|
42
48
|
await waitFor(() => expect(queryByText(/lazy/i)).not.toBeInTheDocument());
|
|
43
|
-
await waitFor(() =>
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
expect(applyTemplate).toHaveBeenCalledTimes(2);
|
|
49
|
+
await waitFor(() =>
|
|
50
|
+
expect(queryByText(/loading/i)).not.toBeInTheDocument()
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
expect(container).toMatchSnapshot();
|
|
49
54
|
});
|
|
50
55
|
|
|
51
56
|
it("DynamicForm rendered if template, template_id, selectedDomain informed", async () => {
|
|
@@ -56,7 +61,7 @@ describe("<ConceptsBulkUpdate />", () => {
|
|
|
56
61
|
);
|
|
57
62
|
await waitFor(() => expect(queryByText(/lazy/i)).not.toBeInTheDocument());
|
|
58
63
|
userEvent.click(await findByText("fooDomain"));
|
|
59
|
-
await waitFor(() => expect(queryByText(/
|
|
64
|
+
await waitFor(() => expect(queryByText(/field1/)).toBeInTheDocument());
|
|
60
65
|
});
|
|
61
66
|
|
|
62
67
|
it("calls bulkUpdate on onClick", async () => {
|
|
@@ -70,15 +75,15 @@ describe("<ConceptsBulkUpdate />", () => {
|
|
|
70
75
|
);
|
|
71
76
|
await waitFor(() => expect(queryByText(/lazy/i)).not.toBeInTheDocument());
|
|
72
77
|
userEvent.click(await findByText("fooDomain"));
|
|
73
|
-
await waitFor(() => expect(queryByText(/
|
|
74
|
-
userEvent.type(await findByPlaceholderText("
|
|
78
|
+
await waitFor(() => expect(queryByText(/field1/)).toBeInTheDocument());
|
|
79
|
+
userEvent.type(await findByPlaceholderText("field1"), "abc123456");
|
|
75
80
|
await waitFor(() => expect(queryByText(/Save/)).toBeEnabled());
|
|
76
81
|
userEvent.click(await findByText("Save"));
|
|
77
82
|
userEvent.click(await findByText("Yes"));
|
|
78
83
|
await waitFor(() => {
|
|
79
84
|
expect(dispatch).toHaveBeenLastCalledWith(
|
|
80
85
|
bulkUpdate({
|
|
81
|
-
update_attributes: { content: {
|
|
86
|
+
update_attributes: { content: { field1: "abc123456" }, domain_id: 1 },
|
|
82
87
|
})
|
|
83
88
|
);
|
|
84
89
|
});
|
|
@@ -4,13 +4,18 @@ import { shallow } from "enzyme";
|
|
|
4
4
|
import { ConceptsUpdateButton } from "../ConceptsUpdateButton";
|
|
5
5
|
|
|
6
6
|
jest.mock("@truedat/core/hooks", () => ({
|
|
7
|
-
useAuthorized: jest.fn(() => true)
|
|
7
|
+
useAuthorized: jest.fn(() => true),
|
|
8
|
+
}));
|
|
9
|
+
|
|
10
|
+
jest.mock("react-router-dom", () => ({
|
|
11
|
+
...jest.requireActual("react-router-dom"),
|
|
12
|
+
useLocation: () => ({ pathname: "/concept" }),
|
|
8
13
|
}));
|
|
9
14
|
|
|
10
15
|
describe("<ConceptsUpdateButton />", () => {
|
|
11
16
|
it("button will appear disabled if template is empty", () => {
|
|
12
17
|
const props = {
|
|
13
|
-
updateUrl: ""
|
|
18
|
+
updateUrl: "",
|
|
14
19
|
};
|
|
15
20
|
const wrapper = shallow(<ConceptsUpdateButton {...props} />);
|
|
16
21
|
wrapper.find("Popup").props().content;
|
|
@@ -19,7 +24,7 @@ describe("<ConceptsUpdateButton />", () => {
|
|
|
19
24
|
|
|
20
25
|
it("matches the latest snapshot", () => {
|
|
21
26
|
const props = {
|
|
22
|
-
updateUrl: "url"
|
|
27
|
+
updateUrl: "url",
|
|
23
28
|
};
|
|
24
29
|
const wrapper = shallow(<ConceptsUpdateButton {...props} />);
|
|
25
30
|
expect(wrapper).toMatchSnapshot();
|