@truedat/dq 4.41.3 → 4.42.1
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 +13 -0
- package/package.json +5 -5
- package/src/components/ConditionSummary.js +41 -27
- package/src/components/ImplementationSummary.js +5 -5
- package/src/components/NewRuleImplementation.js +76 -17
- package/src/components/RuleImplementationProperties.js +2 -1
- package/src/components/__test_samples__/NewRuleImplementationProps.js +44 -42
- package/src/components/__tests__/ImplementationSummary.spec.js +4 -4
- package/src/components/__tests__/__snapshots__/ImplementationSummary.spec.js.snap +68 -3
- package/src/components/__tests__/__snapshots__/NewRuleImplementation.spec.js.snap +108 -100
- package/src/components/__tests__/__snapshots__/RuleImplementationProperties.spec.js.snap +1 -1
- package/src/components/ruleImplementationForm/PopulationForm.js +1 -27
- package/src/components/ruleImplementationForm/RuleImplementationForm.js +69 -20
- package/src/components/ruleImplementationForm/RuleImplementationRawForm.js +163 -177
- package/src/components/ruleImplementationForm/__tests__/RuleImplementationRawForm.spec.js +3 -3
- package/src/components/ruleImplementationForm/__tests__/__snapshots__/RuleImplementationForm.spec.js.snap +1 -1
- package/src/components/ruleImplementationForm/__tests__/__snapshots__/RuleImplementationRawForm.spec.js.snap +159 -156
- package/src/messages/en.js +4 -2
- package/src/messages/es.js +3 -1
- package/src/reducers/ruleImplementation.js +1 -1
- package/src/sagas/__tests__/createRuleImplementation.spec.js +12 -10
- package/src/sagas/__tests__/updateRuleImplementation.spec.js +8 -6
|
@@ -5,6 +5,7 @@ import { connect } from "react-redux";
|
|
|
5
5
|
import { useHistory } from "react-router-dom";
|
|
6
6
|
import { FormattedMessage, useIntl } from "react-intl";
|
|
7
7
|
import { Button, Form, Icon, Popup } from "semantic-ui-react";
|
|
8
|
+
import { accentInsensitivePathOrder } from "@truedat/core/services/sort";
|
|
8
9
|
import { validateContent as validDfContent } from "@truedat/df/utils";
|
|
9
10
|
import { selectTemplate } from "@truedat/df/routines";
|
|
10
11
|
import LimitsForm from "./LimitsForm";
|
|
@@ -17,9 +18,7 @@ const Help = ({ message }) => {
|
|
|
17
18
|
trigger={
|
|
18
19
|
<Icon className="rule-form-popup" name="question circle outline" />
|
|
19
20
|
}
|
|
20
|
-
content={formatMessage({
|
|
21
|
-
id: message,
|
|
22
|
-
})}
|
|
21
|
+
content={formatMessage({ id: message })}
|
|
23
22
|
on="click"
|
|
24
23
|
hideOnScroll
|
|
25
24
|
/>
|
|
@@ -38,10 +37,6 @@ const DynamicForm = React.lazy(() =>
|
|
|
38
37
|
import("@truedat/df/components/DynamicForm")
|
|
39
38
|
);
|
|
40
39
|
|
|
41
|
-
const SourcesLoader = React.lazy(() =>
|
|
42
|
-
import("@truedat/cx/sources/components/SourcesLoader")
|
|
43
|
-
);
|
|
44
|
-
|
|
45
40
|
const ImplementationDynamicForm = ({
|
|
46
41
|
ruleImplementation,
|
|
47
42
|
onChange,
|
|
@@ -89,8 +84,9 @@ export const RuleImplementationRawForm = ({
|
|
|
89
84
|
rawContent,
|
|
90
85
|
setImplementationKey,
|
|
91
86
|
setImplementationRawContent,
|
|
92
|
-
sources,
|
|
93
87
|
selectTemplate,
|
|
88
|
+
sources,
|
|
89
|
+
sourcesLoading,
|
|
94
90
|
template = {},
|
|
95
91
|
templates,
|
|
96
92
|
onChange,
|
|
@@ -115,33 +111,29 @@ export const RuleImplementationRawForm = ({
|
|
|
115
111
|
const onChangeImplementation = (prop, value) =>
|
|
116
112
|
setImplementationRawContent({ ...rawContent, [prop]: value });
|
|
117
113
|
|
|
118
|
-
const onChangeSource = (
|
|
114
|
+
const onChangeSource = (value) => {
|
|
119
115
|
setImplementationRawContent({
|
|
120
116
|
...rawContent,
|
|
121
|
-
source_id:
|
|
117
|
+
source_id: value,
|
|
122
118
|
database: "",
|
|
123
119
|
});
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const selectedSourceId = rawContent?.source_id?.toString();
|
|
124
123
|
|
|
125
|
-
const
|
|
126
|
-
_.
|
|
127
|
-
|
|
128
|
-
),
|
|
129
|
-
_.map(({ id, external_id }) => ({
|
|
124
|
+
const sourceOptions = _.flow(
|
|
125
|
+
_.sortBy(accentInsensitivePathOrder("externalId")),
|
|
126
|
+
_.map(({ id, externalId }) => ({
|
|
130
127
|
key: id,
|
|
131
|
-
text: external_id,
|
|
132
128
|
value: id,
|
|
129
|
+
text: externalId,
|
|
133
130
|
}))
|
|
134
131
|
)(sources);
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
const databasesOptions = _.flow(
|
|
132
|
+
const databaseOptions = _.flow(
|
|
138
133
|
_.find({ id: selectedSourceId }),
|
|
139
|
-
_.
|
|
140
|
-
_.
|
|
141
|
-
|
|
142
|
-
text: database,
|
|
143
|
-
value: database,
|
|
144
|
-
}))
|
|
134
|
+
_.path(["config", "databases"]),
|
|
135
|
+
_.sortedUniq,
|
|
136
|
+
_.map((value) => ({ key: value, text: value, value }))
|
|
145
137
|
)(sources);
|
|
146
138
|
|
|
147
139
|
const getBannedWordsAndChars = (text) => {
|
|
@@ -159,7 +151,7 @@ export const RuleImplementationRawForm = ({
|
|
|
159
151
|
return (
|
|
160
152
|
validInformation() &&
|
|
161
153
|
isNotEmptyProp("source_id") &&
|
|
162
|
-
(_.isEmpty(
|
|
154
|
+
(_.isEmpty(databaseOptions) || isNotEmptyProp("database")) &&
|
|
163
155
|
_.every(isNotEmptyProp)(["dataset", "validations"]) &&
|
|
164
156
|
_.every(hasNoErrors)(["dataset", "population", "validations"])
|
|
165
157
|
);
|
|
@@ -193,183 +185,178 @@ export const RuleImplementationRawForm = ({
|
|
|
193
185
|
const errors = getErrors();
|
|
194
186
|
|
|
195
187
|
return (
|
|
196
|
-
|
|
197
|
-
<
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
188
|
+
<Form className="rule">
|
|
189
|
+
<Form.Radio
|
|
190
|
+
checked={ruleImplementation.executable}
|
|
191
|
+
name="executable"
|
|
192
|
+
label={formatMessage({ id: "ruleImplementation.props.executable" })}
|
|
193
|
+
onChange={(_e, { checked }) => onChange("executable", checked)}
|
|
194
|
+
toggle
|
|
195
|
+
/>
|
|
196
|
+
<Form.Field>
|
|
197
|
+
<label>
|
|
198
|
+
{formatMessage({ id: "ruleImplementation.props.name" })}
|
|
199
|
+
<Help message="datasetForm.implementation_key.tooltip" />
|
|
200
|
+
</label>
|
|
201
|
+
<Form.Input
|
|
202
|
+
autoComplete="off"
|
|
203
|
+
name="implementation_key"
|
|
204
|
+
onChange={(_e, { value }) => setImplementationKey(value)}
|
|
205
|
+
placeholder={formatMessage({
|
|
206
|
+
id: "ruleImplementation.props.name.placeholder",
|
|
207
|
+
})}
|
|
208
|
+
required
|
|
209
|
+
value={implementationKey}
|
|
205
210
|
/>
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
name="implementation_key"
|
|
214
|
-
onChange={(_e, { value }) => setImplementationKey(value)}
|
|
215
|
-
placeholder={formatMessage({
|
|
216
|
-
id: "ruleImplementation.props.name.placeholder",
|
|
217
|
-
})}
|
|
218
|
-
required
|
|
219
|
-
value={implementationKey}
|
|
220
|
-
/>
|
|
221
|
-
</Form.Field>
|
|
222
|
-
<LimitsForm
|
|
223
|
-
onChange={onChange}
|
|
211
|
+
</Form.Field>
|
|
212
|
+
<LimitsForm onChange={onChange} ruleImplementation={ruleImplementation} />
|
|
213
|
+
{!_.isEmpty(templates) && (
|
|
214
|
+
<ImplementationDynamicForm
|
|
215
|
+
selectTemplate={selectTemplate}
|
|
216
|
+
template={template}
|
|
217
|
+
templates={templates}
|
|
224
218
|
ruleImplementation={ruleImplementation}
|
|
219
|
+
onChange={onChange}
|
|
225
220
|
/>
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
221
|
+
)}
|
|
222
|
+
<Form.Dropdown
|
|
223
|
+
label={
|
|
224
|
+
<label>
|
|
225
|
+
<FormattedMessage id="ruleImplementationRawForm.props.source" />
|
|
226
|
+
</label>
|
|
227
|
+
}
|
|
228
|
+
loading={sourcesLoading}
|
|
229
|
+
name="source_id"
|
|
230
|
+
onChange={(_e, { value }) => onChangeSource(value)}
|
|
231
|
+
options={sourceOptions}
|
|
232
|
+
placeholder={formatMessage({
|
|
233
|
+
id: "ruleImplementationRawForm.props.source.placeholder",
|
|
234
|
+
})}
|
|
235
|
+
required
|
|
236
|
+
search
|
|
237
|
+
selection
|
|
238
|
+
value={selectedSourceId}
|
|
239
|
+
/>
|
|
240
|
+
{selectedSourceId && !_.isEmpty(databaseOptions) ? (
|
|
235
241
|
<Form.Dropdown
|
|
236
242
|
label={
|
|
237
243
|
<label>
|
|
238
|
-
<FormattedMessage id="ruleImplementationRawForm.props.
|
|
244
|
+
<FormattedMessage id="ruleImplementationRawForm.props.database" />
|
|
239
245
|
</label>
|
|
240
246
|
}
|
|
247
|
+
loading={sourcesLoading}
|
|
248
|
+
name="database"
|
|
241
249
|
placeholder={formatMessage({
|
|
242
|
-
id: "ruleImplementationRawForm.props.
|
|
250
|
+
id: "ruleImplementationRawForm.props.database.placeholder",
|
|
243
251
|
})}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
options={sourcesOptions}
|
|
247
|
-
required
|
|
248
|
-
selection
|
|
249
|
-
value={selectedSourceId}
|
|
250
|
-
/>
|
|
251
|
-
{selectedSourceId && !_.isEmpty(databasesOptions) && (
|
|
252
|
-
<Form.Dropdown
|
|
253
|
-
label={
|
|
254
|
-
<label>
|
|
255
|
-
<FormattedMessage id="ruleImplementationRawForm.props.database" />
|
|
256
|
-
</label>
|
|
257
|
-
}
|
|
258
|
-
name="database"
|
|
259
|
-
placeholder={formatMessage({
|
|
260
|
-
id: "ruleImplementationRawForm.props.database.placeholder",
|
|
261
|
-
})}
|
|
262
|
-
onChange={(_e, { value }) =>
|
|
263
|
-
onChangeImplementation("database", value)
|
|
264
|
-
}
|
|
265
|
-
options={databasesOptions}
|
|
266
|
-
required
|
|
267
|
-
selection
|
|
268
|
-
value={_.prop("database")(rawContent)}
|
|
269
|
-
/>
|
|
270
|
-
)}
|
|
271
|
-
<Form.TextArea
|
|
272
|
-
className="raw"
|
|
273
|
-
error={
|
|
274
|
-
_.path("dataset.hasErrors")(errors) && {
|
|
275
|
-
content: _.path("dataset.errorMessage")(errors),
|
|
276
|
-
}
|
|
252
|
+
onChange={(_e, { value }) =>
|
|
253
|
+
onChangeImplementation("database", value)
|
|
277
254
|
}
|
|
278
|
-
|
|
279
|
-
<label>
|
|
280
|
-
<FormattedMessage id="ruleImplementationRawForm.props.dataset" />
|
|
281
|
-
<Help message="ruleImplementationRawForm.props.dataset.help"></Help>
|
|
282
|
-
</label>
|
|
283
|
-
}
|
|
284
|
-
name="dataset"
|
|
285
|
-
onChange={(e, { value }) => onChangeImplementation("dataset", value)}
|
|
286
|
-
placeholder={formatMessage({
|
|
287
|
-
id: "ruleImplementationRawForm.props.dataset.placeholder",
|
|
288
|
-
})}
|
|
255
|
+
options={databaseOptions}
|
|
289
256
|
required
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
value={_.prop("dataset")(rawContent) || ""}
|
|
293
|
-
/>
|
|
294
|
-
<Form.TextArea
|
|
295
|
-
className="raw"
|
|
296
|
-
error={
|
|
297
|
-
_.path("population.hasErrors")(errors) && {
|
|
298
|
-
content: _.path("population.errorMessage")(errors),
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
label={
|
|
302
|
-
<label>
|
|
303
|
-
<FormattedMessage id="ruleImplementationRawForm.props.population" />
|
|
304
|
-
<Help message="ruleImplementationRawForm.props.population.help"></Help>
|
|
305
|
-
</label>
|
|
306
|
-
}
|
|
307
|
-
name="population"
|
|
308
|
-
onChange={(e, { value }) =>
|
|
309
|
-
onChangeImplementation("population", value)
|
|
310
|
-
}
|
|
311
|
-
placeholder={formatMessage({
|
|
312
|
-
id: "ruleImplementationRawForm.props.population.placeholder",
|
|
313
|
-
})}
|
|
314
|
-
rows={4}
|
|
315
|
-
size="small"
|
|
316
|
-
value={_.prop("population")(rawContent) || ""}
|
|
257
|
+
selection
|
|
258
|
+
value={_.prop("database")(rawContent)}
|
|
317
259
|
/>
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
260
|
+
) : null}
|
|
261
|
+
<Form.TextArea
|
|
262
|
+
className="raw"
|
|
263
|
+
error={
|
|
264
|
+
_.path("dataset.hasErrors")(errors) && {
|
|
265
|
+
content: _.path("dataset.errorMessage")(errors),
|
|
324
266
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
267
|
+
}
|
|
268
|
+
label={
|
|
269
|
+
<label>
|
|
270
|
+
<FormattedMessage id="ruleImplementationRawForm.props.dataset" />
|
|
271
|
+
<Help message="ruleImplementationRawForm.props.dataset.help"></Help>
|
|
272
|
+
</label>
|
|
273
|
+
}
|
|
274
|
+
name="dataset"
|
|
275
|
+
onChange={(e, { value }) => onChangeImplementation("dataset", value)}
|
|
276
|
+
placeholder={formatMessage({
|
|
277
|
+
id: "ruleImplementationRawForm.props.dataset.placeholder",
|
|
278
|
+
})}
|
|
279
|
+
required
|
|
280
|
+
rows={4}
|
|
281
|
+
size="small"
|
|
282
|
+
value={_.prop("dataset")(rawContent) || ""}
|
|
283
|
+
/>
|
|
284
|
+
<Form.TextArea
|
|
285
|
+
className="raw"
|
|
286
|
+
error={
|
|
287
|
+
_.path("population.hasErrors")(errors) && {
|
|
288
|
+
content: _.path("population.errorMessage")(errors),
|
|
330
289
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
290
|
+
}
|
|
291
|
+
label={
|
|
292
|
+
<label>
|
|
293
|
+
<FormattedMessage id="ruleImplementationRawForm.props.population" />
|
|
294
|
+
<Help message="ruleImplementationRawForm.props.population.help"></Help>
|
|
295
|
+
</label>
|
|
296
|
+
}
|
|
297
|
+
name="population"
|
|
298
|
+
onChange={(e, { value }) => onChangeImplementation("population", value)}
|
|
299
|
+
placeholder={formatMessage({
|
|
300
|
+
id: "ruleImplementationRawForm.props.population.placeholder",
|
|
301
|
+
})}
|
|
302
|
+
rows={4}
|
|
303
|
+
size="small"
|
|
304
|
+
value={_.prop("population")(rawContent) || ""}
|
|
305
|
+
/>
|
|
306
|
+
<Form.TextArea
|
|
307
|
+
className="raw"
|
|
308
|
+
error={
|
|
309
|
+
_.path("validations.hasErrors")(errors) && {
|
|
310
|
+
content: _.path("validations.errorMessage")(errors),
|
|
334
311
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
312
|
+
}
|
|
313
|
+
label={
|
|
314
|
+
<label>
|
|
315
|
+
<FormattedMessage id="ruleImplementationRawForm.props.validations" />
|
|
316
|
+
<Help message="ruleImplementationRawForm.props.validations.help"></Help>
|
|
317
|
+
</label>
|
|
318
|
+
}
|
|
319
|
+
name="validations"
|
|
320
|
+
onChange={(e, { value }) =>
|
|
321
|
+
onChangeImplementation("validations", value)
|
|
322
|
+
}
|
|
323
|
+
placeholder={formatMessage({
|
|
324
|
+
id: "ruleImplementationRawForm.props.validations.placeholder",
|
|
325
|
+
})}
|
|
326
|
+
required
|
|
327
|
+
rows={4}
|
|
328
|
+
size="small"
|
|
329
|
+
value={_.prop("validations")(rawContent) || ""}
|
|
330
|
+
/>
|
|
331
|
+
<Form.Button
|
|
332
|
+
floated="right"
|
|
333
|
+
disabled={!isValidForm()}
|
|
334
|
+
type="submit"
|
|
335
|
+
primary
|
|
336
|
+
loading={isSubmitting}
|
|
337
|
+
onClick={() => doSubmit()}
|
|
338
|
+
content={formatMessage({ id: "actions.submit" })}
|
|
339
|
+
/>
|
|
340
|
+
<Button
|
|
341
|
+
content={formatMessage({ id: "actions.cancel" })}
|
|
342
|
+
floated="right"
|
|
343
|
+
onClick={() => doCancel()}
|
|
344
|
+
secondary
|
|
345
|
+
/>
|
|
346
|
+
</Form>
|
|
360
347
|
);
|
|
361
348
|
};
|
|
362
349
|
|
|
363
350
|
RuleImplementationRawForm.propTypes = {
|
|
364
|
-
mode: PropTypes.string,
|
|
365
351
|
handleSubmit: PropTypes.func.isRequired,
|
|
366
352
|
implementationKey: PropTypes.string,
|
|
367
353
|
isSubmitting: PropTypes.bool,
|
|
368
354
|
rawContent: PropTypes.object,
|
|
369
355
|
setImplementationKey: PropTypes.func,
|
|
370
356
|
setImplementationRawContent: PropTypes.func,
|
|
371
|
-
sources: PropTypes.array,
|
|
372
357
|
selectTemplate: PropTypes.func,
|
|
358
|
+
sources: PropTypes.array,
|
|
359
|
+
sourcesLoading: PropTypes.bool,
|
|
373
360
|
template: PropTypes.object,
|
|
374
361
|
templates: PropTypes.object,
|
|
375
362
|
ruleImplementation: PropTypes.object,
|
|
@@ -378,7 +365,6 @@ RuleImplementationRawForm.propTypes = {
|
|
|
378
365
|
|
|
379
366
|
const mapStateToProps = (state) => ({
|
|
380
367
|
isSubmitting: state.ruleImplementationCreating,
|
|
381
|
-
sources: _.get("sources")(state),
|
|
382
368
|
templates: state.templates,
|
|
383
369
|
template: getTemplate(state),
|
|
384
370
|
});
|
|
@@ -18,12 +18,12 @@ describe("<RuleImplementationRawForm />", () => {
|
|
|
18
18
|
const isSubmitting = false;
|
|
19
19
|
const sources = [
|
|
20
20
|
{
|
|
21
|
-
id: 1,
|
|
21
|
+
id: "1",
|
|
22
22
|
config: { alias: "source1", job_types: ["quality"] },
|
|
23
23
|
external_id: "ext_id_1",
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
|
-
id: 2,
|
|
26
|
+
id: "2",
|
|
27
27
|
config: {
|
|
28
28
|
alias: "source2",
|
|
29
29
|
job_types: ["quality"],
|
|
@@ -31,7 +31,7 @@ describe("<RuleImplementationRawForm />", () => {
|
|
|
31
31
|
},
|
|
32
32
|
external_id: "ext_id_2",
|
|
33
33
|
},
|
|
34
|
-
{ id: 3, config: {}, external_id: "ext_id_3" },
|
|
34
|
+
{ id: "3", config: {}, external_id: "ext_id_3" },
|
|
35
35
|
];
|
|
36
36
|
const setImplementationRawContent = jest.fn();
|
|
37
37
|
|