@truedat/dq 4.33.10 → 4.35.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 (96) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/package.json +5 -5
  3. package/src/api.js +7 -1
  4. package/src/components/ConditionSummary.js +23 -21
  5. package/src/components/ExecutionDetails.js +11 -14
  6. package/src/components/ExecutionGroup.js +24 -15
  7. package/src/components/ImplementationResultBar.js +80 -0
  8. package/src/components/ImplementationSummary.js +33 -72
  9. package/src/components/ImplementationsUploadButton.js +61 -0
  10. package/src/components/InformationSummary.js +68 -0
  11. package/src/components/NewRuleImplementation.js +12 -0
  12. package/src/components/RuleForm.js +0 -178
  13. package/src/components/RuleImplementation.js +10 -6
  14. package/src/components/RuleImplementationProperties.js +31 -64
  15. package/src/components/RuleImplementationResults.js +87 -53
  16. package/src/components/RuleImplementationsActions.js +3 -59
  17. package/src/components/RuleImplementationsDownload.js +86 -0
  18. package/src/components/RuleImplementationsOptions.js +28 -0
  19. package/src/components/RuleProperties.js +1 -10
  20. package/src/components/RuleResultDecorator.js +43 -26
  21. package/src/components/RuleResultRow.js +4 -1
  22. package/src/components/RuleResultsUpload.js +47 -0
  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__/ExecutionGroup.spec.js +11 -7
  28. package/src/components/__tests__/ImplementationResultBar.spec.js +98 -0
  29. package/src/components/__tests__/ImplementationSummary.spec.js +9 -26
  30. package/src/components/__tests__/InformationSummary.spec.js +35 -0
  31. package/src/components/__tests__/NewRuleImplementation.spec.js +1 -1
  32. package/src/components/__tests__/RuleForm.spec.js +0 -191
  33. package/src/components/__tests__/RuleImplementation.spec.js +1 -0
  34. package/src/components/__tests__/RuleImplementationProperties.spec.js +23 -33
  35. package/src/components/__tests__/RuleImplementationsActions.spec.js +0 -9
  36. package/src/components/__tests__/RuleImplementationsOptions.spec.js +18 -0
  37. package/src/components/__tests__/RuleProperties.spec.js +7 -9
  38. package/src/components/__tests__/RuleResultDecorator.spec.js +17 -11
  39. package/src/components/__tests__/RuleResultRow.spec.js +25 -46
  40. package/src/components/__tests__/RuleResultsUpload.spec.js +18 -0
  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__/ExecutionGroup.spec.js.snap +5 -4
  46. package/src/components/__tests__/__snapshots__/ImplementationResultBar.spec.js.snap +141 -0
  47. package/src/components/__tests__/__snapshots__/ImplementationSummary.spec.js.snap +194 -457
  48. package/src/components/__tests__/__snapshots__/InformationSummary.spec.js.snap +185 -0
  49. package/src/components/__tests__/__snapshots__/NewRuleImplementation.spec.js.snap +6 -0
  50. package/src/components/__tests__/__snapshots__/RuleForm.spec.js.snap +0 -148
  51. package/src/components/__tests__/__snapshots__/RuleImplementation.spec.js.snap +20 -0
  52. package/src/components/__tests__/__snapshots__/RuleImplementationProperties.spec.js.snap +43 -49
  53. package/src/components/__tests__/__snapshots__/RuleImplementationResults.spec.js.snap +63 -61
  54. package/src/components/__tests__/__snapshots__/RuleImplementationsActions.spec.js.snap +1 -7
  55. package/src/components/__tests__/__snapshots__/RuleImplementationsOptions.spec.js.snap +58 -0
  56. package/src/components/__tests__/__snapshots__/RuleProperties.spec.js.snap +0 -1
  57. package/src/components/__tests__/__snapshots__/RuleResultsUpload.spec.js.snap +18 -0
  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/FiltersGroup.js +1 -0
  61. package/src/components/ruleImplementationForm/InformationForm.js +5 -5
  62. package/src/components/ruleImplementationForm/LimitsForm.js +142 -0
  63. package/src/components/ruleImplementationForm/RuleImplementationForm.js +14 -4
  64. package/src/components/ruleImplementationForm/RuleImplementationRawForm.js +16 -6
  65. package/src/components/ruleImplementationForm/ValueConditions.js +11 -0
  66. package/src/components/ruleImplementationForm/__tests__/LimitsForm.spec.js +186 -0
  67. package/src/components/ruleImplementationForm/__tests__/RuleImplementationRawForm.spec.js +42 -35
  68. package/src/components/ruleImplementationForm/__tests__/__snapshots__/LimitsForm.spec.js.snap +1104 -0
  69. package/src/components/ruleImplementationForm/__tests__/__snapshots__/RuleImplementationForm.spec.js.snap +4 -1
  70. package/src/components/ruleImplementationForm/__tests__/__snapshots__/RuleImplementationRawForm.spec.js.snap +12 -1
  71. package/src/components/ruleImplementationForm/limitsValidation.js +72 -0
  72. package/src/messages/en.js +167 -76
  73. package/src/messages/es.js +292 -185
  74. package/src/reducers/__tests__/rule.spec.js +2 -4
  75. package/src/reducers/__tests__/ruleImplementation.spec.js +2 -0
  76. package/src/reducers/__tests__/ruleImplementations.spec.js +12 -8
  77. package/src/reducers/__tests__/uploadingResults.spec.js +28 -0
  78. package/src/reducers/dqMessage.js +121 -1
  79. package/src/reducers/index.js +6 -0
  80. package/src/reducers/rule.js +0 -3
  81. package/src/reducers/ruleImplementation.js +3 -0
  82. package/src/reducers/ruleImplementationRedirect.js +6 -1
  83. package/src/reducers/ruleImplementations.js +3 -0
  84. package/src/reducers/ruleRedirect.js +5 -0
  85. package/src/reducers/uploadImplementationsFile.js +28 -0
  86. package/src/reducers/uploadRulesFile.js +25 -0
  87. package/src/reducers/uploadingResults.js +16 -0
  88. package/src/routines.js +3 -0
  89. package/src/sagas/__tests__/uploadResults.spec.js +65 -0
  90. package/src/sagas/index.js +9 -0
  91. package/src/sagas/uploadImplementations.js +28 -0
  92. package/src/sagas/uploadResults.js +32 -0
  93. package/src/sagas/uploadRules.js +28 -0
  94. package/src/selectors/getRuleImplementationColumns.js +38 -3
  95. package/src/selectors/ruleColumnsSelector.js +0 -31
  96. package/src/styles/ruleSummary.less +17 -10
@@ -2,9 +2,7 @@ import _ from "lodash/fp";
2
2
  import React from "react";
3
3
  import PropTypes from "prop-types";
4
4
  import { connect } from "react-redux";
5
- import { Button, Checkbox } from "semantic-ui-react";
6
- import { useIntl } from "react-intl";
7
- import { downloadImplementations } from "../routines";
5
+ import { Checkbox } from "semantic-ui-react";
8
6
  import { getImplementationsExecution } from "../selectors";
9
7
  import {
10
8
  addImplementationFilter,
@@ -13,35 +11,11 @@ import {
13
11
  createExecutionGroup,
14
12
  } from "../routines";
15
13
  import ExecutionPopup from "./ExecutionPopup";
16
-
17
- const staticHeaderLabels = [
18
- "implementation_key",
19
- "implementation_type",
20
- "rule",
21
- "template",
22
- "goal",
23
- "minimum",
24
- "business_concept",
25
- "last_execution_at",
26
- "result",
27
- "execution",
28
- "inserted_at",
29
- "executable",
30
- ];
31
-
32
- const staticContentLabels = [
33
- "quality_result.under_minimum",
34
- "quality_result.under_goal",
35
- "quality_result.over_goal",
36
- "quality_result.no_execution",
37
- "executable.true",
38
- "executable.false",
39
- ];
14
+ import RuleImplementationsOptions from "./RuleImplementationsOptions";
40
15
 
41
16
  export const RuleImplementationsActions = ({
42
17
  addImplementationFilter,
43
18
  canExecute,
44
- downloadImplementations,
45
19
  executeImplementationsOn,
46
20
  toggleImplementationFilterValue,
47
21
  removeImplementationFilter,
@@ -51,21 +25,8 @@ export const RuleImplementationsActions = ({
51
25
  setMode,
52
26
  implementationsExecution,
53
27
  ruleImplementationCount,
54
- ruleImplementationsDownloading,
55
28
  ruleImplementationsLoading,
56
29
  }) => {
57
- const { formatMessage } = useIntl();
58
-
59
- const headerLabels = _.flow(
60
- _.map((l) => [l, formatMessage({ id: `ruleImplementations.props.${l}` })]),
61
- _.fromPairs
62
- )(staticHeaderLabels);
63
-
64
- const contentLabels = _.flow(
65
- _.map((l) => [l, formatMessage({ id: `ruleImplementations.props.${l}` })]),
66
- _.fromPairs
67
- )(staticContentLabels);
68
-
69
30
  const showExecutableInfo = () => {
70
31
  addImplementationFilter({ filter: "executable" });
71
32
  toggleImplementationFilterValue({
@@ -112,27 +73,13 @@ export const RuleImplementationsActions = ({
112
73
  />
113
74
  </>
114
75
  )}
115
- {!ruleImplementationsLoading && (
116
- <Button
117
- floated="right"
118
- secondary
119
- icon="download"
120
- data-tooltip={formatMessage({
121
- id: "implementations.actions.download.tooltip",
122
- })}
123
- onClick={() =>
124
- downloadImplementations({ contentLabels, headerLabels })
125
- }
126
- loading={ruleImplementationsDownloading}
127
- />
128
- )}
76
+ <RuleImplementationsOptions loading={ruleImplementationsLoading} />
129
77
  </div>
130
78
  );
131
79
  };
132
80
 
133
81
  RuleImplementationsActions.propTypes = {
134
82
  addImplementationFilter: PropTypes.func,
135
- downloadImplementations: PropTypes.func,
136
83
  canExecute: PropTypes.bool,
137
84
  createExecutionGroup: PropTypes.func,
138
85
  executeImplementationsOn: PropTypes.bool,
@@ -143,7 +90,6 @@ RuleImplementationsActions.propTypes = {
143
90
  selectedImplementations: PropTypes.array,
144
91
  setMode: PropTypes.func,
145
92
  toggleImplementationFilterValue: PropTypes.func,
146
- ruleImplementationsDownloading: PropTypes.bool,
147
93
  ruleImplementationsLoading: PropTypes.bool,
148
94
  };
149
95
 
@@ -151,13 +97,11 @@ const mapStateToProps = (state) => ({
151
97
  canExecute: _.propOr(false, "userImplementationsPermissions.execute")(state),
152
98
  ruleImplementationCount: state.ruleImplementationCount,
153
99
  implementationsExecution: getImplementationsExecution(state),
154
- ruleImplementationsDownloading: state.ruleImplementationsDownloading,
155
100
  ruleImplementationsLoading: state.ruleImplementationsLoading,
156
101
  });
157
102
 
158
103
  export default connect(mapStateToProps, {
159
104
  addImplementationFilter,
160
- downloadImplementations,
161
105
  toggleImplementationFilterValue,
162
106
  removeImplementationFilter,
163
107
  createExecutionGroup,
@@ -0,0 +1,86 @@
1
+ import _ from "lodash/fp";
2
+ import React from "react";
3
+ import PropTypes from "prop-types";
4
+ import { connect } from "react-redux";
5
+ import { Dropdown } from "semantic-ui-react";
6
+ import { useIntl } from "react-intl";
7
+ import { downloadImplementations } from "../routines";
8
+
9
+ const staticHeaderLabels = [
10
+ "implementation_key",
11
+ "implementation_type",
12
+ "rule",
13
+ "template",
14
+ "goal",
15
+ "minimum",
16
+ "business_concept",
17
+ "last_execution_at",
18
+ "result",
19
+ "execution",
20
+ "inserted_at",
21
+ "executable",
22
+ ];
23
+
24
+ const staticContentLabels = [
25
+ "quality_result.under_minimum",
26
+ "quality_result.under_goal",
27
+ "quality_result.over_goal",
28
+ "quality_result.no_execution",
29
+ "executable.true",
30
+ "executable.false",
31
+ ];
32
+
33
+ export const RuleImplementationsDownload = ({
34
+ downloadImplementations,
35
+ ruleImplementationsDownloading,
36
+ ruleImplementations,
37
+ }) => {
38
+ const { formatMessage } = useIntl();
39
+
40
+ const headerLabels = _.flow(
41
+ _.map((l) => [l, formatMessage({ id: `ruleImplementations.props.${l}` })]),
42
+ _.fromPairs
43
+ )(staticHeaderLabels);
44
+
45
+ const contentLabels = _.flow(
46
+ _.map((l) => [l, formatMessage({ id: `ruleImplementations.props.${l}` })]),
47
+ _.fromPairs
48
+ )(staticContentLabels);
49
+
50
+ const isDisabled = _.isEmpty(ruleImplementations);
51
+
52
+ return (
53
+ <Dropdown.Item
54
+ icon="download"
55
+ content={
56
+ <>
57
+ <span>
58
+ {formatMessage({ id: "implementations.actions.download.tooltip" })}
59
+ </span>
60
+ {isDisabled && (
61
+ <p className="menu-item-description">
62
+ {formatMessage({ id: "implementations.actions.download.empty" })}
63
+ </p>
64
+ )}
65
+ </>
66
+ }
67
+ onClick={() => downloadImplementations({ contentLabels, headerLabels })}
68
+ disabled={isDisabled || ruleImplementationsDownloading}
69
+ />
70
+ );
71
+ };
72
+
73
+ RuleImplementationsDownload.propTypes = {
74
+ downloadImplementations: PropTypes.func,
75
+ ruleImplementationsDownloading: PropTypes.bool,
76
+ ruleImplementations: PropTypes.array,
77
+ };
78
+
79
+ const mapStateToProps = _.pick([
80
+ "ruleImplementationsDownloading",
81
+ "ruleImplementations",
82
+ ]);
83
+
84
+ export default connect(mapStateToProps, {
85
+ downloadImplementations,
86
+ })(RuleImplementationsDownload);
@@ -0,0 +1,28 @@
1
+ import React from "react";
2
+ import PropTypes from "prop-types";
3
+ import { Dropdown } from "semantic-ui-react";
4
+ import RuleImplementationsDownload from "./RuleImplementationsDownload";
5
+ import RuleResultsUpload from "./RuleResultsUpload";
6
+ import ImplementationsUploadButton from "./ImplementationsUploadButton";
7
+
8
+ export const RuleImplementationsOptions = ({ loading }) => (
9
+ <Dropdown
10
+ icon="ellipsis vertical"
11
+ className="button icon group-actions button-update"
12
+ direction="left"
13
+ floating
14
+ disabled={loading}
15
+ >
16
+ <Dropdown.Menu>
17
+ <RuleImplementationsDownload />
18
+ <ImplementationsUploadButton />
19
+ <RuleResultsUpload />
20
+ </Dropdown.Menu>
21
+ </Dropdown>
22
+ );
23
+
24
+ RuleImplementationsOptions.propTypes = {
25
+ loading: PropTypes.bool,
26
+ };
27
+
28
+ export default RuleImplementationsOptions;
@@ -3,12 +3,10 @@ import React from "react";
3
3
  import PropTypes from "prop-types";
4
4
  import { FormattedMessage } from "react-intl";
5
5
  import { connect } from "react-redux";
6
- import { useHistory, Link } from "react-router-dom";
6
+ import { Link } from "react-router-dom";
7
7
  import { List, Label } from "semantic-ui-react";
8
8
  import "rc-slider/assets/index.css";
9
9
  import { linkTo } from "@truedat/core/routes";
10
- import RuleRangeNumber from "./RuleRangeNumber";
11
- import RuleRangePercentage from "./RuleRangePercentage";
12
10
 
13
11
  const RichTextEditor = React.lazy(() =>
14
12
  import("@truedat/core/components/RichTextEditor")
@@ -27,7 +25,6 @@ export const RuleProperties = ({
27
25
  domain,
28
26
  domain_id,
29
27
  active,
30
- result_type,
31
28
  }) => {
32
29
  return (
33
30
  <List size="big" relaxed>
@@ -67,11 +64,6 @@ export const RuleProperties = ({
67
64
  </Link>
68
65
  </List.Item>
69
66
  )}
70
- {["percentage", "deviation"].includes(result_type) ? (
71
- <RuleRangePercentage />
72
- ) : (
73
- <RuleRangeNumber />
74
- )}
75
67
  </List>
76
68
  );
77
69
  };
@@ -83,7 +75,6 @@ RuleProperties.propTypes = {
83
75
  description: PropTypes.object,
84
76
  domain: PropTypes.object,
85
77
  domain_id: PropTypes.number,
86
- result_type: PropTypes.string,
87
78
  };
88
79
 
89
80
  const mapStateToProps = ({ rule }) => rule;
@@ -10,31 +10,30 @@ const nilResult = (ruleResult) =>
10
10
  isNil(ruleResult) ||
11
11
  (has("result_text")(ruleResult) && isNil(ruleResult?.result_text));
12
12
 
13
- export const RuleResultDecorator = ({ ruleResult, rule, date }) => {
14
- const { formatMessage, formatNumber: _formatNumber } = useIntl();
13
+ export const calculateResultDecoration = ({
14
+ ruleResult,
15
+ ruleImplementation,
16
+ date,
17
+ intl: { formatMessage, formatNumber: _formatNumber },
18
+ }) => {
15
19
  const formatNumber = (num) => (isNil(num) ? num : _formatNumber(num));
16
- if (nilResult(ruleResult) && isNil(date)) {
17
- return null;
18
- }
20
+
19
21
  if (ruleResult?.result_text === "quality_result.failed") {
20
- return (
21
- <>
22
- <Icon
23
- name="warning circle"
24
- color="red"
25
- title={formatMessage({ id: "quality_result.failed" })}
26
- />
27
- {formatMessage({ id: "quality_result.failed" })}
28
- </>
29
- );
22
+ const resultText = formatMessage({ id: "quality_result.failed" });
23
+ return {
24
+ iconName: "warning circle",
25
+ resultText: resultText,
26
+ color: "red",
27
+ resultText,
28
+ };
30
29
  }
31
- const resultText = ruleResult?.result_text;
32
- const resultType = rule?.result_type;
30
+
31
+ const resultType = ruleImplementation?.result_type;
33
32
  const result =
34
33
  resultType === "errors_number"
35
34
  ? formatNumber(ruleResult?.errors)
36
35
  : ruleResult?.result;
37
- const resultTitle = isNil(result)
36
+ const resultText = isNil(result)
38
37
  ? formatMessage({ id: "quality.result.no.data" })
39
38
  : date
40
39
  ? formatMessage(
@@ -45,23 +44,41 @@ export const RuleResultDecorator = ({ ruleResult, rule, date }) => {
45
44
  { id: `quality.result.${resultType}.description` },
46
45
  { result }
47
46
  );
48
- const color = selectColor({ ...rule, ...ruleResult });
47
+ const color = selectColor({ ...ruleImplementation, ...ruleResult });
48
+ const iconTitle = ruleResult?.result_text
49
+ ? formatMessage({ id: ruleResult?.result_text })
50
+ : null;
51
+
52
+ return { iconName: "circle", color, resultText, iconTitle };
53
+ };
54
+
55
+ export const RuleResultDecorator = ({
56
+ ruleResult,
57
+ ruleImplementation,
58
+ date,
59
+ }) => {
60
+ const intl = useIntl();
61
+ if (nilResult(ruleResult) && isNil(date)) {
62
+ return null;
63
+ }
64
+ const { iconName, color, resultText, iconTitle } = calculateResultDecoration({
65
+ ruleResult,
66
+ ruleImplementation,
67
+ date,
68
+ intl,
69
+ });
49
70
 
50
71
  return (
51
72
  <>
52
- <Icon
53
- name="circle"
54
- title={resultText ? formatMessage({ id: resultText }) : null}
55
- color={color}
56
- />
57
- {resultTitle}
73
+ <Icon name={iconName} title={iconTitle} color={color} />
74
+ {resultText}
58
75
  </>
59
76
  );
60
77
  };
61
78
 
62
79
  RuleResultDecorator.propTypes = {
63
80
  ruleResult: PropTypes.object,
64
- rule: PropTypes.object,
81
+ ruleImplementation: PropTypes.object,
65
82
  date: PropTypes.string,
66
83
  };
67
84
 
@@ -41,7 +41,10 @@ export const RuleResultRow = ({
41
41
  }
42
42
  >
43
43
  <Table.Cell>
44
- <Icon name="circle" color={selectColor({ ...rule, ...ruleResult })} />
44
+ <Icon
45
+ name="circle"
46
+ color={selectColor({ ...ruleImplementation, ...ruleResult })}
47
+ />
45
48
  {`${parseFloat(ruleResult.result)} %`}
46
49
  </Table.Cell>
47
50
  <Table.Cell>
@@ -0,0 +1,47 @@
1
+ import React from "react";
2
+ import PropTypes from "prop-types";
3
+ import { connect } from "react-redux";
4
+ import { Dropdown } from "semantic-ui-react";
5
+ import { useIntl } from "react-intl";
6
+ import { UploadModal } from "@truedat/core/components";
7
+ import { uploadResults } from "../routines";
8
+
9
+ export const RuleResultsUpload = ({ uploadResults, loading }) => {
10
+ const { formatMessage } = useIntl();
11
+
12
+ return (
13
+ <UploadModal
14
+ icon="upload"
15
+ trigger={
16
+ <Dropdown.Item
17
+ icon="upload"
18
+ text={formatMessage({ id: "ruleResults.actions.upload.tooltip" })}
19
+ disabled={loading}
20
+ />
21
+ }
22
+ header={formatMessage({
23
+ id: "ruleResults.actions.upload.confirmation.header",
24
+ })}
25
+ content={formatMessage({
26
+ id: "uploadModal.actions.upload.confirmation.content",
27
+ })}
28
+ param={"rule_results"}
29
+ handleSubmit={(data) =>
30
+ uploadResults({
31
+ data,
32
+ })
33
+ }
34
+ />
35
+ );
36
+ };
37
+
38
+ RuleResultsUpload.propTypes = {
39
+ uploadResults: PropTypes.func,
40
+ loading: PropTypes.bool,
41
+ };
42
+
43
+ const mapStateToProps = ({ uploadingResults }) => ({
44
+ loading: uploadingResults,
45
+ });
46
+
47
+ export default connect(mapStateToProps, { uploadResults })(RuleResultsUpload);
@@ -66,7 +66,6 @@ const RuleRoutes = ({
66
66
  templatesLoaded,
67
67
  template,
68
68
  structuresAliasesLoading,
69
- templateImpl,
70
69
  ruleImplementation,
71
70
  }) => {
72
71
  const latest = _.head(ruleImplementation.results);
@@ -227,14 +226,6 @@ const RuleRoutes = ({
227
226
  <RuleImplementationProperties />
228
227
  </RuleImplementation>
229
228
  )}
230
- {!_.isEmpty(templateImpl) && ruleImplementationLoaded && (
231
- <Segment attached="bottom">
232
- <DynamicFormViewer
233
- template={templateImpl}
234
- content={ruleImplementation.df_content}
235
- />
236
- </Segment>
237
- )}
238
229
  </Segment>
239
230
  </>
240
231
  )}
@@ -305,7 +296,6 @@ RuleRoutes.propTypes = {
305
296
  implementationStructures: PropTypes.array,
306
297
  ruleLoaded: PropTypes.bool,
307
298
  template: PropTypes.object,
308
- templateImpl: PropTypes.object,
309
299
  ruleImplementation: PropTypes.object,
310
300
  ruleImplementationLoaded: PropTypes.bool,
311
301
  implementationStructuresLoaded: PropTypes.bool,
@@ -325,9 +315,6 @@ const mapStateToProps = (state) => ({
325
315
  templatesLoaded: !state.templatesLoading && !_.isEmpty(state.templates),
326
316
  template: _.find(_.propEq("name", state.rule.df_name))(state.templates),
327
317
  structuresAliasesLoading: state.structuresAliasesLoading,
328
- templateImpl: _.find(_.propEq("name", state.ruleImplementation.df_name))(
329
- state.templates
330
- ),
331
318
  ruleImplementation: state.ruleImplementation,
332
319
  });
333
320
 
@@ -22,8 +22,12 @@ const mapSummary = (implementations) => {
22
22
  const failed = _.size(failedImplementations);
23
23
  const quality = _.reduce(
24
24
  (summary, implementation) => {
25
- const { errors, result } = implementation.execution_result_info;
26
- const { goal, minimum, result_type } = implementation.rule;
25
+ const {
26
+ goal,
27
+ minimum,
28
+ result_type,
29
+ execution_result_info: { errors, result },
30
+ } = implementation;
27
31
  const color = selectColor({ errors, result, minimum, goal, result_type });
28
32
  return _.set(color, summary[color] + 1)(summary);
29
33
  },
@@ -71,6 +75,15 @@ const SummaryBar = ({
71
75
  </>
72
76
  );
73
77
 
78
+ SummaryBar.propTypes = {
79
+ key: PropTypes.string,
80
+ className: PropTypes.string,
81
+ summary: PropTypes.object,
82
+ percentages: PropTypes.array,
83
+ showPercentages: PropTypes.bool,
84
+ tooltip: PropTypes.string,
85
+ };
86
+
74
87
  const SummaryBars = (props) => {
75
88
  return (
76
89
  <div className="rule-summary">
@@ -5,26 +5,33 @@ import { Link } from "react-router-dom";
5
5
  import { Button } from "semantic-ui-react";
6
6
  import { FormattedMessage } from "react-intl";
7
7
  import { RULE_NEW } from "@truedat/core/routes";
8
+ import { uploadRules } from "../routines";
9
+ import RulesUploadButton from "./RulesUploadButton";
8
10
 
9
- export const RulesActions = ({ userRulesPermissions }) => (
11
+ export const RulesActions = ({ userRulesPermissions, upload }) => (
10
12
  <div style={{ float: "right" }}>
11
13
  {userRulesPermissions.manage_quality_rules && (
12
- <Button
13
- primary
14
- as={Link}
15
- to={RULE_NEW}
16
- content={<FormattedMessage id="quality.actions.create" />}
17
- />
14
+ <>
15
+ <Button
16
+ primary
17
+ as={Link}
18
+ to={RULE_NEW}
19
+ content={<FormattedMessage id="quality.actions.create" />}
20
+ />
21
+ {upload && <RulesUploadButton />}
22
+ <RulesUploadButton />
23
+ </>
18
24
  )}
19
25
  </div>
20
26
  );
21
27
 
22
28
  RulesActions.propTypes = {
23
- userRulesPermissions: PropTypes.object
29
+ userRulesPermissions: PropTypes.object,
30
+ upload: PropTypes.bool,
24
31
  };
25
32
 
26
33
  const mapStateToProps = ({ userRulesPermissions }) => ({
27
- userRulesPermissions
34
+ userRulesPermissions,
28
35
  });
29
36
 
30
- export default connect(mapStateToProps)(RulesActions);
37
+ export default connect(mapStateToProps)(RulesActions, uploadRules);
@@ -0,0 +1,58 @@
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_RULES_UPLOAD } from "../api";
8
+ import { uploadRules } from "../routines";
9
+
10
+ const uploadAction = {
11
+ method: "POST",
12
+ href: API_RULES_UPLOAD,
13
+ };
14
+
15
+ export const RulesUploadButton = ({ uploadRules, loading }) => {
16
+ const { formatMessage } = useIntl();
17
+ return (
18
+ <UploadModal
19
+ icon="upload"
20
+ trigger={
21
+ <Button
22
+ secondary
23
+ floated="right"
24
+ icon="upload"
25
+ loading={loading}
26
+ data-tooltip={formatMessage({
27
+ id: "rules.actions.upload.tooltip",
28
+ })}
29
+ />
30
+ }
31
+ header={
32
+ <FormattedMessage id="rules.actions.upload.confirmation.header" />
33
+ }
34
+ content={
35
+ <FormattedMessage id="rules.actions.upload.confirmation.content" />
36
+ }
37
+ param={"rules"}
38
+ handleSubmit={(data) =>
39
+ uploadRules({
40
+ action: "upload",
41
+ data,
42
+ ...uploadAction,
43
+ })
44
+ }
45
+ />
46
+ );
47
+ };
48
+
49
+ RulesUploadButton.propTypes = {
50
+ uploadRules: PropTypes.func,
51
+ loading: PropTypes.bool,
52
+ };
53
+
54
+ const mapStateToProps = ({ uploadRulesFile: { loading } }) => ({
55
+ loading,
56
+ });
57
+
58
+ export default connect(mapStateToProps, { uploadRules })(RulesUploadButton);
@@ -11,11 +11,15 @@ describe("<ExecutionGroup />", () => {
11
11
  const rule = {
12
12
  id: 1,
13
13
  name: "rule_name",
14
+ };
15
+ const implementation = {
16
+ id: 1,
17
+ implementation_key: "foo",
18
+ rule_id: 1,
14
19
  result_type: "percentage",
15
20
  minimum: 10,
16
- goal: 20
21
+ goal: 20,
17
22
  };
18
- const implementation = { id: 1, implementation_key: "foo", rule_id: 1 };
19
23
  const result = {
20
24
  id: 1,
21
25
  implementation_key: "foo",
@@ -25,7 +29,7 @@ describe("<ExecutionGroup />", () => {
25
29
  errors: 30,
26
30
  result_type: "percentage",
27
31
  minimum: 10,
28
- goal: 20
32
+ goal: 20,
29
33
  };
30
34
  const quality_events = [
31
35
  {
@@ -33,14 +37,14 @@ describe("<ExecutionGroup />", () => {
33
37
  execution_id: 1,
34
38
  id: 1,
35
39
  type: "SUCCESS",
36
- message: ""
37
- }
40
+ message: "",
41
+ },
38
42
  ];
39
43
  const executions = [
40
- { id: 1, _embedded: { rule, implementation, result, quality_events } }
44
+ { id: 1, _embedded: { rule, implementation, result, quality_events } },
41
45
  ];
42
46
  const props = {
43
- executionGroup: { id: 1, _embedded: { executions } }
47
+ executionGroup: { id: 1, _embedded: { executions } },
44
48
  };
45
49
 
46
50
  it("matches the latest snapshot", () => {