@truedat/dq 4.33.8 → 4.34.2

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 (90) hide show
  1. package/CHANGELOG.md +21 -1
  2. package/package.json +5 -5
  3. package/src/api.js +5 -1
  4. package/src/components/ConditionSummary.js +23 -21
  5. package/src/components/ExecutionDetails.js +11 -14
  6. package/src/components/ExecutionForm.js +116 -0
  7. package/src/components/ExecutionGroup.js +24 -15
  8. package/src/components/ExecutionPopup.js +58 -0
  9. package/src/components/ImplementationResultBar.js +80 -0
  10. package/src/components/ImplementationSummary.js +33 -72
  11. package/src/components/ImplementationsRoutes.js +15 -5
  12. package/src/components/ImplementationsUploadButton.js +63 -0
  13. package/src/components/InformationSummary.js +68 -0
  14. package/src/components/NewRuleImplementation.js +12 -0
  15. package/src/components/RuleForm.js +0 -178
  16. package/src/components/RuleImplementation.js +10 -6
  17. package/src/components/RuleImplementationProperties.js +31 -64
  18. package/src/components/RuleImplementationResults.js +87 -53
  19. package/src/components/RuleImplementationsActions.js +18 -48
  20. package/src/components/RuleProperties.js +1 -10
  21. package/src/components/RuleResultDecorator.js +43 -26
  22. package/src/components/RuleResultRow.js +4 -1
  23. package/src/components/RuleRoutes.js +0 -13
  24. package/src/components/RuleSummary.js +15 -2
  25. package/src/components/RulesActions.js +17 -10
  26. package/src/components/RulesUploadButton.js +58 -0
  27. package/src/components/__tests__/ExecutionForm.spec.js +25 -0
  28. package/src/components/__tests__/ExecutionGroup.spec.js +11 -7
  29. package/src/components/__tests__/ExecutionPopup.spec.js +20 -0
  30. package/src/components/__tests__/ImplementationResultBar.spec.js +98 -0
  31. package/src/components/__tests__/ImplementationSummary.spec.js +9 -26
  32. package/src/components/__tests__/InformationSummary.spec.js +35 -0
  33. package/src/components/__tests__/NewRuleImplementation.spec.js +1 -1
  34. package/src/components/__tests__/RuleForm.spec.js +0 -191
  35. package/src/components/__tests__/RuleImplementation.spec.js +1 -0
  36. package/src/components/__tests__/RuleImplementationProperties.spec.js +23 -33
  37. package/src/components/__tests__/RuleImplementationsActions.spec.js +10 -32
  38. package/src/components/__tests__/RuleProperties.spec.js +7 -9
  39. package/src/components/__tests__/RuleResultDecorator.spec.js +17 -11
  40. package/src/components/__tests__/RuleResultRow.spec.js +25 -46
  41. package/src/components/__tests__/RuleRow.spec.js +0 -4
  42. package/src/components/__tests__/RuleSummary.spec.js +6 -6
  43. package/src/components/__tests__/Rules.spec.js +15 -39
  44. package/src/components/__tests__/__snapshots__/ConditionSummary.spec.js.snap +55 -51
  45. package/src/components/__tests__/__snapshots__/ExecutionForm.spec.js.snap +33 -0
  46. package/src/components/__tests__/__snapshots__/ExecutionGroup.spec.js.snap +5 -4
  47. package/src/components/__tests__/__snapshots__/ExecutionPopup.spec.js.snap +11 -0
  48. package/src/components/__tests__/__snapshots__/ImplementationResultBar.spec.js.snap +141 -0
  49. package/src/components/__tests__/__snapshots__/ImplementationSummary.spec.js.snap +194 -457
  50. package/src/components/__tests__/__snapshots__/InformationSummary.spec.js.snap +185 -0
  51. package/src/components/__tests__/__snapshots__/NewRuleImplementation.spec.js.snap +6 -0
  52. package/src/components/__tests__/__snapshots__/RuleForm.spec.js.snap +0 -148
  53. package/src/components/__tests__/__snapshots__/RuleImplementation.spec.js.snap +20 -0
  54. package/src/components/__tests__/__snapshots__/RuleImplementationProperties.spec.js.snap +43 -49
  55. package/src/components/__tests__/__snapshots__/RuleImplementationResults.spec.js.snap +63 -61
  56. package/src/components/__tests__/__snapshots__/RuleImplementationsActions.spec.js.snap +5 -49
  57. package/src/components/__tests__/__snapshots__/RuleProperties.spec.js.snap +0 -1
  58. package/src/components/__tests__/__snapshots__/RuleRow.spec.js.snap +0 -28
  59. package/src/components/__tests__/__snapshots__/Rules.spec.js.snap +0 -101
  60. package/src/components/ruleImplementationForm/InformationForm.js +5 -5
  61. package/src/components/ruleImplementationForm/LimitsForm.js +142 -0
  62. package/src/components/ruleImplementationForm/RuleImplementationForm.js +14 -4
  63. package/src/components/ruleImplementationForm/RuleImplementationRawForm.js +16 -6
  64. package/src/components/ruleImplementationForm/__tests__/LimitsForm.spec.js +186 -0
  65. package/src/components/ruleImplementationForm/__tests__/RuleImplementationRawForm.spec.js +42 -35
  66. package/src/components/ruleImplementationForm/__tests__/__snapshots__/LimitsForm.spec.js.snap +1104 -0
  67. package/src/components/ruleImplementationForm/__tests__/__snapshots__/RuleImplementationForm.spec.js.snap +4 -1
  68. package/src/components/ruleImplementationForm/__tests__/__snapshots__/RuleImplementationRawForm.spec.js.snap +12 -1
  69. package/src/components/ruleImplementationForm/limitsValidation.js +72 -0
  70. package/src/messages/en.js +145 -71
  71. package/src/messages/es.js +270 -180
  72. package/src/reducers/__tests__/rule.spec.js +2 -4
  73. package/src/reducers/__tests__/ruleImplementation.spec.js +2 -0
  74. package/src/reducers/__tests__/ruleImplementations.spec.js +12 -8
  75. package/src/reducers/dqMessage.js +100 -1
  76. package/src/reducers/index.js +4 -0
  77. package/src/reducers/rule.js +0 -3
  78. package/src/reducers/ruleImplementation.js +3 -0
  79. package/src/reducers/ruleImplementationRedirect.js +6 -1
  80. package/src/reducers/ruleImplementations.js +3 -0
  81. package/src/reducers/ruleRedirect.js +5 -0
  82. package/src/reducers/uploadImplementationsFile.js +28 -0
  83. package/src/reducers/uploadRulesFile.js +25 -0
  84. package/src/routines.js +2 -0
  85. package/src/sagas/index.js +6 -0
  86. package/src/sagas/uploadImplementations.js +28 -0
  87. package/src/sagas/uploadRules.js +28 -0
  88. package/src/selectors/getRuleImplementationColumns.js +38 -3
  89. package/src/selectors/ruleColumnsSelector.js +0 -31
  90. package/src/styles/ruleSummary.less +17 -10
@@ -1,11 +1,12 @@
1
1
  import _ from "lodash/fp";
2
2
  import React from "react";
3
3
  import PropTypes from "prop-types";
4
- import { Header, Icon, Label, Grid, Table } from "semantic-ui-react";
4
+ import { Header, Icon, Table, Segment } from "semantic-ui-react";
5
5
  import { Link } from "react-router-dom";
6
6
  import { FormattedMessage } from "react-intl";
7
7
  import { linkTo } from "@truedat/core/routes";
8
8
  import ConditionSummary, { empty, path } from "./ConditionSummary";
9
+ import InformationSummary from "./InformationSummary";
9
10
 
10
11
  const defaults = [
11
12
  "executable",
@@ -38,45 +39,6 @@ FormattedLink.propTypes = {
38
39
  operator: PropTypes.object,
39
40
  };
40
41
 
41
- const GeneralSummary = ({ executable, implementationKey }) => (
42
- <>
43
- <Header as="h3">
44
- <Icon name="database" size="small" />
45
- <Header.Content>
46
- <FormattedMessage id="ruleImplementations.summary.headers.implementation" />
47
- </Header.Content>
48
- </Header>
49
- <Grid>
50
- <Grid.Row>
51
- <Grid.Column>
52
- <Label color={executable ? "olive" : "teal"}>
53
- <FormattedMessage
54
- id={`ruleImplementation.props.executable.${executable}`}
55
- />
56
- </Label>
57
- </Grid.Column>
58
- </Grid.Row>
59
- {implementationKey && (
60
- <Grid.Row columns={2}>
61
- <Grid.Column width={4}>
62
- <FormattedMessage
63
- id={`ruleImplementation.summary.implementation_key`}
64
- />
65
- </Grid.Column>
66
- <Grid.Column width={12}>
67
- <span className="highlighted">{`"${implementationKey}"`}</span>
68
- </Grid.Column>
69
- </Grid.Row>
70
- )}
71
- </Grid>
72
- </>
73
- );
74
-
75
- GeneralSummary.propTypes = {
76
- executable: PropTypes.bool,
77
- implementationKey: PropTypes.string,
78
- };
79
-
80
42
  const DatasetSummary = ({ rows }) =>
81
43
  empty(rows) ? null : (
82
44
  <>
@@ -86,34 +48,36 @@ const DatasetSummary = ({ rows }) =>
86
48
  <FormattedMessage id="ruleImplementations.summary.headers.dataset" />
87
49
  </Header.Content>
88
50
  </Header>
89
- <Table basic="very">
90
- <Table.Header>
91
- <Table.Row>
92
- <Table.HeaderCell>
93
- <FormattedMessage id={`ruleImplementation.summary.structure`} />
94
- </Table.HeaderCell>
95
- </Table.Row>
96
- </Table.Header>
97
- <Table.Body>
98
- {rows.map((row, i) => (
99
- <Table.Row key={i}>
100
- {_.has("structure")(row) && (
101
- <Table.Cell key={i}>
102
- <Link
103
- to={linkTo.STRUCTURE({
104
- id: _.pathOr("", "structure.id")(row),
105
- })}
106
- >
107
- <span key={i} className="highlighted">{`"${path(
108
- _.propOr({}, "structure")(row)
109
- )}"`}</span>
110
- </Link>
111
- </Table.Cell>
112
- )}
51
+ <Segment>
52
+ <Table basic="very">
53
+ <Table.Header>
54
+ <Table.Row>
55
+ <Table.HeaderCell>
56
+ <FormattedMessage id={`ruleImplementation.summary.structure`} />
57
+ </Table.HeaderCell>
113
58
  </Table.Row>
114
- ))}
115
- </Table.Body>
116
- </Table>
59
+ </Table.Header>
60
+ <Table.Body>
61
+ {rows.map((row, i) => (
62
+ <Table.Row key={i}>
63
+ {_.has("structure")(row) && (
64
+ <Table.Cell key={i}>
65
+ <Link
66
+ to={linkTo.STRUCTURE({
67
+ id: _.pathOr("", "structure.id")(row),
68
+ })}
69
+ >
70
+ <span key={i} className="highlighted">{`"${path(
71
+ _.propOr({}, "structure")(row)
72
+ )}"`}</span>
73
+ </Link>
74
+ </Table.Cell>
75
+ )}
76
+ </Table.Row>
77
+ ))}
78
+ </Table.Body>
79
+ </Table>
80
+ </Segment>
117
81
  </>
118
82
  );
119
83
 
@@ -123,16 +87,13 @@ DatasetSummary.propTypes = {
123
87
 
124
88
  export const ImplementationSummary = ({ ruleImplementation, activeSteps }) => {
125
89
  const steps = _.isEmpty(activeSteps) ? defaults : activeSteps;
126
- const { executable, implementationKey, dataset, population, validations } =
90
+ const { dataset, population, validations } =
127
91
  _.pick(steps)(ruleImplementation);
128
92
  return (
129
93
  <>
130
94
  {(_.includes("implementationKey")(steps) ||
131
95
  _.includes("executable")(steps)) && (
132
- <GeneralSummary
133
- executable={executable}
134
- implementationKey={implementationKey}
135
- />
96
+ <InformationSummary ruleImplementation={ruleImplementation} />
136
97
  )}
137
98
  {dataset && _.includes("dataset")(steps) && (
138
99
  <DatasetSummary rows={dataset} />
@@ -5,12 +5,22 @@ import ImplementationFiltersLoader from "./ImplementationFiltersLoader";
5
5
  import RuleImplementations from "./RuleImplementations";
6
6
  import RuleImplementationsLoader from "./RuleImplementationsLoader";
7
7
 
8
+ const TemplatesLoader = React.lazy(() =>
9
+ import("@truedat/df/templates/components/TemplatesLoader")
10
+ );
11
+
8
12
  const ImplementationsRoutes = () => (
9
- <>
10
- <Route path={IMPLEMENTATIONS} component={RuleImplementationsLoader} />
11
- <Route path={IMPLEMENTATIONS} component={ImplementationFiltersLoader} />
12
- <Route path={IMPLEMENTATIONS} component={RuleImplementations} exact />
13
- </>
13
+ <Route
14
+ path={IMPLEMENTATIONS}
15
+ render={() => (
16
+ <>
17
+ <RuleImplementationsLoader />
18
+ <ImplementationFiltersLoader />
19
+ <TemplatesLoader scope="qe" />
20
+ <RuleImplementations exact />
21
+ </>
22
+ )}
23
+ />
14
24
  );
15
25
 
16
26
  export default ImplementationsRoutes;
@@ -0,0 +1,63 @@
1
+ import React from "react";
2
+ import PropTypes from "prop-types";
3
+ import { connect } from "react-redux";
4
+ import { Button } from "semantic-ui-react";
5
+ import { FormattedMessage, useIntl } from "react-intl";
6
+ import { UploadModal } from "@truedat/core/components";
7
+ import { API_RULE_IMPLEMENTATIONS_UPLOAD } from "../api";
8
+ import { uploadImplementations } from "../routines";
9
+
10
+ const uploadAction = {
11
+ method: "POST",
12
+ href: API_RULE_IMPLEMENTATIONS_UPLOAD,
13
+ };
14
+
15
+ export const ImplementationsUploadButton = ({
16
+ uploadImplementations,
17
+ loading,
18
+ }) => {
19
+ const { formatMessage } = useIntl();
20
+ return (
21
+ <UploadModal
22
+ icon="upload"
23
+ trigger={
24
+ <Button
25
+ secondary
26
+ floated="right"
27
+ icon="upload"
28
+ loading={loading}
29
+ data-tooltip={formatMessage({
30
+ id: "ruleImplementations.actions.upload.tooltip",
31
+ })}
32
+ />
33
+ }
34
+ header={
35
+ <FormattedMessage id="ruleImplementations.actions.upload.confirmation.header" />
36
+ }
37
+ content={
38
+ <FormattedMessage id="ruleImplementations.actions.upload.confirmation.content" />
39
+ }
40
+ param={"implementations"}
41
+ handleSubmit={(data) =>
42
+ uploadImplementations({
43
+ action: "upload",
44
+ data,
45
+ ...uploadAction,
46
+ })
47
+ }
48
+ />
49
+ );
50
+ };
51
+
52
+ ImplementationsUploadButton.propTypes = {
53
+ uploadImplementations: PropTypes.func,
54
+ loading: PropTypes.bool,
55
+ };
56
+
57
+ const mapStateToProps = ({ uploadImplementationsFile: { loading } }) => ({
58
+ loading,
59
+ });
60
+
61
+ export default connect(mapStateToProps, { uploadImplementations })(
62
+ ImplementationsUploadButton
63
+ );
@@ -0,0 +1,68 @@
1
+ import React from "react";
2
+ import PropTypes from "prop-types";
3
+ import { FormattedMessage } from "react-intl";
4
+ import { Header, Icon, Segment, List } from "semantic-ui-react";
5
+
6
+ export default function InformationSummary({ ruleImplementation }) {
7
+ return (
8
+ <>
9
+ <Header as="h3">
10
+ <Icon name="info" size="small" />
11
+ <Header.Content>
12
+ <FormattedMessage id="ruleImplementationForm.step.information" />
13
+ </Header.Content>
14
+ </Header>
15
+ <Segment>
16
+ <List>
17
+ <List.Item>
18
+ <List.Header>
19
+ <FormattedMessage id="quality.thresholds" />
20
+ </List.Header>
21
+ <List.Content>
22
+ <List.Description>
23
+ <FormattedMessage
24
+ id={`ruleImplementations.props.result_type.${ruleImplementation.result_type}`}
25
+ />
26
+ </List.Description>
27
+ </List.Content>
28
+ </List.Item>
29
+ <List.Item>
30
+ <Icon name="circle" color="yellow" />
31
+ <List.Content>
32
+ <List.Header>
33
+ <FormattedMessage id="quality.threshold" />
34
+ </List.Header>
35
+ <List.Description>
36
+ {ruleImplementation.minimum &&
37
+ `${ruleImplementation.minimum} ${
38
+ ruleImplementation.result_type !== "errors_number"
39
+ ? "%"
40
+ : ""
41
+ }`}
42
+ </List.Description>
43
+ </List.Content>
44
+ </List.Item>
45
+ <List.Item>
46
+ <Icon name="circle" color="green" />
47
+ <List.Content>
48
+ <List.Header>
49
+ <FormattedMessage id="quality.goal" />
50
+ </List.Header>
51
+ <List.Description>
52
+ {ruleImplementation.goal &&
53
+ `${ruleImplementation.goal} ${
54
+ ruleImplementation.result_type !== "errors_number"
55
+ ? "%"
56
+ : ""
57
+ }`}
58
+ </List.Description>
59
+ </List.Content>
60
+ </List.Item>
61
+ </List>
62
+ </Segment>
63
+ </>
64
+ );
65
+ }
66
+ InformationSummary.propTypes = {
67
+ ruleImplementation: PropTypes.object.isRequired,
68
+ };
@@ -220,6 +220,9 @@ export const NewRuleImplementation = ({
220
220
  },
221
221
  dfName: _.prop("df_name")(ruleImplementationProps),
222
222
  dfContent: ruleImplementationProps.df_content,
223
+ result_type: ruleImplementationProps.result_type,
224
+ minimum: ruleImplementationProps.minimum,
225
+ goal: ruleImplementationProps.goal,
223
226
  }
224
227
  : {
225
228
  executable: true,
@@ -237,6 +240,9 @@ export const NewRuleImplementation = ({
237
240
  },
238
241
  dfName: "",
239
242
  dfContent: {},
243
+ result_type: "percentage",
244
+ minimum: null,
245
+ goal: null,
240
246
  }
241
247
  );
242
248
 
@@ -343,6 +349,9 @@ export const NewRuleImplementation = ({
343
349
  df_content: dfContent,
344
350
  rule_id: rule.id,
345
351
  raw_content: { ...raw_content, source },
352
+ result_type: ruleImplementation.result_type,
353
+ minimum: ruleImplementation.minimum,
354
+ goal: ruleImplementation.goal,
346
355
  }
347
356
  : {
348
357
  executable: ruleImplementation.executable,
@@ -355,6 +364,9 @@ export const NewRuleImplementation = ({
355
364
  df_name,
356
365
  df_content: dfContent,
357
366
  rule_id: rule.id,
367
+ result_type: ruleImplementation.result_type,
368
+ minimum: ruleImplementation.minimum,
369
+ goal: ruleImplementation.goal,
358
370
  };
359
371
 
360
372
  clone || !edition
@@ -85,12 +85,9 @@ export class RuleForm extends React.Component {
85
85
  domain_id: null,
86
86
  name: "",
87
87
  description: null,
88
- minimum: null,
89
- goal: null,
90
88
  type_params: {},
91
89
  df_name: "",
92
90
  df_content: {},
93
- result_type: "percentage",
94
91
  };
95
92
 
96
93
  componentDidMount() {
@@ -218,86 +215,6 @@ export class RuleForm extends React.Component {
218
215
  this.setState({ activeSelection: !activeSelection });
219
216
  };
220
217
 
221
- percentageResultValidationMessages = () => {
222
- const rule = this.state;
223
- const {
224
- intl: { formatMessage },
225
- } = this.props;
226
- const minimumMessages = [];
227
- const goalMessages = [];
228
- if (rule.goal > 100)
229
- goalMessages.push(formatMessage({ id: "rule.form.validation.max_goal" }));
230
-
231
- if (
232
- !_.isNil(rule.minimum) &&
233
- !_.isNil(rule.goal) &&
234
- rule.minimum > rule.goal
235
- ) {
236
- minimumMessages.push(
237
- formatMessage({ id: "rule.form.validation.minimum_greater" })
238
- );
239
- goalMessages.push(
240
- formatMessage({ id: "rule.form.validation.goal_less" })
241
- );
242
- }
243
- return { minimumMessages, goalMessages };
244
- };
245
-
246
- errorsNumberResultValidationMessages = () => {
247
- const rule = this.state;
248
- const {
249
- intl: { formatMessage },
250
- } = this.props;
251
- const minimumMessages = [];
252
- const goalMessages = [];
253
-
254
- if (
255
- !_.isNil(rule.minimum) &&
256
- !_.isNil(rule.goal) &&
257
- rule.minimum < rule.goal
258
- ) {
259
- minimumMessages.push(
260
- formatMessage({
261
- id: "rule.form.validation.minimum.greater_eq.goal",
262
- })
263
- );
264
- goalMessages.push(
265
- formatMessage({ id: "rule.form.validation.goal.less_eq.minimum" })
266
- );
267
- }
268
- return { minimumMessages, goalMessages };
269
- };
270
-
271
- deviationResultValidationMessages = () => {
272
- const rule = this.state;
273
- const {
274
- intl: { formatMessage },
275
- } = this.props;
276
- const minimumMessages = [];
277
- const goalMessages = [];
278
-
279
- if (rule.minimum > 100)
280
- minimumMessages.push(
281
- formatMessage({ id: "rule.form.validation.max_minimum" })
282
- );
283
-
284
- if (
285
- !_.isNil(rule.minimum) &&
286
- !_.isNil(rule.goal) &&
287
- rule.minimum < rule.goal
288
- ) {
289
- minimumMessages.push(
290
- formatMessage({
291
- id: "rule.form.validation.minimum.greater_eq.goal",
292
- })
293
- );
294
- goalMessages.push(
295
- formatMessage({ id: "rule.form.validation.goal.less_eq.minimum" })
296
- );
297
- }
298
- return { minimumMessages, goalMessages };
299
- };
300
-
301
218
  generateValidationMessages = () => {
302
219
  const rule = this.state;
303
220
  const {
@@ -311,30 +228,9 @@ export class RuleForm extends React.Component {
311
228
  : undefined;
312
229
  const domain = _.isNil(rule.domain_id) ? [requiredMessage] : undefined;
313
230
 
314
- const { minimumMessages, goalMessages } = (() => {
315
- switch (rule.result_type) {
316
- case "percentage":
317
- return this.percentageResultValidationMessages();
318
- case "errors_number":
319
- return this.errorsNumberResultValidationMessages();
320
- case "deviation":
321
- return this.deviationResultValidationMessages();
322
- }
323
- })();
324
-
325
- if (_.isNil(rule.minimum)) minimumMessages.push(requiredMessage);
326
- if (_.isNil(rule.goal)) goalMessages.push(requiredMessage);
327
-
328
- const minimum_validation = !_.isEmpty(minimumMessages)
329
- ? minimumMessages
330
- : undefined;
331
- const goal_validation = !_.isEmpty(goalMessages) ? goalMessages : undefined;
332
-
333
231
  return {
334
232
  domain,
335
233
  name: name_validation,
336
- minimum: minimum_validation,
337
- goal: goal_validation,
338
234
  };
339
235
  };
340
236
 
@@ -454,80 +350,6 @@ export class RuleForm extends React.Component {
454
350
  </Accordion>
455
351
  </Segment>
456
352
  )}
457
- <Segment>
458
- <FieldLabelWrapping
459
- label={formatMessage({ id: "rule.props.result_type" })}
460
- messages={_.prop("result_type")(messages)}
461
- required
462
- tooltip={formatMessage({ id: "rule.form.tooltip.result_type" })}
463
- >
464
- <Form.Group inline>
465
- <Form.Radio
466
- name={"result_type"}
467
- label={formatMessage({
468
- id: "rule.props.result_type.percentage",
469
- })}
470
- value={"percentage"}
471
- checked={rule.result_type == "percentage"}
472
- onChange={this.handleChange}
473
- />
474
- <Form.Radio
475
- name={"result_type"}
476
- label={formatMessage({
477
- id: "rule.props.result_type.deviation",
478
- })}
479
- value={"deviation"}
480
- checked={rule.result_type == "deviation"}
481
- onChange={this.handleChange}
482
- />
483
- <Form.Radio
484
- name={"result_type"}
485
- label={formatMessage({
486
- id: "rule.props.result_type.errors_number",
487
- })}
488
- value={"errors_number"}
489
- checked={rule.result_type == "errors_number"}
490
- onChange={this.handleChange}
491
- />
492
- </Form.Group>
493
- </FieldLabelWrapping>
494
- <FieldLabelWrapping
495
- label={formatMessage({ id: "rule.props.minimum" })}
496
- messages={_.prop("minimum")(messages)}
497
- required
498
- tooltip={formatMessage({
499
- id: `rule.form.tooltip.${rule.result_type}.minimum`,
500
- })}
501
- >
502
- <Form.Input
503
- name="minimum"
504
- onChange={this.handleChangeInteger}
505
- value={_.isNil(rule.minimum) ? "" : rule.minimum}
506
- placeholder={formatMessage({
507
- id: "rule.props.minimum.placeholder",
508
- })}
509
- autoComplete="off"
510
- />
511
- </FieldLabelWrapping>
512
- <FieldLabelWrapping
513
- label={formatMessage({ id: "rule.props.goal" })}
514
- messages={_.prop("goal")(messages)}
515
- required
516
- tooltip={formatMessage({
517
- id: `rule.form.tooltip.${rule.result_type}.goal`,
518
- })}
519
- >
520
- <Form.Input
521
- name="goal"
522
- onChange={this.handleChangeInteger}
523
- value={_.isNil(rule.goal) ? "" : rule.goal}
524
- placeholder={formatMessage({
525
- id: "rule.props.goal.placeholder",
526
- })}
527
- autoComplete="off"
528
- />
529
- </FieldLabelWrapping>
530
- </Segment>
531
353
  {!_.isNil(rule.df_content) && templatesLoaded && (
532
354
  <DynamicRuleForm
533
355
  name="dynamicForm"
@@ -4,12 +4,13 @@ import { Link } from "react-router-dom";
4
4
  import PropTypes from "prop-types";
5
5
  import { useIntl } from "react-intl";
6
6
  import { connect } from "react-redux";
7
- import { Header, Label, Menu, Grid } from "semantic-ui-react";
7
+ import { Header, Label, Menu, Grid, Icon } from "semantic-ui-react";
8
8
  import { ConfirmModal, GroupActions } from "@truedat/core/components";
9
9
  import { useAuthorized } from "@truedat/core/hooks";
10
10
  import { linkTo } from "@truedat/core/routes";
11
11
  import { setRuleImplementationStatus } from "../routines";
12
12
  import RuleImplementationTabs from "./RuleImplementationTabs";
13
+ import ImplementationResultBar from "./ImplementationResultBar";
13
14
 
14
15
  const getAvailableActions = (props, formatMessage) => {
15
16
  const contentActions = [
@@ -177,11 +178,13 @@ export const RuleImplementation = ({
177
178
  <>
178
179
  <Grid>
179
180
  <Grid.Column width={8}>
180
- <Header
181
- as="h2"
182
- content={ruleImplementation.implementation_key}
183
- icon={{ name: "clipboard check", circular: true }}
184
- />
181
+ <Header as="h2">
182
+ <Icon circular name="clipboard check" />
183
+ <Header.Content>
184
+ {ruleImplementation.implementation_key}
185
+ <ImplementationResultBar implementation={ruleImplementation} />
186
+ </Header.Content>
187
+ </Header>
185
188
  </Grid.Column>
186
189
  <Grid.Column width={8} textAlign="right">
187
190
  <>
@@ -215,6 +218,7 @@ RuleImplementation.propTypes = {
215
218
  rule: PropTypes.object,
216
219
  ruleImplementation: PropTypes.object,
217
220
  userRulePermissions: PropTypes.object,
221
+ children: PropTypes.node,
218
222
  };
219
223
 
220
224
  const mapStateToProps = ({