@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
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## [Unreleased]
4
+
5
+ - [TD-4314] Add BulkLoad for `rules`
6
+ - [TD-4301] Add BulkLoad for `implementations`
7
+
8
+ ## [4.34.0] 2021-12-02
9
+
10
+ ### Changed
11
+
12
+ - [TD-4270] Move goal and threshold from Rule to Implementation
13
+ - [TD-4295] Changed how implementation Information section is displayed
14
+
15
+ ## [4.33.10] 2021-11-30
16
+
17
+ - [TD-4306] Fix popups inside execution popup
18
+
19
+ ## [4.33.9] 2021-11-29
20
+
21
+ - [TD-4306] Add `df_content` to execution groups
22
+
3
23
  ## [4.33.6] 2021-11-29
4
24
 
5
25
  ### Added
@@ -16,7 +36,7 @@
16
36
 
17
37
  ### Hotfix
18
38
 
19
- [TD-4327] Fix dropdown domain selector for glossay new quality rule
39
+ - [TD-4327] Fix dropdown domain selector for glossay new quality rule
20
40
 
21
41
  ## [4.31.4] 2021-10-25
22
42
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/dq",
3
- "version": "4.33.8",
3
+ "version": "4.34.2",
4
4
  "description": "Truedat Web Data Quality Module",
5
5
  "sideEffects": false,
6
6
  "jsnext:main": "src/index.js",
@@ -31,7 +31,7 @@
31
31
  "@babel/plugin-transform-modules-commonjs": "^7.15.0",
32
32
  "@babel/preset-env": "^7.15.0",
33
33
  "@babel/preset-react": "^7.14.5",
34
- "@truedat/test": "4.33.8",
34
+ "@truedat/test": "4.34.0",
35
35
  "babel-jest": "^27.0.6",
36
36
  "babel-plugin-dynamic-import-node": "^2.3.3",
37
37
  "babel-plugin-lodash": "^3.3.4",
@@ -82,8 +82,8 @@
82
82
  },
83
83
  "dependencies": {
84
84
  "@apollo/client": "^3.4.10",
85
- "@truedat/core": "4.33.8",
86
- "@truedat/df": "4.33.8",
85
+ "@truedat/core": "4.34.2",
86
+ "@truedat/df": "4.34.2",
87
87
  "axios": "^0.19.2",
88
88
  "graphql": "^15.5.3",
89
89
  "path-to-regexp": "^1.7.0",
@@ -103,5 +103,5 @@
103
103
  "react-dom": ">= 16.8.6 < 17",
104
104
  "semantic-ui-react": ">= 0.88.2 < 2.1"
105
105
  },
106
- "gitHead": "14e8164b15d17c5d25ebd0296b6a9899b32dff1d"
106
+ "gitHead": "8b28a5faca902e9cab3e8b5ab2bc1f8626e3ec7b"
107
107
  }
package/src/api.js CHANGED
@@ -4,6 +4,7 @@ const API_EXECUTION_GROUPS = "/api/execution_groups";
4
4
  const API_RULE = "/api/rules/:id";
5
5
  const API_RULES = "/api/rules";
6
6
  const API_RULES_SEARCH = "/api/rules/search";
7
+ const API_RULES_UPLOAD = "/api/rules/upload";
7
8
  const API_RULE_FILTERS_SEARCH = "/api/rule_filters/search";
8
9
  const API_RULE_IMPLEMENTATION = "/api/rule_implementations/:id";
9
10
  const API_RULE_IMPLEMENTATIONS = "/api/rule_implementations";
@@ -13,6 +14,7 @@ const API_RULE_IMPLEMENTATIONS_FROM_RULE =
13
14
  const API_RULE_IMPLEMENTATIONS_SEARCH = "/api/rule_implementations/search";
14
15
  const API_RULE_IMPLEMENTATION_FILTERS_SEARCH =
15
16
  "/api/rule_implementation_filters/search";
17
+ const API_RULE_IMPLEMENTATIONS_UPLOAD = "/api/rule_implementations/upload";
16
18
  const API_RULE_RESULT = "/api/rule_results/:id";
17
19
  const API_SUBSCRIPTIONS_SEARCH = "/api/subscriptions/user/me/search";
18
20
  const API_SUBSCRIPTION = "/api/subscriptions/:id";
@@ -25,6 +27,7 @@ export {
25
27
  API_RULE,
26
28
  API_RULES,
27
29
  API_RULES_SEARCH,
30
+ API_RULES_UPLOAD,
28
31
  API_RULE_FILTERS_SEARCH,
29
32
  API_RULE_IMPLEMENTATION,
30
33
  API_RULE_IMPLEMENTATIONS,
@@ -32,8 +35,9 @@ export {
32
35
  API_RULE_IMPLEMENTATIONS_FROM_RULE,
33
36
  API_RULE_IMPLEMENTATIONS_SEARCH,
34
37
  API_RULE_IMPLEMENTATION_FILTERS_SEARCH,
38
+ API_RULE_IMPLEMENTATIONS_UPLOAD,
35
39
  API_RULE_RESULT,
36
40
  API_SUBSCRIPTIONS_SEARCH,
37
41
  API_SUBSCRIPTION,
38
- API_SUBSCRIPTIONS
42
+ API_SUBSCRIPTIONS,
39
43
  };
@@ -1,7 +1,7 @@
1
1
  import _ from "lodash/fp";
2
2
  import React, { Fragment } from "react";
3
3
  import PropTypes from "prop-types";
4
- import { Header, Icon, Table } from "semantic-ui-react";
4
+ import { Header, Icon, Segment, Table } 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";
@@ -168,26 +168,28 @@ export const ConditionSummary = ({ rows, type, icon }) =>
168
168
  />
169
169
  </Header.Content>
170
170
  </Header>
171
- <Table basic="very">
172
- <Table.Header>
173
- <Table.Row>
174
- <Table.HeaderCell>
175
- <FormattedMessage id={`ruleImplementation.summary.field`} />
176
- </Table.HeaderCell>
177
- <Table.HeaderCell>
178
- <FormattedMessage id={`ruleImplementation.summary.operator`} />
179
- </Table.HeaderCell>
180
- <Table.HeaderCell>
181
- <FormattedMessage id={`ruleImplementation.summary.values`} />
182
- </Table.HeaderCell>
183
- </Table.Row>
184
- </Table.Header>
185
- <Table.Body>
186
- {rows.map((row, i) => (
187
- <ConditionCell key={i} row={row} />
188
- ))}
189
- </Table.Body>
190
- </Table>
171
+ <Segment>
172
+ <Table basic="very">
173
+ <Table.Header>
174
+ <Table.Row>
175
+ <Table.HeaderCell>
176
+ <FormattedMessage id={`ruleImplementation.summary.field`} />
177
+ </Table.HeaderCell>
178
+ <Table.HeaderCell>
179
+ <FormattedMessage id={`ruleImplementation.summary.operator`} />
180
+ </Table.HeaderCell>
181
+ <Table.HeaderCell>
182
+ <FormattedMessage id={`ruleImplementation.summary.values`} />
183
+ </Table.HeaderCell>
184
+ </Table.Row>
185
+ </Table.Header>
186
+ <Table.Body>
187
+ {rows.map((row, i) => (
188
+ <ConditionCell key={i} row={row} />
189
+ ))}
190
+ </Table.Body>
191
+ </Table>
192
+ </Segment>
191
193
  </>
192
194
  );
193
195
 
@@ -8,7 +8,7 @@ import { Table, Message, Icon } from "semantic-ui-react";
8
8
  import { DateTime } from "@truedat/core/components";
9
9
  import { selectColor } from "../functions/selectors";
10
10
 
11
- const GeneralInformation = ({ rule, ruleResult }) => {
11
+ const GeneralInformation = ({ ruleImplementation, ruleResult }) => {
12
12
  const { formatMessage, formatNumber: _formatNumber } = useIntl();
13
13
  const formatNumber = (num) => (_.isNil(num) ? num : _formatNumber(num));
14
14
  return (
@@ -18,7 +18,10 @@ const GeneralInformation = ({ rule, ruleResult }) => {
18
18
  {formatMessage({ id: "ruleResult.props.quality" })}
19
19
  </Table.Cell>
20
20
  <Table.Cell>
21
- <Icon name="circle" color={selectColor({ ...rule, ...ruleResult })} />
21
+ <Icon
22
+ name="circle"
23
+ color={selectColor({ ...ruleImplementation, ...ruleResult })}
24
+ />
22
25
  {`${parseFloat(ruleResult.result)} %`}
23
26
  </Table.Cell>
24
27
  </Table.Row>
@@ -50,7 +53,7 @@ const GeneralInformation = ({ rule, ruleResult }) => {
50
53
  };
51
54
 
52
55
  GeneralInformation.propTypes = {
53
- rule: PropTypes.object,
56
+ ruleImplementation: PropTypes.object,
54
57
  ruleResult: PropTypes.object,
55
58
  };
56
59
 
@@ -70,11 +73,7 @@ const DetailRow = ({ details }) => {
70
73
  )(details);
71
74
  };
72
75
 
73
- export const ExecutionDetails = ({
74
- rule,
75
- ruleImplementation,
76
- rule_result_id,
77
- }) => {
76
+ export const ExecutionDetails = ({ ruleImplementation, rule_result_id }) => {
78
77
  const { formatMessage } = useIntl();
79
78
  const { rule_result_id: id } = useParams();
80
79
 
@@ -104,7 +103,10 @@ export const ExecutionDetails = ({
104
103
  </Table.Row>
105
104
  </Table.Header>
106
105
  <Table.Body>
107
- <GeneralInformation rule={rule} ruleResult={ruleResult} />
106
+ <GeneralInformation
107
+ ruleImplementation={ruleImplementation}
108
+ ruleResult={ruleResult}
109
+ />
108
110
  </Table.Body>
109
111
 
110
112
  <Table.Header>
@@ -126,16 +128,11 @@ export const ExecutionDetails = ({
126
128
 
127
129
  ExecutionDetails.propTypes = {
128
130
  ruleImplementation: PropTypes.object,
129
- rule: PropTypes.object,
130
- customColumns: PropTypes.array,
131
- isAdmin: PropTypes.bool,
132
131
  rule_result_id: PropTypes.number,
133
132
  };
134
133
 
135
134
  const mapStateToProps = (state) => ({
136
- rule: state.rule,
137
135
  ruleImplementation: state.ruleImplementation,
138
- isAdmin: state.authentication.role === "admin",
139
136
  });
140
137
 
141
138
  export default connect(mapStateToProps)(ExecutionDetails);
@@ -0,0 +1,116 @@
1
+ import _ from "lodash/fp";
2
+ import React, { Suspense, useState } from "react";
3
+ import PropTypes from "prop-types";
4
+ import { connect } from "react-redux";
5
+ import { useIntl } from "react-intl";
6
+ import { Button, Form, Header } from "semantic-ui-react";
7
+ import { validateContent } from "@truedat/df/utils";
8
+ import { selectTemplate } from "@truedat/df/routines";
9
+
10
+ const TemplateSelector = React.lazy(() =>
11
+ import("@truedat/df/templates/components/TemplateSelector")
12
+ );
13
+
14
+ const TemplateLoader = React.lazy(() =>
15
+ import("@truedat/df/templates/components/TemplateLoader")
16
+ );
17
+
18
+ const DynamicForm = React.lazy(() =>
19
+ import("@truedat/df/components/DynamicForm")
20
+ );
21
+
22
+ export const ExecutionForm = ({
23
+ count,
24
+ selectTemplate,
25
+ template,
26
+ templates,
27
+ handleSubmit,
28
+ onCancel,
29
+ }) => {
30
+ const { formatMessage } = useIntl();
31
+ const [content, setContent] = useState({});
32
+
33
+ const handleContentChange = (content) => setContent(content);
34
+
35
+ const handleTemplateSelected = (e, { value }) =>
36
+ selectTemplate({ id: value });
37
+
38
+ const isInvalid = () =>
39
+ template && !_.isEmpty(validateContent(template)(content));
40
+
41
+ if (_.size(templates) == 1) {
42
+ const id = _.flow(_.head, _.prop("id"))(templates);
43
+ selectTemplate({ id });
44
+ }
45
+
46
+ return (
47
+ <>
48
+ <Header
49
+ as="h2"
50
+ content={formatMessage({
51
+ id: "implementations.actions.execution.confirmation.header",
52
+ })}
53
+ />
54
+ <Suspense fallback={null}>
55
+ <Form>
56
+ <TemplateLoader scope="qe" />
57
+ {_.size(templates) > 1 && (
58
+ <TemplateSelector
59
+ name="template"
60
+ selectedValue={_.prop("id")(template)}
61
+ onChange={handleTemplateSelected}
62
+ isOptional={true}
63
+ />
64
+ )}
65
+ {template && template.id && (
66
+ <>
67
+ <Header
68
+ as="h3"
69
+ content={formatMessage({
70
+ id: "implementations.actions.execution.confirmation.legend",
71
+ })}
72
+ />
73
+ <div
74
+ style={{ maxHeight: "calc(100vh - 550px)", overflowY: "auto" }}
75
+ >
76
+ <DynamicForm onChange={handleContentChange} content={content} />
77
+ </div>
78
+ </>
79
+ )}
80
+ <p>
81
+ {formatMessage(
82
+ { id: "implementations.actions.execution.confirmation.content" },
83
+ { implementations_count: count }
84
+ )}
85
+ </p>
86
+ <div className="actions">
87
+ <Button
88
+ secondary
89
+ onClick={onCancel}
90
+ content={formatMessage({ id: "actions.cancel" })}
91
+ />
92
+ <Button
93
+ primary
94
+ disabled={isInvalid()}
95
+ onClick={() => handleSubmit(content)}
96
+ content={formatMessage({ id: "actions.create" })}
97
+ />
98
+ </div>
99
+ </Form>
100
+ </Suspense>
101
+ </>
102
+ );
103
+ };
104
+
105
+ ExecutionForm.propTypes = {
106
+ count: PropTypes.number,
107
+ template: PropTypes.object,
108
+ templates: PropTypes.array,
109
+ selectTemplate: PropTypes.func,
110
+ handleSubmit: PropTypes.func,
111
+ onCancel: PropTypes.func,
112
+ };
113
+
114
+ const mapStateToProps = _.pick(["templates", "template"]);
115
+
116
+ export default connect(mapStateToProps, { selectTemplate })(ExecutionForm);
@@ -1,4 +1,4 @@
1
- import { flow, pick, reject, size, sortBy } from "lodash/fp";
1
+ import { flow, pick, filter, reject, size, prop, sortBy } from "lodash/fp";
2
2
  import React from "react";
3
3
  import PropTypes from "prop-types";
4
4
  import { connect } from "react-redux";
@@ -15,41 +15,41 @@ const columns = [
15
15
  {
16
16
  name: "ruleImplementations.props.status",
17
17
  fieldDecorator: RuleEventDecorator,
18
- fieldSelector: pick(["_embedded.quality_events"])
18
+ fieldSelector: pick(["_embedded.quality_events"]),
19
19
  },
20
20
  {
21
21
  name: "ruleImplementations.props.implementation_key",
22
22
  fieldSelector: "_embedded.implementation",
23
- fieldDecorator: RuleImplementationResultsLink
23
+ fieldDecorator: RuleImplementationResultsLink,
24
24
  },
25
25
  {
26
26
  name: "rule.props.name",
27
- fieldSelector: "_embedded.rule.name"
27
+ fieldSelector: "_embedded.rule.name",
28
28
  },
29
29
  {
30
30
  name: "ruleResult.props.date",
31
31
  fieldDecorator: DateTime,
32
32
  textAlign: "center",
33
- fieldSelector: ({ _embedded }) => ({ value: _embedded?.result?.date })
33
+ fieldSelector: ({ _embedded }) => ({ value: _embedded?.result?.date }),
34
34
  },
35
35
  {
36
36
  name: "ruleResult.props.records",
37
37
  textAlign: "right",
38
- fieldSelector: "_embedded.result.records"
38
+ fieldSelector: "_embedded.result.records",
39
39
  },
40
40
  {
41
41
  name: "ruleResult.props.errors",
42
42
  textAlign: "right",
43
- fieldSelector: "_embedded.result.errors"
43
+ fieldSelector: "_embedded.result.errors",
44
44
  },
45
45
  {
46
46
  name: "ruleResult.props.quality",
47
47
  fieldSelector: ({ _embedded }) => ({
48
48
  ruleResult: _embedded?.result,
49
- rule: _embedded?.rule
49
+ ruleImplementation: _embedded?.implementation,
50
50
  }),
51
- fieldDecorator: RuleResultDecorator
52
- }
51
+ fieldDecorator: RuleResultDecorator,
52
+ },
53
53
  ];
54
54
 
55
55
  export const ExecutionRow = ({ execution }) => (
@@ -65,7 +65,7 @@ export const ExecutionRow = ({ execution }) => (
65
65
  );
66
66
 
67
67
  ExecutionRow.propTypes = {
68
- execution: PropTypes.object
68
+ execution: PropTypes.object,
69
69
  };
70
70
 
71
71
  export const ExecutionGroup = ({ executionGroup, executionGroupLoading }) => {
@@ -74,10 +74,19 @@ export const ExecutionGroup = ({ executionGroup, executionGroupLoading }) => {
74
74
  executionGroup?._embedded?.executions
75
75
  );
76
76
  const count = size(executions);
77
- const pendingCount = flow(reject("_embedded.result"), size)(executions);
77
+ const missingResultCount = flow(reject("_embedded.result"), size)(executions);
78
+ const errorCount = flow(
79
+ filter(flow(prop("_embedded.quality_events"), size)),
80
+ size
81
+ )(executions);
82
+
78
83
  return executionGroupLoading ? null : (
79
84
  <>
80
- <ExecutionGroupMessage count={count} pending={pendingCount} />
85
+ <ExecutionGroupMessage
86
+ count={count}
87
+ pending={missingResultCount - errorCount}
88
+ error={errorCount}
89
+ />
81
90
  <Table>
82
91
  <Table.Header>
83
92
  <Table.Row>
@@ -102,12 +111,12 @@ export const ExecutionGroup = ({ executionGroup, executionGroupLoading }) => {
102
111
 
103
112
  ExecutionGroup.propTypes = {
104
113
  executionGroup: PropTypes.object,
105
- executionGroupLoading: PropTypes.bool
114
+ executionGroupLoading: PropTypes.bool,
106
115
  };
107
116
 
108
117
  export const mapStateToProps = ({ executionGroup, executionGroupLoading }) => ({
109
118
  executionGroup,
110
- executionGroupLoading
119
+ executionGroupLoading,
111
120
  });
112
121
 
113
122
  export default connect(mapStateToProps)(ExecutionGroup);
@@ -0,0 +1,58 @@
1
+ import _ from "lodash/fp";
2
+ import React, { useState } from "react";
3
+ import PropTypes from "prop-types";
4
+ import { connect } from "react-redux";
5
+ import { useIntl } from "react-intl";
6
+ import { Button, Popup } from "semantic-ui-react";
7
+ import ExecutionForm from "./ExecutionForm";
8
+
9
+ export const ExecutionPopup = ({
10
+ disabled,
11
+ executionGroupLoading,
12
+ count,
13
+ handleSubmit,
14
+ }) => {
15
+ const { formatMessage } = useIntl();
16
+ const [open, setOpen] = useState(false);
17
+
18
+ return (
19
+ <Popup
20
+ on="click"
21
+ basic
22
+ flowing
23
+ onOpen={() => setOpen(true)}
24
+ onClose={() => false}
25
+ open={open}
26
+ position="bottom right"
27
+ size="large"
28
+ positionFixed
29
+ trigger={
30
+ <Button
31
+ secondary
32
+ disabled={disabled}
33
+ loading={executionGroupLoading}
34
+ content={formatMessage({
35
+ id: "implementations.actions.do_execution",
36
+ })}
37
+ />
38
+ }
39
+ >
40
+ <ExecutionForm
41
+ count={count}
42
+ handleSubmit={handleSubmit}
43
+ onCancel={() => setOpen(false)}
44
+ />
45
+ </Popup>
46
+ );
47
+ };
48
+
49
+ ExecutionPopup.propTypes = {
50
+ count: PropTypes.number,
51
+ disabled: PropTypes.bool,
52
+ executionGroupLoading: PropTypes.bool,
53
+ handleSubmit: PropTypes.func,
54
+ };
55
+
56
+ const mapStateToProps = _.pick(["executionGroupLoading"]);
57
+
58
+ export default connect(mapStateToProps)(ExecutionPopup);
@@ -0,0 +1,80 @@
1
+ import _ from "lodash/fp";
2
+ import React from "react";
3
+ import PropTypes from "prop-types";
4
+ import { Popup } from "semantic-ui-react";
5
+ import { Link } from "react-router-dom";
6
+ import { FormattedMessage, useIntl } from "react-intl";
7
+ import { linkTo } from "@truedat/core/routes";
8
+ import { calculateResultDecoration } from "./RuleResultDecorator";
9
+ import "../styles/ruleSummary.less";
10
+
11
+ export default function ImplementationResultBar({ implementation }) {
12
+ const intl = useIntl();
13
+ const ruleResult = _.head(implementation?.results);
14
+ const { color, resultText } =
15
+ implementation.event_type === "FAILED"
16
+ ? {
17
+ color: "failed",
18
+ resultText: intl.formatMessage({ id: "quality.error" }),
19
+ }
20
+ : calculateResultDecoration({
21
+ ruleResult,
22
+ ruleImplementation: implementation,
23
+ date: ruleResult?.date,
24
+ intl,
25
+ });
26
+
27
+ const propsByColor = {
28
+ red: {
29
+ className: "under-minimum-color",
30
+ tooltip: "under_minimum",
31
+ },
32
+ yellow: {
33
+ className: "under-goal-color",
34
+ tooltip: "under_goal",
35
+ },
36
+ green: {
37
+ className: "over-goal-color",
38
+ tooltip: "over_goal",
39
+ },
40
+ grey: {
41
+ className: "not-executed-color",
42
+ tooltip: "no_execution",
43
+ },
44
+ failed: {
45
+ className: "failed-color",
46
+ tooltip: "failed",
47
+ },
48
+ };
49
+ const summaryProps = propsByColor[color];
50
+ return (
51
+ <div className="rule-summary-wrapper">
52
+ <Link
53
+ as="div"
54
+ className="rule-summary pointer"
55
+ to={linkTo.RULE_IMPLEMENTATION_RESULTS({
56
+ id: implementation.rule_id,
57
+ implementation_id: implementation.id,
58
+ })}
59
+ >
60
+ <Popup
61
+ position="bottom center"
62
+ basic
63
+ on="hover"
64
+ content={
65
+ <FormattedMessage id={`quality_result.${summaryProps.tooltip}`} />
66
+ }
67
+ trigger={
68
+ <span className={summaryProps.className} style={{ width: "100%" }}>
69
+ <span className="value">{resultText}</span>
70
+ </span>
71
+ }
72
+ />
73
+ </Link>
74
+ </div>
75
+ );
76
+ }
77
+
78
+ ImplementationResultBar.propTypes = {
79
+ implementation: PropTypes.object.isRequired,
80
+ };