@truedat/dq 4.47.4 → 4.47.7
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 +16 -1
- package/package.json +5 -5
- package/src/api/queries.js +5 -0
- package/src/components/ConditionSummary.js +63 -21
- package/src/components/NewRuleImplementation.js +21 -46
- package/src/components/RuleImplementationResults.js +5 -3
- package/src/components/__test_samples__/newRuleImplementationHelper.js +1239 -0
- package/src/components/__tests__/NewRuleImplementation.spec.js +273 -6
- package/src/components/ruleImplementationForm/FiltersField.js +31 -11
- package/src/components/ruleImplementationForm/FiltersFormGroup.js +1 -1
- package/src/components/ruleImplementationForm/FiltersGrid.js +18 -6
- package/src/components/ruleImplementationForm/FiltersGroup.js +3 -3
- package/src/components/ruleImplementationForm/InformationForm.js +2 -0
- package/src/components/ruleImplementationForm/RuleImplementationForm.js +1 -1
- package/src/components/ruleImplementationForm/RuleImplementationRawForm.js +30 -1
- package/src/components/ruleImplementationForm/__tests__/RuleImplementationRawForm.spec.js +24 -24
- package/src/components/ruleImplementationForm/__tests__/__snapshots__/FiltersFormGroup.spec.js.snap +7 -1
- package/src/components/ruleImplementationForm/__tests__/__snapshots__/FiltersGroup.spec.js.snap +8 -1
- package/src/components/ruleImplementationForm/__tests__/__snapshots__/RuleImplementationRawForm.spec.js.snap +67 -0
- package/src/components/ruleImplementationForm/__tests__/__snapshots__/ValueConditions.spec.js.snap +7 -1
- package/src/messages/en.js +2 -1
- package/src/messages/es.js +2 -1
- package/src/selectors/getRuleImplementationOperators.js +1 -0
|
@@ -1,20 +1,29 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
1
2
|
import React from "react";
|
|
2
|
-
import { waitFor } from "@testing-library/react";
|
|
3
|
+
import { waitFor, within } from "@testing-library/react";
|
|
3
4
|
import { render } from "@truedat/test/render";
|
|
4
5
|
import { multipleTemplatesMock } from "@truedat/test/mocks";
|
|
5
|
-
import
|
|
6
|
+
import userEvent from "@testing-library/user-event";
|
|
7
|
+
import defaultMessages from "@truedat/test/messages";
|
|
8
|
+
import NewRuleImplementation, {
|
|
9
|
+
NewRuleImplementation as NewRuleImplementationComponent,
|
|
10
|
+
} from "../NewRuleImplementation";
|
|
6
11
|
import { newRuleImplementationProps } from "../__test_samples__/NewRuleImplementationProps";
|
|
12
|
+
import {
|
|
13
|
+
ruleImplementationLoaderGlobalState,
|
|
14
|
+
ruleImplementationLoaderActions,
|
|
15
|
+
} from "../__test_samples__/newRuleImplementationHelper";
|
|
7
16
|
|
|
8
17
|
describe("<NewRuleImplementation />", () => {
|
|
9
18
|
const createRuleImplementation = jest.fn();
|
|
10
19
|
const updateRuleImplementation = jest.fn();
|
|
11
|
-
|
|
20
|
+
|
|
12
21
|
const ruleImplementationProps = { id: 1, name: "nn", executable: true };
|
|
22
|
+
|
|
13
23
|
const props = {
|
|
14
24
|
ruleImplementationProps,
|
|
15
25
|
createRuleImplementation,
|
|
16
26
|
updateRuleImplementation,
|
|
17
|
-
sources,
|
|
18
27
|
};
|
|
19
28
|
const renderOpts = {
|
|
20
29
|
mocks: [
|
|
@@ -32,11 +41,11 @@ describe("<NewRuleImplementation />", () => {
|
|
|
32
41
|
<NewRuleImplementation {...props} />,
|
|
33
42
|
renderOpts
|
|
34
43
|
);
|
|
44
|
+
|
|
35
45
|
await waitFor(() => expect(queryByText(/lazy/i)).not.toBeInTheDocument());
|
|
36
46
|
await waitFor(() =>
|
|
37
47
|
expect(queryByText(/loading/i)).not.toBeInTheDocument()
|
|
38
48
|
);
|
|
39
|
-
|
|
40
49
|
expect(container).toMatchSnapshot();
|
|
41
50
|
});
|
|
42
51
|
|
|
@@ -47,7 +56,7 @@ describe("<NewRuleImplementation />", () => {
|
|
|
47
56
|
applyTemplate: applyTemplate,
|
|
48
57
|
};
|
|
49
58
|
const { container, queryByText } = render(
|
|
50
|
-
<
|
|
59
|
+
<NewRuleImplementationComponent {...props} />,
|
|
51
60
|
renderOpts
|
|
52
61
|
);
|
|
53
62
|
await waitFor(() => expect(queryByText(/lazy/i)).not.toBeInTheDocument());
|
|
@@ -57,3 +66,261 @@ describe("<NewRuleImplementation />", () => {
|
|
|
57
66
|
expect(container).toMatchSnapshot();
|
|
58
67
|
});
|
|
59
68
|
});
|
|
69
|
+
|
|
70
|
+
describe("<NewRuleImplementation> NewRuleImplementation doSubmit", () => {
|
|
71
|
+
const dispatch = jest.fn();
|
|
72
|
+
|
|
73
|
+
const renderOptsImplementationEdit = {
|
|
74
|
+
mocks: [
|
|
75
|
+
multipleTemplatesMock({
|
|
76
|
+
scope: "ri",
|
|
77
|
+
domainIds: [2],
|
|
78
|
+
}),
|
|
79
|
+
],
|
|
80
|
+
messages: {
|
|
81
|
+
en: {
|
|
82
|
+
...defaultMessages.en,
|
|
83
|
+
// This is in td-web
|
|
84
|
+
"filtersGrid.field.modifier.cast_as_date": "Cast as date",
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
state: ruleImplementationLoaderGlobalState,
|
|
88
|
+
fallback: "lazy",
|
|
89
|
+
dispatch,
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const props = {
|
|
93
|
+
...ruleImplementationLoaderActions,
|
|
94
|
+
edition: true,
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const expectedRuleImplementationBase = {
|
|
98
|
+
dataset: [
|
|
99
|
+
{
|
|
100
|
+
alias: { index: 4, text: null },
|
|
101
|
+
clauses: [],
|
|
102
|
+
structure: { id: 11127104 },
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
df_content: {},
|
|
106
|
+
df_name: "template1",
|
|
107
|
+
domain_id: 2,
|
|
108
|
+
executable: true,
|
|
109
|
+
goal: 90,
|
|
110
|
+
id: 1329 + 1,
|
|
111
|
+
implementation_key: "oracle_prueba",
|
|
112
|
+
implementation_type: "default",
|
|
113
|
+
minimum: 80,
|
|
114
|
+
populations: [],
|
|
115
|
+
result_type: "percentage",
|
|
116
|
+
rule_id: undefined,
|
|
117
|
+
segments: [],
|
|
118
|
+
status: undefined,
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
it("doSubmit: is empty operator", async () => {
|
|
122
|
+
const expectedRuleImplementation = {
|
|
123
|
+
...expectedRuleImplementationBase,
|
|
124
|
+
validations: [
|
|
125
|
+
{
|
|
126
|
+
modifier: null,
|
|
127
|
+
operator: { name: "empty" },
|
|
128
|
+
population: [],
|
|
129
|
+
structure: { id: 11127109, parent_index: 4 },
|
|
130
|
+
value: [],
|
|
131
|
+
value_modifier: [],
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const { queryByText, getByRole, findByRole, findByTestId } = render(
|
|
137
|
+
<NewRuleImplementation {...props} />,
|
|
138
|
+
renderOptsImplementationEdit
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
// Information Form
|
|
142
|
+
|
|
143
|
+
await waitFor(() => {
|
|
144
|
+
expect(queryByText(/Template/)).toBeTruthy();
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
userEvent.click(await findByRole("option", { name: "template1" }));
|
|
148
|
+
|
|
149
|
+
await waitFor(() => {
|
|
150
|
+
expect(getByRole("button", { name: "Next" })).toBeEnabled();
|
|
151
|
+
});
|
|
152
|
+
userEvent.click(await getByRole("button", { name: "Next" }));
|
|
153
|
+
|
|
154
|
+
// Dataset Form
|
|
155
|
+
|
|
156
|
+
await waitFor(() => {
|
|
157
|
+
expect(getByRole("button", { name: "Next" })).toBeEnabled();
|
|
158
|
+
});
|
|
159
|
+
userEvent.click(await getByRole("button", { name: "Next" }));
|
|
160
|
+
|
|
161
|
+
// Population Form
|
|
162
|
+
|
|
163
|
+
await waitFor(() => {
|
|
164
|
+
expect(getByRole("button", { name: "Next" })).toBeEnabled();
|
|
165
|
+
});
|
|
166
|
+
userEvent.click(await getByRole("button", { name: "Next" }));
|
|
167
|
+
|
|
168
|
+
// Validations Form
|
|
169
|
+
|
|
170
|
+
userEvent.click(await findByRole("button", { name: "add-condition-row" }));
|
|
171
|
+
|
|
172
|
+
const row = await findByTestId("row-0");
|
|
173
|
+
|
|
174
|
+
const field = row.querySelector('div[label="Field"]');
|
|
175
|
+
const operator = row.querySelector('div[label="Operator"]');
|
|
176
|
+
|
|
177
|
+
userEvent.click(field);
|
|
178
|
+
const fieldOptions = await within(field).findByRole("listbox");
|
|
179
|
+
const emailFieldOption = within(fieldOptions).getByText("EMAIL");
|
|
180
|
+
userEvent.click(emailFieldOption);
|
|
181
|
+
const selectedField = fieldOptions.querySelector(".selected>span");
|
|
182
|
+
expect(within(selectedField).queryByText(/EMAIL/)).toBeInTheDocument();
|
|
183
|
+
|
|
184
|
+
userEvent.click(operator);
|
|
185
|
+
const operatorOptions = await within(operator).findByRole("listbox");
|
|
186
|
+
const emptyOperatorOption = within(operatorOptions).getByText("is empty");
|
|
187
|
+
userEvent.click(emptyOperatorOption);
|
|
188
|
+
const selectedOperator = operatorOptions.querySelector(".selected>span");
|
|
189
|
+
expect(
|
|
190
|
+
within(selectedOperator).queryByText(/is empty/)
|
|
191
|
+
).toBeInTheDocument();
|
|
192
|
+
|
|
193
|
+
await waitFor(() => {
|
|
194
|
+
expect(getByRole("button", { name: "Save" })).toBeEnabled();
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
userEvent.click(await getByRole("button", { name: "Save" }));
|
|
198
|
+
|
|
199
|
+
expect(dispatch).toHaveBeenCalledWith({
|
|
200
|
+
...ruleImplementationLoaderActions.updateRuleImplementation(),
|
|
201
|
+
payload: { rule_implementation: expectedRuleImplementation },
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("doSubmit: unique across fields operator", async () => {
|
|
206
|
+
const expectedRuleImplementation = {
|
|
207
|
+
...expectedRuleImplementationBase,
|
|
208
|
+
validations: [
|
|
209
|
+
{
|
|
210
|
+
modifier: null,
|
|
211
|
+
operator: { name: "unique", value_type: "field_list" },
|
|
212
|
+
population: [],
|
|
213
|
+
structure: { id: 11127109, parent_index: 4 },
|
|
214
|
+
value: [
|
|
215
|
+
{
|
|
216
|
+
fields: [
|
|
217
|
+
{
|
|
218
|
+
id: 11127109,
|
|
219
|
+
name: "EMAIL",
|
|
220
|
+
parent_index: 4,
|
|
221
|
+
path: undefined,
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
id: 11127116,
|
|
225
|
+
name: "PHONE_NUMBER",
|
|
226
|
+
parent_index: 4,
|
|
227
|
+
path: undefined,
|
|
228
|
+
},
|
|
229
|
+
],
|
|
230
|
+
},
|
|
231
|
+
],
|
|
232
|
+
value_modifier: [],
|
|
233
|
+
},
|
|
234
|
+
],
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
const { queryByText, getByRole, findByRole, findByTestId } = render(
|
|
238
|
+
<NewRuleImplementation {...props} />,
|
|
239
|
+
renderOptsImplementationEdit
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
// Information Form
|
|
243
|
+
|
|
244
|
+
await waitFor(() => {
|
|
245
|
+
expect(queryByText(/Template/)).toBeTruthy();
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
userEvent.click(await findByRole("option", { name: "template1" }));
|
|
249
|
+
|
|
250
|
+
await waitFor(() => {
|
|
251
|
+
expect(getByRole("button", { name: "Next" })).toBeEnabled();
|
|
252
|
+
});
|
|
253
|
+
userEvent.click(await getByRole("button", { name: "Next" }));
|
|
254
|
+
|
|
255
|
+
// Dataset Form
|
|
256
|
+
|
|
257
|
+
await waitFor(() => {
|
|
258
|
+
expect(getByRole("button", { name: "Next" })).toBeEnabled();
|
|
259
|
+
});
|
|
260
|
+
userEvent.click(await getByRole("button", { name: "Next" }));
|
|
261
|
+
|
|
262
|
+
// Population Form
|
|
263
|
+
|
|
264
|
+
await waitFor(() => {
|
|
265
|
+
expect(getByRole("button", { name: "Next" })).toBeEnabled();
|
|
266
|
+
});
|
|
267
|
+
userEvent.click(await getByRole("button", { name: "Next" }));
|
|
268
|
+
|
|
269
|
+
// Validations Form
|
|
270
|
+
|
|
271
|
+
userEvent.click(await findByRole("button", { name: "add-condition-row" }));
|
|
272
|
+
|
|
273
|
+
const row = await findByTestId("row-0");
|
|
274
|
+
|
|
275
|
+
const field = row.querySelector('div[label="Field"]');
|
|
276
|
+
const operator = row.querySelector('div[label="Operator"]');
|
|
277
|
+
|
|
278
|
+
userEvent.click(field);
|
|
279
|
+
const fieldOptions = await within(field).findByRole("listbox");
|
|
280
|
+
const emailFieldOption = within(fieldOptions).getByText("EMAIL");
|
|
281
|
+
userEvent.click(emailFieldOption);
|
|
282
|
+
const selectedField = fieldOptions.querySelector(".selected>span");
|
|
283
|
+
expect(within(selectedField).queryByText(/EMAIL/)).toBeInTheDocument();
|
|
284
|
+
|
|
285
|
+
userEvent.click(operator);
|
|
286
|
+
const operatorOptions = await within(operator).findByRole("listbox");
|
|
287
|
+
const uniqueAcrossFieldsOperatorOption = within(operatorOptions).getByText(
|
|
288
|
+
"unique across fields"
|
|
289
|
+
);
|
|
290
|
+
userEvent.click(uniqueAcrossFieldsOperatorOption);
|
|
291
|
+
const selectedOperator = operatorOptions.querySelector(".selected>span");
|
|
292
|
+
expect(
|
|
293
|
+
within(selectedOperator).queryByText(/unique across fields/)
|
|
294
|
+
).toBeInTheDocument();
|
|
295
|
+
|
|
296
|
+
const updatedRow = await findByTestId("row-0");
|
|
297
|
+
const value = updatedRow.querySelector('div[label="Value"]');
|
|
298
|
+
userEvent.click(value);
|
|
299
|
+
const valueOptions = await within(value).findByRole("listbox");
|
|
300
|
+
const valueEmailFieldOption = within(valueOptions).getByText("EMAIL");
|
|
301
|
+
const valuePhoneNumberFieldOption =
|
|
302
|
+
within(valueOptions).getByText("PHONE_NUMBER");
|
|
303
|
+
|
|
304
|
+
userEvent.click(valueEmailFieldOption);
|
|
305
|
+
userEvent.click(valuePhoneNumberFieldOption);
|
|
306
|
+
const selectedFieldValues = updatedRow.querySelectorAll(".label");
|
|
307
|
+
|
|
308
|
+
const selectedFieldTexts = [...selectedFieldValues].map(
|
|
309
|
+
(selectedFieldValue) => selectedFieldValue.text
|
|
310
|
+
);
|
|
311
|
+
|
|
312
|
+
expect(_.difference(selectedFieldTexts, ["EMAIL", "PHONE_NUMBER"])).toEqual(
|
|
313
|
+
[]
|
|
314
|
+
);
|
|
315
|
+
|
|
316
|
+
await waitFor(() => {
|
|
317
|
+
expect(getByRole("button", { name: "Save" })).toBeEnabled();
|
|
318
|
+
});
|
|
319
|
+
userEvent.click(await getByRole("button", { name: "Save" }));
|
|
320
|
+
|
|
321
|
+
expect(dispatch).toHaveBeenCalledWith({
|
|
322
|
+
...ruleImplementationLoaderActions.updateRuleImplementation(),
|
|
323
|
+
payload: { rule_implementation: expectedRuleImplementation },
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
});
|
|
@@ -48,6 +48,19 @@ export const FiltersField = ({
|
|
|
48
48
|
const { value_type, value_type_filter, fixed_values } = operator;
|
|
49
49
|
|
|
50
50
|
const modifierDef = _.find({ name: modifier?.name })(typeCastModifiers);
|
|
51
|
+
const pickFromValue = _.pick(["data_structure_id", "name", "parent_index"]);
|
|
52
|
+
|
|
53
|
+
const getVal = (value) =>
|
|
54
|
+
_.isNil(_.prop("parent_index")(value))
|
|
55
|
+
? _.prop("id")(value)
|
|
56
|
+
: `${_.prop("id")(value)}/${_.prop("parent_index")(value)}`;
|
|
57
|
+
|
|
58
|
+
const getValue = (valueOrValues, operator) =>
|
|
59
|
+
operator?.value_type === "field_list"
|
|
60
|
+
? (valueOrValues?.fields || []).map((v) => {
|
|
61
|
+
return getVal(v);
|
|
62
|
+
})
|
|
63
|
+
: getVal(valueOrValues);
|
|
51
64
|
|
|
52
65
|
switch (value_type) {
|
|
53
66
|
case "string":
|
|
@@ -89,6 +102,7 @@ export const FiltersField = ({
|
|
|
89
102
|
case "timestamp":
|
|
90
103
|
return <DateTimeField label={label} value={value} onChange={onChange} />;
|
|
91
104
|
case "field":
|
|
105
|
+
case "field_list":
|
|
92
106
|
const structureFields = getStructureFields(parentStructures);
|
|
93
107
|
return value_type_filter == "any" ? (
|
|
94
108
|
<StructureSelectorInputField
|
|
@@ -111,24 +125,30 @@ export const FiltersField = ({
|
|
|
111
125
|
) : (
|
|
112
126
|
<>
|
|
113
127
|
<StructureFieldsDropdown
|
|
128
|
+
multiple={value_type === "field_list"}
|
|
114
129
|
label={label}
|
|
115
130
|
inline={false}
|
|
116
131
|
parentStructures={parentStructures}
|
|
117
132
|
structureFields={structureFields}
|
|
118
133
|
typeCastModifiers={typeCastModifiers}
|
|
119
|
-
filters={
|
|
120
|
-
|
|
134
|
+
filters={
|
|
135
|
+
value_type === "field_list" ? null : { field_type: [fieldType] }
|
|
136
|
+
}
|
|
137
|
+
onSelectField={(value, modifier) => {
|
|
121
138
|
onChange(
|
|
122
139
|
null,
|
|
123
|
-
|
|
140
|
+
pickFromValue(value),
|
|
124
141
|
modifier ? { name: modifier.name } : null
|
|
125
|
-
)
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
142
|
+
);
|
|
143
|
+
}}
|
|
144
|
+
onSelectFields={(values) => {
|
|
145
|
+
onChange(
|
|
146
|
+
null,
|
|
147
|
+
values.map((value) => pickFromValue(value)),
|
|
148
|
+
null
|
|
149
|
+
);
|
|
150
|
+
}}
|
|
151
|
+
value={getValue(value, operator)}
|
|
132
152
|
/>
|
|
133
153
|
{modifier && (
|
|
134
154
|
<FieldModifier
|
|
@@ -158,7 +178,7 @@ FiltersField.propTypes = {
|
|
|
158
178
|
parentStructures: PropTypes.array,
|
|
159
179
|
operator: PropTypes.object,
|
|
160
180
|
fieldType: PropTypes.string,
|
|
161
|
-
value: PropTypes.string,
|
|
181
|
+
value: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
|
162
182
|
name: PropTypes.string,
|
|
163
183
|
onChange: PropTypes.func,
|
|
164
184
|
modifier: PropTypes.object,
|
|
@@ -56,13 +56,21 @@ export const FiltersGrid = ({
|
|
|
56
56
|
});
|
|
57
57
|
};
|
|
58
58
|
|
|
59
|
+
const composeFieldValue = (value) => ({
|
|
60
|
+
id: value.data_structure_id || value.id,
|
|
61
|
+
name: value.name,
|
|
62
|
+
path: value.path,
|
|
63
|
+
parent_index: value.parent_index,
|
|
64
|
+
});
|
|
65
|
+
|
|
59
66
|
const composeValue = (value_type, value) => {
|
|
60
67
|
if (value_type == "field") {
|
|
68
|
+
return composeFieldValue(value);
|
|
69
|
+
} else if (value_type === "field_list") {
|
|
61
70
|
return {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
parent_index: value.parent_index,
|
|
71
|
+
fields: _.map((v) => {
|
|
72
|
+
return composeFieldValue(v);
|
|
73
|
+
})(value),
|
|
66
74
|
};
|
|
67
75
|
} else {
|
|
68
76
|
return { raw: value };
|
|
@@ -151,7 +159,11 @@ export const FiltersGrid = ({
|
|
|
151
159
|
scope={scope}
|
|
152
160
|
/>
|
|
153
161
|
</Grid>
|
|
154
|
-
<Button
|
|
162
|
+
<Button
|
|
163
|
+
aria-label="add-condition-row"
|
|
164
|
+
onClick={onRowAddition}
|
|
165
|
+
icon="plus circle"
|
|
166
|
+
/>
|
|
155
167
|
</>
|
|
156
168
|
);
|
|
157
169
|
};
|
|
@@ -161,7 +173,7 @@ FiltersGrid.propTypes = {
|
|
|
161
173
|
setRowValue: PropTypes.func,
|
|
162
174
|
scope: PropTypes.string,
|
|
163
175
|
structures: PropTypes.array,
|
|
164
|
-
typeOperators: PropTypes.
|
|
176
|
+
typeOperators: PropTypes.object,
|
|
165
177
|
};
|
|
166
178
|
|
|
167
179
|
export default FiltersGrid;
|
|
@@ -50,7 +50,7 @@ const Filter = ({
|
|
|
50
50
|
_.filter((v) => !_.isNil(v?.id))(row?.value || []);
|
|
51
51
|
return (
|
|
52
52
|
<>
|
|
53
|
-
<Grid.Row>
|
|
53
|
+
<Grid.Row data-testid={`row-${index}`}>
|
|
54
54
|
<Grid.Column width={14}>
|
|
55
55
|
<FiltersFormGroup
|
|
56
56
|
clause={clause}
|
|
@@ -126,7 +126,7 @@ const Filter = ({
|
|
|
126
126
|
Filter.propTypes = {
|
|
127
127
|
activeConditionIndex: PropTypes.number,
|
|
128
128
|
allOperators: PropTypes.array,
|
|
129
|
-
operators: PropTypes.
|
|
129
|
+
operators: PropTypes.object,
|
|
130
130
|
clause: PropTypes.object,
|
|
131
131
|
composeValue: PropTypes.func,
|
|
132
132
|
onConditionChange: PropTypes.func,
|
|
@@ -182,7 +182,7 @@ export const FiltersGroup = ({
|
|
|
182
182
|
FiltersGroup.propTypes = {
|
|
183
183
|
activeConditionIndex: PropTypes.number,
|
|
184
184
|
allOperators: PropTypes.array,
|
|
185
|
-
operators: PropTypes.
|
|
185
|
+
operators: PropTypes.object,
|
|
186
186
|
composeValue: PropTypes.func,
|
|
187
187
|
onConditionChange: PropTypes.func,
|
|
188
188
|
onOperatorChange: PropTypes.func,
|
|
@@ -25,6 +25,7 @@ export const InformationForm = ({
|
|
|
25
25
|
|
|
26
26
|
const handleContentChange = ({ content, valid }) => {
|
|
27
27
|
onChange("dfContent", content);
|
|
28
|
+
|
|
28
29
|
setIsValid(_.isEmpty(valid));
|
|
29
30
|
};
|
|
30
31
|
const domainId = ruleImplementation?.domain_id || rule?.domain_id;
|
|
@@ -64,6 +65,7 @@ export const InformationForm = ({
|
|
|
64
65
|
autoComplete="off"
|
|
65
66
|
/>
|
|
66
67
|
</Form.Field>
|
|
68
|
+
|
|
67
69
|
{_.isEmpty(rule) && !ruleImplementation?.rule_id ? (
|
|
68
70
|
<Form.Field>
|
|
69
71
|
<DomainDropdownSelector
|
|
@@ -350,7 +350,7 @@ RuleImplementationForm.propTypes = {
|
|
|
350
350
|
addSegments: PropTypes.func,
|
|
351
351
|
authManageSegments: PropTypes.bool,
|
|
352
352
|
isAdmin: PropTypes.bool,
|
|
353
|
-
isSubmitting: PropTypes.bool
|
|
353
|
+
isSubmitting: PropTypes.bool,
|
|
354
354
|
onChange: PropTypes.func,
|
|
355
355
|
onSubmit: PropTypes.func.isRequired,
|
|
356
356
|
operators: PropTypes.object,
|
|
@@ -4,6 +4,8 @@ import PropTypes from "prop-types";
|
|
|
4
4
|
import { connect } from "react-redux";
|
|
5
5
|
import { useHistory } from "react-router-dom";
|
|
6
6
|
import { FormattedMessage, useIntl } from "react-intl";
|
|
7
|
+
import { gql, useQuery } from "@apollo/client";
|
|
8
|
+
import { Loading } from "@truedat/core/components";
|
|
7
9
|
import { Button, Form, Icon, Popup } from "semantic-ui-react";
|
|
8
10
|
import { accentInsensitivePathOrder } from "@truedat/core/services/sort";
|
|
9
11
|
import LimitsForm from "./LimitsForm";
|
|
@@ -80,6 +82,7 @@ export const RuleImplementationRawForm = ({
|
|
|
80
82
|
setImplementationRawContent({
|
|
81
83
|
...rawContent,
|
|
82
84
|
source_id: value,
|
|
85
|
+
source: _.find({ id: value })(sources),
|
|
83
86
|
database: "",
|
|
84
87
|
});
|
|
85
88
|
};
|
|
@@ -334,6 +337,32 @@ RuleImplementationRawForm.propTypes = {
|
|
|
334
337
|
sourcesLoading: PropTypes.bool,
|
|
335
338
|
};
|
|
336
339
|
|
|
340
|
+
export const SOURCES_WITH_CONFIG = gql`
|
|
341
|
+
query SOURCES_WITH_CONFIG($jobTypes: String) {
|
|
342
|
+
sources(jobTypes: $jobTypes) {
|
|
343
|
+
id
|
|
344
|
+
externalId
|
|
345
|
+
config
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
`;
|
|
349
|
+
|
|
350
|
+
export const RuleImplementationRawFormLoader = (props) => {
|
|
351
|
+
const { data, error, loading } = useQuery(SOURCES_WITH_CONFIG, {
|
|
352
|
+
variables: { jobTypes: "quality" },
|
|
353
|
+
});
|
|
354
|
+
if (error) return null;
|
|
355
|
+
if (loading) return <Loading />;
|
|
356
|
+
const sources = data?.sources || [];
|
|
357
|
+
return (
|
|
358
|
+
<RuleImplementationRawForm
|
|
359
|
+
sources={sources}
|
|
360
|
+
sourcesLoading={loading}
|
|
361
|
+
{...props}
|
|
362
|
+
/>
|
|
363
|
+
);
|
|
364
|
+
};
|
|
365
|
+
|
|
337
366
|
const mapStateToProps = ({
|
|
338
367
|
implementationActions,
|
|
339
368
|
rule,
|
|
@@ -344,4 +373,4 @@ const mapStateToProps = ({
|
|
|
344
373
|
rule,
|
|
345
374
|
});
|
|
346
375
|
|
|
347
|
-
export default connect(mapStateToProps)(
|
|
376
|
+
export default connect(mapStateToProps)(RuleImplementationRawFormLoader);
|
|
@@ -4,7 +4,7 @@ import { waitFor } from "@testing-library/react";
|
|
|
4
4
|
import userEvent from "@testing-library/user-event";
|
|
5
5
|
import { render } from "@truedat/test/render";
|
|
6
6
|
import { multipleTemplatesMock } from "@truedat/test/mocks";
|
|
7
|
-
import RuleImplementationRawForm from "../RuleImplementationRawForm";
|
|
7
|
+
import { RuleImplementationRawForm } from "../RuleImplementationRawForm";
|
|
8
8
|
|
|
9
9
|
jest.setTimeout(30000);
|
|
10
10
|
|
|
@@ -13,6 +13,7 @@ const renderOpts = {
|
|
|
13
13
|
state: {
|
|
14
14
|
rule: { domain_id: 1 },
|
|
15
15
|
ruleImplementationCreating: false,
|
|
16
|
+
domains: [{ id: 1, name: "domain1" }],
|
|
16
17
|
},
|
|
17
18
|
fallback: "lazy",
|
|
18
19
|
};
|
|
@@ -35,6 +36,7 @@ const props = {
|
|
|
35
36
|
minimum: "1",
|
|
36
37
|
result_type: "percentage",
|
|
37
38
|
},
|
|
39
|
+
sourcesLoading: false,
|
|
38
40
|
sources: [
|
|
39
41
|
{
|
|
40
42
|
id: "1",
|
|
@@ -56,8 +58,11 @@ const props = {
|
|
|
56
58
|
|
|
57
59
|
describe("<RuleImplementationRawForm />", () => {
|
|
58
60
|
it("matches the latest snapshot", async () => {
|
|
61
|
+
const updatedProps = _.flow(_.set("ruleImplementation.domain_id", 1))(
|
|
62
|
+
props
|
|
63
|
+
);
|
|
59
64
|
const { container, queryByText } = render(
|
|
60
|
-
<RuleImplementationRawForm {...
|
|
65
|
+
<RuleImplementationRawForm {...updatedProps} />,
|
|
61
66
|
renderOpts
|
|
62
67
|
);
|
|
63
68
|
await waitFor(() => expect(queryByText(/lazy/i)).not.toBeInTheDocument(), {
|
|
@@ -141,6 +146,7 @@ describe("<RuleImplementationRawForm />", () => {
|
|
|
141
146
|
|
|
142
147
|
it("submit button enabled if there is valid content in form with database", async () => {
|
|
143
148
|
const updatedProps = _.flow(
|
|
149
|
+
_.set("ruleImplementation.domain_id", 1),
|
|
144
150
|
_.set("ruleImplementation.dfName", "template1"),
|
|
145
151
|
_.set("ruleImplementation.dfContent", { field1: "foo" })
|
|
146
152
|
)(props);
|
|
@@ -156,13 +162,11 @@ describe("<RuleImplementationRawForm />", () => {
|
|
|
156
162
|
rule: { id: 5, name: "regla" },
|
|
157
163
|
};
|
|
158
164
|
|
|
159
|
-
const {
|
|
165
|
+
const { findByRole } = render(
|
|
160
166
|
<RuleImplementationRawForm {...customProps} />,
|
|
161
167
|
renderOpts
|
|
162
168
|
);
|
|
163
|
-
await
|
|
164
|
-
expect(queryByRole("button", { name: /save/i })).toBeEnabled()
|
|
165
|
-
);
|
|
169
|
+
expect(await findByRole("button", { name: /save/i })).toBeEnabled();
|
|
166
170
|
});
|
|
167
171
|
|
|
168
172
|
it("submit button disabled if databases are available and not selected", async () => {
|
|
@@ -176,14 +180,10 @@ describe("<RuleImplementationRawForm />", () => {
|
|
|
176
180
|
},
|
|
177
181
|
};
|
|
178
182
|
|
|
179
|
-
const {
|
|
183
|
+
const { getByRole } = render(
|
|
180
184
|
<RuleImplementationRawForm {...customProps} />,
|
|
181
185
|
renderOpts
|
|
182
186
|
);
|
|
183
|
-
await waitFor(() => expect(queryByText(/lazy/i)).not.toBeInTheDocument());
|
|
184
|
-
await waitFor(() =>
|
|
185
|
-
expect(queryByText(/loading/i)).not.toBeInTheDocument()
|
|
186
|
-
);
|
|
187
187
|
expect(getByRole("button", { name: "Save" })).toBeDisabled();
|
|
188
188
|
});
|
|
189
189
|
|
|
@@ -221,6 +221,15 @@ describe("<RuleImplementationRawForm />", () => {
|
|
|
221
221
|
population: "",
|
|
222
222
|
source_id: "2",
|
|
223
223
|
validations: "",
|
|
224
|
+
source: {
|
|
225
|
+
id: "2",
|
|
226
|
+
config: {
|
|
227
|
+
alias: "source2",
|
|
228
|
+
job_types: ["quality"],
|
|
229
|
+
databases: ["db1", "db2"],
|
|
230
|
+
},
|
|
231
|
+
externalId: "ext_id_2",
|
|
232
|
+
},
|
|
224
233
|
});
|
|
225
234
|
});
|
|
226
235
|
|
|
@@ -239,17 +248,12 @@ describe("<RuleImplementationRawForm />", () => {
|
|
|
239
248
|
validations: "a.city='MADRID'",
|
|
240
249
|
},
|
|
241
250
|
};
|
|
242
|
-
const {
|
|
251
|
+
const { findByRole } = render(
|
|
243
252
|
<RuleImplementationRawForm {...customProps} />,
|
|
244
253
|
renderOpts
|
|
245
254
|
);
|
|
246
|
-
|
|
247
|
-
await
|
|
248
|
-
expect(queryByText(/loading/i)).not.toBeInTheDocument()
|
|
249
|
-
);
|
|
250
|
-
await waitFor(() =>
|
|
251
|
-
expect(queryByRole("button", { name: /save/i })).toBeEnabled()
|
|
252
|
-
);
|
|
255
|
+
|
|
256
|
+
expect(await findByRole("button", { name: /save/i })).toBeEnabled();
|
|
253
257
|
});
|
|
254
258
|
|
|
255
259
|
it("submit button disabled if there is invalid content in form", async () => {
|
|
@@ -266,14 +270,10 @@ describe("<RuleImplementationRawForm />", () => {
|
|
|
266
270
|
validations: "a.city='MADRID'",
|
|
267
271
|
},
|
|
268
272
|
};
|
|
269
|
-
const { queryByRole
|
|
273
|
+
const { queryByRole } = render(
|
|
270
274
|
<RuleImplementationRawForm {...customProps} />,
|
|
271
275
|
renderOpts
|
|
272
276
|
);
|
|
273
|
-
await waitFor(() => expect(queryByText(/lazy/i)).not.toBeInTheDocument());
|
|
274
|
-
await waitFor(() =>
|
|
275
|
-
expect(queryByText(/loading/i)).not.toBeInTheDocument()
|
|
276
|
-
);
|
|
277
277
|
expect(queryByRole("button", { name: /save/i })).toBeDisabled();
|
|
278
278
|
});
|
|
279
279
|
|