@truedat/dq 4.42.5 → 4.43.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/package.json +5 -5
  3. package/src/api.js +8 -0
  4. package/src/components/ConditionSummary.js +1 -0
  5. package/src/components/FieldSummary.js +86 -0
  6. package/src/components/ImplementationStructureDelete.js +41 -0
  7. package/src/components/ImplementationStructureLink.js +24 -0
  8. package/src/components/ImplementationStructures.js +138 -0
  9. package/src/components/ImplementationStructuresNew.js +125 -0
  10. package/src/components/ImplementationSummary.js +11 -1
  11. package/src/components/NewRemediation.js +27 -20
  12. package/src/components/NewRuleImplementation.js +42 -6
  13. package/src/components/RemediationPlan.js +47 -78
  14. package/src/components/RuleImplementationProperties.js +2 -1
  15. package/src/components/RuleImplementationResultTabs.js +113 -0
  16. package/src/components/RuleImplementationResults.js +1 -1
  17. package/src/components/RuleImplementationTabs.js +16 -1
  18. package/src/components/RuleImplementationsTable.js +10 -3
  19. package/src/components/RuleResult.js +108 -0
  20. package/src/components/{ExecutionDetails.js → RuleResultDetails.js} +4 -21
  21. package/src/components/RuleResultRemediationLoader.js +44 -0
  22. package/src/components/RuleResultRemediations.js +47 -0
  23. package/src/components/RuleResultRow.js +0 -3
  24. package/src/components/RuleResultSegmentRow.js +83 -0
  25. package/src/components/RuleResultSegments.js +102 -0
  26. package/src/components/RuleResultSegmentsLoader.js +34 -0
  27. package/src/components/RuleResultsRoutes.js +73 -0
  28. package/src/components/RuleRoutes.js +38 -12
  29. package/src/components/__test_samples__/NewRuleImplementationProps.js +22 -2
  30. package/src/components/__tests__/ExecutionDetails.spec.js +5 -5
  31. package/src/components/__tests__/ImplementationStructureDelete.spec.js +27 -0
  32. package/src/components/__tests__/ImplementationStructureLink.spec.js +23 -0
  33. package/src/components/__tests__/ImplementationStructures.spec.js +88 -0
  34. package/src/components/__tests__/ImplementationStructuresNew.spec.js +34 -0
  35. package/src/components/__tests__/NewRuleImplementation.spec.js +27 -7
  36. package/src/components/__tests__/RuleImplementation.spec.js +2 -1
  37. package/src/components/__tests__/RuleImplementationTabs.spec.js +2 -1
  38. package/src/components/__tests__/RuleResultSegmentsLoader.spec.js +32 -0
  39. package/src/components/__tests__/__snapshots__/ExecutionDetails.spec.js.snap +2 -30
  40. package/src/components/__tests__/__snapshots__/ImplementationStructureDelete.spec.js.snap +10 -0
  41. package/src/components/__tests__/__snapshots__/ImplementationStructureLink.spec.js.snap +11 -0
  42. package/src/components/__tests__/__snapshots__/ImplementationStructures.spec.js.snap +208 -0
  43. package/src/components/__tests__/__snapshots__/ImplementationStructuresNew.spec.js.snap +106 -0
  44. package/src/components/__tests__/__snapshots__/NewRuleImplementation.spec.js.snap +1211 -1217
  45. package/src/components/__tests__/__snapshots__/RuleImplementation.spec.js.snap +7 -1
  46. package/src/components/__tests__/__snapshots__/RuleImplementationProperties.spec.js.snap +1 -0
  47. package/src/components/__tests__/__snapshots__/RuleImplementationTabs.spec.js.snap +8 -2
  48. package/src/components/index.js +2 -2
  49. package/src/components/ruleImplementationForm/FieldsGrid.js +57 -0
  50. package/src/components/ruleImplementationForm/FieldsGroup.js +107 -0
  51. package/src/components/ruleImplementationForm/RuleImplementationForm.js +45 -0
  52. package/src/components/ruleImplementationForm/SegmentsForm.js +35 -0
  53. package/src/components/ruleImplementationForm/__tests__/RuleImplementationForm.spec.js +27 -10
  54. package/src/components/ruleImplementationForm/__tests__/__snapshots__/RuleImplementationForm.spec.js.snap +315 -91
  55. package/src/messages/en.js +20 -1
  56. package/src/messages/es.js +21 -1
  57. package/src/reducers/__tests__/segmentResult.spec.js +46 -0
  58. package/src/reducers/index.js +2 -0
  59. package/src/reducers/ruleImplementation.js +2 -0
  60. package/src/reducers/ruleImplementationRedirect.js +4 -0
  61. package/src/reducers/segmentResults.js +19 -0
  62. package/src/routines.js +10 -0
  63. package/src/sagas/__tests__/createImplementationStructure.spec.js +86 -0
  64. package/src/sagas/__tests__/deleteImplementationStructure.spec.js +84 -0
  65. package/src/sagas/__tests__/fetchSegmentResults.spec.js +78 -0
  66. package/src/sagas/createImplementationStructure.js +32 -0
  67. package/src/sagas/deleteImplementationStructure.js +37 -0
  68. package/src/sagas/fetchSegmentResults.js +30 -0
  69. package/src/sagas/index.js +19 -10
  70. package/src/services/encodeRawContent.js +5 -5
  71. package/src/styles/remediationPlan.less +5 -0
  72. package/src/styles/ruleImplementationForm/DatasetForm.less +5 -0
@@ -224,8 +224,8 @@ const updateStructureParentIndex = (structures) => (structure) => {
224
224
  return structure;
225
225
  };
226
226
 
227
- const withConditionDefaultAlias = (conditions, structures) =>
228
- _.map((p) => {
227
+ const withConditionDefaultAlias = (conditions, structures) => {
228
+ return _.map((p) => {
229
229
  return {
230
230
  ...p,
231
231
  structure: updateStructureParentIndex(structures)(p.structure),
@@ -235,6 +235,7 @@ const withConditionDefaultAlias = (conditions, structures) =>
235
235
  : p.value,
236
236
  };
237
237
  })(conditions);
238
+ };
238
239
 
239
240
  export const NewRuleImplementation = ({
240
241
  canManageRaw,
@@ -296,6 +297,18 @@ export const NewRuleImplementation = ({
296
297
  ),
297
298
  precalculatedDataset
298
299
  ),
300
+ segments: withConditionDefaultAlias(
301
+ addFieldType(
302
+ ruleImplementationProps,
303
+ structuresFields,
304
+ structuresSiblings,
305
+ "segments",
306
+ "segment",
307
+ { name: "" }
308
+ ),
309
+ precalculatedDataset
310
+ ),
311
+
299
312
  rawContent: {
300
313
  ..._.prop("raw_content")(ruleImplementationProps),
301
314
  },
@@ -313,12 +326,14 @@ export const NewRuleImplementation = ({
313
326
  population: [],
314
327
  populations: [],
315
328
  validations: [{}],
329
+ segments: [{}],
316
330
  rawContent: {
317
331
  database: "",
318
332
  source_id: null,
319
333
  dataset: "",
320
334
  population: "",
321
335
  validations: "",
336
+ segments: "",
322
337
  },
323
338
  dfName: "",
324
339
  dfContent: {},
@@ -380,6 +395,12 @@ export const NewRuleImplementation = ({
380
395
  _.filter((val) => valueInDataset(val))
381
396
  )(ruleImplementation);
382
397
 
398
+ const segments_within_dataset = _.flow(
399
+ _.prop("segments"),
400
+ _.filter((val) => belongsToDataset(_.path("structure.id")(val))),
401
+ _.filter((val) => valueInDataset(val))
402
+ )(ruleImplementation);
403
+
383
404
  const population_within_dataset = _.flow(
384
405
  _.prop("population"),
385
406
  _.filter((val) => belongsToDataset(_.path("structure.id")(val))),
@@ -395,16 +416,15 @@ export const NewRuleImplementation = ({
395
416
  validations: _.isEmpty(validations_within_dataset)
396
417
  ? [{}]
397
418
  : validations_within_dataset,
419
+ segments: _.isEmpty(segments_within_dataset)
420
+ ? []
421
+ : segments_within_dataset,
398
422
  });
399
423
  };
400
424
 
401
425
  const onChange = (prop, value) =>
402
426
  setRuleImplementation({ ...ruleImplementation, [prop]: value });
403
427
 
404
- const setPopulation = (population) => {
405
- setRuleImplementation({ ...ruleImplementation, population });
406
- };
407
-
408
428
  const addPopulation = () => {
409
429
  const populations = _.concat(
410
430
  _.pathOr([], "populations")(ruleImplementation)
@@ -426,6 +446,18 @@ export const NewRuleImplementation = ({
426
446
  setRuleImplementation({ ...ruleImplementation, validations });
427
447
  };
428
448
 
449
+ const addSegments = () => {
450
+ const segments = _.concat(_.pathOr([], "segments")(ruleImplementation))([
451
+ {},
452
+ ]);
453
+ setRuleImplementation({ ...ruleImplementation, segments });
454
+ };
455
+
456
+ const setSegments = (segments) => {
457
+ const newSegments = _.isEqual([{}])(segments) ? [] : segments;
458
+ setRuleImplementation({ ...ruleImplementation, segments: newSegments });
459
+ };
460
+
429
461
  const setImplementationKey = (implementationKey) =>
430
462
  setRuleImplementation({ ...ruleImplementation, implementationKey });
431
463
 
@@ -449,6 +481,7 @@ export const NewRuleImplementation = ({
449
481
  const validations = _.filter(_.negate(_.isEmpty))(
450
482
  ruleImplementation.validations
451
483
  );
484
+ const segments = _.filter(_.negate(_.isEmpty))(ruleImplementation.segments);
452
485
 
453
486
  const dfContent = _.flow(
454
487
  _.prop("dfContent"),
@@ -481,6 +514,7 @@ export const NewRuleImplementation = ({
481
514
  dataset: datasetAttributes(_.prop("dataset")(ruleImplementation)),
482
515
  populations: populationsAttributes(populations),
483
516
  validations: conditionAttributes(validations),
517
+ segments,
484
518
  implementation_key: _.prop("implementationKey")(ruleImplementation),
485
519
  implementation_type:
486
520
  _.prop("implementationType")(ruleImplementation),
@@ -562,6 +596,8 @@ export const NewRuleImplementation = ({
562
596
  addPopulation={addPopulation}
563
597
  setPopulations={setPopulations}
564
598
  setValidations={setValidations}
599
+ addSegments={addSegments}
600
+ setSegments={setSegments}
565
601
  operators={operators}
566
602
  setImplementationKey={setImplementationKey}
567
603
  onChange={onChange}
@@ -4,17 +4,14 @@ import PropTypes from "prop-types";
4
4
  import { connect } from "react-redux";
5
5
  import { useIntl } from "react-intl";
6
6
  import { useParams } from "react-router-dom";
7
- import { Button, Header, Icon, Grid, Segment } from "semantic-ui-react";
7
+ import { Button, Grid, Container } from "semantic-ui-react";
8
8
  import { FormattedMessage } from "react-intl";
9
9
  import { Loading } from "@truedat/core/components";
10
10
  import { ConfirmModal } from "@truedat/core/components";
11
- import {
12
- fetchRemediation,
13
- clearRemediation,
14
- deleteRemediation,
15
- } from "../routines";
11
+ import { deleteRemediation } from "../routines";
16
12
  import NewRemediation from "./NewRemediation";
17
13
  import RemediationForm from "./RemediationForm";
14
+
18
15
  import "../styles/remediationPlan.less";
19
16
 
20
17
  const DynamicFormViewer = React.lazy(() =>
@@ -23,10 +20,7 @@ const DynamicFormViewer = React.lazy(() =>
23
20
 
24
21
  export const RemediationPlan = ({
25
22
  isLoading,
26
- className,
27
23
  deleteRemediation,
28
- fetchRemediation,
29
- clearRemediation,
30
24
  remediation,
31
25
  templates,
32
26
  latestResultId,
@@ -44,17 +38,6 @@ export const RemediationPlan = ({
44
38
  setRuleResultId(paramsRuleResultId || latestResultId);
45
39
  }, [paramsRuleResultId, latestResultId]);
46
40
 
47
- useEffect(() => {
48
- ruleResultId && fetchRemediation({ rule_result_id: ruleResultId });
49
- }, [fetchRemediation, ruleResultId]);
50
-
51
- useEffect(
52
- () => () => {
53
- clearRemediation();
54
- },
55
- [clearRemediation]
56
- );
57
-
58
41
  const onSave = () => {
59
42
  setIsEdit(false);
60
43
  };
@@ -70,67 +53,58 @@ export const RemediationPlan = ({
70
53
  <>
71
54
  {!_.isEmpty(remediation) ? (
72
55
  <>
73
- <Header as="h2">
74
- <Icon circular name="rain" />
75
- <Header.Content>
76
- <FormattedMessage
77
- id={!isEdit ? "remediation" : "remediation.actions.edit"}
56
+ {manageRemediations ? (
57
+ <div className="ui actions remediation">
58
+ <ConfirmModal
59
+ icon="trash"
60
+ trigger={<Button secondary icon="trash" basic color="red" />}
61
+ header={
62
+ <FormattedMessage id="remediation.actions.delete.confirmation.header" />
63
+ }
64
+ content={
65
+ <FormattedMessage
66
+ id="remediation.actions.delete.confirmation.content"
67
+ values={{ ruleResultId: <b>{ruleResultId}</b> }}
68
+ />
69
+ }
70
+ onConfirm={() =>
71
+ deleteRemediation({
72
+ implementation_id: implementationId,
73
+ rule_result_id: ruleResultId,
74
+ })
75
+ }
76
+ />
77
+ <Button
78
+ className="button-edit-remediation"
79
+ primary
80
+ onClick={() => setIsEdit(!isEdit)}
81
+ content={formatMessage({
82
+ id: !isEdit ? "actions.edit" : "actions.cancel",
83
+ })}
78
84
  />
79
- </Header.Content>
80
- </Header>
85
+ </div>
86
+ ) : null}
81
87
 
82
- <Segment className={className}>
83
- {manageRemediations ? (
84
- <div className="ui actions remediation">
85
- <ConfirmModal
86
- icon="trash"
87
- trigger={<Button secondary icon="trash" basic color="red" />}
88
- header={
89
- <FormattedMessage id="remediation.actions.delete.confirmation.header" />
90
- }
91
- content={
92
- <FormattedMessage
93
- id="remediation.actions.delete.confirmation.content"
94
- values={{ ruleResultId: <b>{ruleResultId}</b> }}
95
- />
96
- }
97
- onConfirm={() =>
98
- deleteRemediation({
99
- implementation_id: implementationId,
100
- rule_result_id: ruleResultId,
101
- })
102
- }
103
- />
104
- <Button
105
- className="button-edit-remediation"
106
- primary
107
- onClick={() => setIsEdit(!isEdit)}
108
- content={formatMessage({
109
- id: !isEdit ? "actions.edit" : "actions.cancel",
110
- })}
88
+ <Grid>
89
+ <Grid.Column width={8}>
90
+ {!isEdit && remediation?.df_name ? (
91
+ <DynamicFormViewer
92
+ template={_.find(_.propEq("name", remediation.df_name))(
93
+ templates
94
+ )}
95
+ content={remediation.df_content}
111
96
  />
112
- </div>
113
- ) : null}
114
-
115
- <Grid>
116
- <Grid.Column width={8}>
117
- {!isEdit && remediation?.df_name ? (
118
- <DynamicFormViewer
119
- template={_.find(_.propEq("name", remediation.df_name))(
120
- templates
121
- )}
122
- content={remediation.df_content}
123
- />
124
- ) : (
97
+ ) : (
98
+ <Container className="new-remedation-container" fluid>
125
99
  <RemediationForm
126
100
  onSave={onSave}
127
101
  remediation={remediation}
128
102
  latestResultId={latestResultId}
129
103
  />
130
- )}
131
- </Grid.Column>
132
- </Grid>
133
- </Segment>
104
+ </Container>
105
+ )}
106
+ </Grid.Column>
107
+ </Grid>
134
108
  </>
135
109
  ) : null}
136
110
  </>
@@ -139,10 +113,7 @@ export const RemediationPlan = ({
139
113
 
140
114
  RemediationPlan.propTypes = {
141
115
  isLoading: PropTypes.bool,
142
- className: PropTypes.string,
143
116
  deleteRemediation: PropTypes.func,
144
- clearRemediation: PropTypes.func,
145
- fetchRemediation: PropTypes.func,
146
117
  remediation: PropTypes.object,
147
118
  templates: PropTypes.array,
148
119
  latestResultId: PropTypes.number,
@@ -164,6 +135,4 @@ const mapStateToProps = ({
164
135
 
165
136
  export default connect(mapStateToProps, {
166
137
  deleteRemediation,
167
- fetchRemediation,
168
- clearRemediation,
169
138
  })(RemediationPlan);
@@ -12,7 +12,7 @@ const DynamicFormViewer = React.lazy(() =>
12
12
  import("@truedat/df/components/DynamicFormViewer")
13
13
  );
14
14
 
15
- const summarySteps = ["dataset", "populations", "validations"];
15
+ const summarySteps = ["dataset", "populations", "validations", "segments"];
16
16
 
17
17
  export const RuleImplementationProperties = ({
18
18
  ruleImplementation,
@@ -75,6 +75,7 @@ const mapStateToProps = ({
75
75
  ruleImplementation: _.pick([
76
76
  ...summarySteps,
77
77
  "populations",
78
+ "segments",
78
79
  "executable",
79
80
  "event_type",
80
81
  "event_message",
@@ -0,0 +1,113 @@
1
+ import _ from "lodash/fp";
2
+ import React from "react";
3
+ import PropTypes from "prop-types";
4
+ import { Menu } from "semantic-ui-react";
5
+ import { Link, withRouter } from "react-router-dom";
6
+ import { compose } from "redux";
7
+ import { connect } from "react-redux";
8
+ import { FormattedMessage } from "react-intl";
9
+ import {
10
+ RULE_IMPLEMENTATION_RESULT_DETAILS,
11
+ RULE_IMPLEMENTATION_RESULT_SEGMENTS_RESULTS,
12
+ //TODO: change name route
13
+ RULE_IMPLEMENTATION_RESULT_DETAILS_REMEDIATION_PLAN,
14
+ linkTo,
15
+ } from "@truedat/core/routes";
16
+
17
+ import RuleResultRemediationLoader from "./RuleResultRemediationLoader";
18
+ const TemplatesLoader = React.lazy(() =>
19
+ import("@truedat/df/templates/components/TemplatesLoader")
20
+ );
21
+
22
+ export const RuleImplementationResultTabs = ({
23
+ rule,
24
+ ruleImplementation,
25
+ ruleResult,
26
+ match,
27
+ authCreateRemediation,
28
+ templates,
29
+ }) => {
30
+ const renderSegmentResult = () => {
31
+ return ruleResult.has_segments ? (
32
+ <Menu.Item
33
+ active={match.path === RULE_IMPLEMENTATION_RESULT_SEGMENTS_RESULTS}
34
+ as={Link}
35
+ to={linkTo.RULE_IMPLEMENTATION_RESULT_SEGMENTS_RESULTS({
36
+ id: rule.id,
37
+ implementation_id: ruleImplementation.id,
38
+ rule_result_id: ruleResult.id,
39
+ })}
40
+ >
41
+ <FormattedMessage id="tabs.dq.ruleImplementationResult.segmentResult" />
42
+ </Menu.Item>
43
+ ) : null;
44
+ };
45
+
46
+ const renderRemediationPlan = () => {
47
+ const canCreateRemediation = authCreateRemediation && !_.isEmpty(templates);
48
+ const renderCondition = ruleResult.has_remediation || canCreateRemediation;
49
+
50
+ return renderCondition ? (
51
+ <Menu.Item
52
+ active={
53
+ match.path === RULE_IMPLEMENTATION_RESULT_DETAILS_REMEDIATION_PLAN
54
+ }
55
+ as={Link}
56
+ to={linkTo.RULE_IMPLEMENTATION_RESULT_DETAILS_REMEDIATION_PLAN({
57
+ id: rule.id,
58
+ implementation_id: ruleImplementation.id,
59
+ rule_result_id: ruleResult.id,
60
+ })}
61
+ >
62
+ <FormattedMessage id="tabs.dq.ruleImplementationResult.remediationPlan" />
63
+ </Menu.Item>
64
+ ) : null;
65
+ };
66
+
67
+ return _.isEmpty(ruleImplementation) || _.isEmpty(rule) ? null : (
68
+ <>
69
+ <RuleResultRemediationLoader propRuleResultId={ruleResult.id} />
70
+ <TemplatesLoader scope="remediation" />
71
+ <Menu attached="top" pointing secondary tabular>
72
+ <Menu.Item
73
+ active={match.path === RULE_IMPLEMENTATION_RESULT_DETAILS}
74
+ as={Link}
75
+ to={linkTo.RULE_IMPLEMENTATION_RESULT_DETAILS({
76
+ id: rule.id,
77
+ implementation_id: ruleImplementation.id,
78
+ rule_result_id: ruleResult.id,
79
+ })}
80
+ >
81
+ <FormattedMessage id="tabs.dq.ruleImplementationResult.info" />
82
+ </Menu.Item>
83
+ {renderSegmentResult()}
84
+ {renderRemediationPlan()}
85
+ </Menu>
86
+ </>
87
+ );
88
+ };
89
+
90
+ RuleImplementationResultTabs.propTypes = {
91
+ rule: PropTypes.object,
92
+ ruleResult: PropTypes.object,
93
+ ruleImplementation: PropTypes.object,
94
+ match: PropTypes.object,
95
+ authCreateRemediation: PropTypes.bool,
96
+ templates: PropTypes.array,
97
+ };
98
+
99
+ const mapStateToProps = (
100
+ { rule, ruleImplementation, remediationActions, templates },
101
+ ownProps
102
+ ) => ({
103
+ rule,
104
+ ruleResult: ownProps.ruleResult,
105
+ ruleImplementation,
106
+ authCreateRemediation: _.has("create")(remediationActions),
107
+ templates,
108
+ });
109
+
110
+ export default compose(
111
+ withRouter,
112
+ connect(mapStateToProps)
113
+ )(RuleImplementationResultTabs);
@@ -1,5 +1,5 @@
1
1
  import _ from "lodash/fp";
2
- import React, { useEffect } from "react";
2
+ import React from "react";
3
3
  import PropTypes from "prop-types";
4
4
  import { useIntl } from "react-intl";
5
5
  import { connect } from "react-redux";
@@ -10,6 +10,8 @@ import {
10
10
  RULE_IMPLEMENTATION_EVENTS,
11
11
  IMPLEMENTATION_CONCEPT_LINKS,
12
12
  IMPLEMENTATION_CONCEPT_LINKS_NEW,
13
+ IMPLEMENTATION_STRUCTURES,
14
+ IMPLEMENTATION_STRUCTURES_NEW,
13
15
  RULE_IMPLEMENTATION_MOVE,
14
16
  RULE_IMPLEMENTATION_RESULTS_DETAILS,
15
17
  RULE_IMPLEMENTATION_RESULTS,
@@ -57,9 +59,22 @@ export const RuleImplementationTabs = ({
57
59
  implementation_id: ruleImplementation.id,
58
60
  })}
59
61
  >
60
- <FormattedMessage id="tabs.dq.implementation.links" />
62
+ <FormattedMessage id="tabs.dq.implementation.links.concepts" />
61
63
  </Menu.Item>
62
64
  )}
65
+ <Menu.Item
66
+ active={
67
+ match.path === IMPLEMENTATION_STRUCTURES ||
68
+ match.path === IMPLEMENTATION_STRUCTURES_NEW
69
+ }
70
+ as={Link}
71
+ to={linkTo.IMPLEMENTATION_STRUCTURES({
72
+ id: rule.id,
73
+ implementation_id: ruleImplementation.id,
74
+ })}
75
+ >
76
+ <FormattedMessage id="tabs.dq.implementation.structures" />
77
+ </Menu.Item>
63
78
  <Menu.Item
64
79
  active={match.path === RULE_IMPLEMENTATION_RESULTS}
65
80
  as={Link}
@@ -15,6 +15,7 @@ export const RuleImplementationsTable = ({
15
15
  additionalColumns = [],
16
16
  checkedAll,
17
17
  checkRow,
18
+ structure,
18
19
  executeImplementationsOn,
19
20
  implementationsSort,
20
21
  sortImplementations,
@@ -127,6 +128,7 @@ RuleImplementationsTable.propTypes = {
127
128
  isRowChecked: PropTypes.bool,
128
129
  ruleImplementationsLoading: PropTypes.bool,
129
130
  sortImplementations: PropTypes.func,
131
+ structure: PropTypes.object,
130
132
  ruleImplementations: PropTypes.array,
131
133
  columns: PropTypes.array,
132
134
  withoutColumns: PropTypes.array,
@@ -134,11 +136,16 @@ RuleImplementationsTable.propTypes = {
134
136
 
135
137
  const mapStateToProps = (state, props) => ({
136
138
  columns: getRuleImplementationColumns(state),
137
- ruleImplementations: _.getOr(
139
+ ruleImplementations:
140
+ props.ruleImplementations ||
141
+ (state?.structure?.implementations &&
142
+ _.map(({ implementation, type }) => ({
143
+ ...implementation,
144
+ implementation_structure_structure_type: type,
145
+ }))(state.structure.implementations)) ||
138
146
  state.ruleImplementations,
139
- "ruleImplementations"
140
- )(props),
141
147
  ruleImplementationsLoading: state.ruleImplementationsLoading,
148
+ structure: state.structure,
142
149
  implementationsSort: _.path("ruleImplementationQuery.sort")(state),
143
150
  });
144
151
 
@@ -0,0 +1,108 @@
1
+ import _ from "lodash/fp";
2
+ import React from "react";
3
+ import PropTypes from "prop-types";
4
+ import { useIntl } from "react-intl";
5
+ import { connect } from "react-redux";
6
+ import { useParams } from "react-router-dom";
7
+ import { Header, Table, Icon } from "semantic-ui-react";
8
+ import { DateTime } from "@truedat/core/components";
9
+ import { FormattedMessage } from "react-intl";
10
+ import { selectColor } from "../functions/selectors";
11
+ import RuleImplementationResultTabs from "./RuleImplementationResultTabs";
12
+
13
+ const GeneralInformation = ({ ruleImplementation, ruleResult }) => {
14
+ const { formatMessage, formatNumber: _formatNumber } = useIntl();
15
+ const formatNumber = (num) => (_.isNil(num) ? num : _formatNumber(num));
16
+ return (
17
+ <>
18
+ <Table.Row>
19
+ <Table.Cell>
20
+ {formatMessage({ id: "ruleResult.props.quality" })}
21
+ </Table.Cell>
22
+ <Table.Cell>
23
+ <Icon
24
+ name="circle"
25
+ color={selectColor({ ...ruleImplementation, ...ruleResult })}
26
+ />
27
+ {`${parseFloat(ruleResult.result)} %`}
28
+ </Table.Cell>
29
+ </Table.Row>
30
+
31
+ <Table.Row>
32
+ <Table.Cell>
33
+ {formatMessage({ id: "ruleResult.props.date" })}
34
+ </Table.Cell>
35
+ <Table.Cell>
36
+ <DateTime value={ruleResult.date} />
37
+ </Table.Cell>
38
+ </Table.Row>
39
+
40
+ <Table.Row>
41
+ <Table.Cell>
42
+ {formatMessage({ id: "ruleResult.props.records" })}
43
+ </Table.Cell>
44
+ <Table.Cell>{formatNumber(ruleResult.records)}</Table.Cell>
45
+ </Table.Row>
46
+
47
+ <Table.Row>
48
+ <Table.Cell>
49
+ {formatMessage({ id: "ruleResult.props.errors" })}
50
+ </Table.Cell>
51
+ <Table.Cell>{formatNumber(ruleResult.errors)}</Table.Cell>
52
+ </Table.Row>
53
+ </>
54
+ );
55
+ };
56
+
57
+ GeneralInformation.propTypes = {
58
+ ruleImplementation: PropTypes.object,
59
+ ruleResult: PropTypes.object,
60
+ };
61
+
62
+ export const RuleResult = ({ ruleImplementation, ruleResultId, children }) => {
63
+ const { rule_result_id: paramsId } = useParams();
64
+
65
+ const resultId = _.defaultTo(_.toNumber(paramsId))(ruleResultId);
66
+
67
+ const ruleResult = _.find(_.propEq("id", resultId))(
68
+ ruleImplementation.results
69
+ );
70
+
71
+ const renderRuleResult = () => {
72
+ return (
73
+ <>
74
+ <Header as="h2">
75
+ <Icon circular name="chart pie" />
76
+ <Header.Content>
77
+ <FormattedMessage id="ruleResult" />
78
+ </Header.Content>
79
+ </Header>
80
+ <RuleImplementationResultTabs ruleResult={ruleResult} />
81
+ {children}
82
+ </>
83
+ );
84
+ };
85
+
86
+ return _.isEmpty(ruleResult) ? null : renderRuleResult();
87
+ };
88
+
89
+ RuleResult.propTypes = {
90
+ ruleImplementation: PropTypes.object,
91
+ ruleResultId: PropTypes.number,
92
+ children: PropTypes.oneOfType([
93
+ PropTypes.node,
94
+ PropTypes.arrayOf(PropTypes.node),
95
+ ]),
96
+ };
97
+
98
+ const mapStateToProps = (
99
+ { ruleImplementation, remediationLoading, templatesLoading },
100
+ ownProps
101
+ ) => ({
102
+ ruleImplementation,
103
+ remediationLoading,
104
+ templatesLoading,
105
+ ...ownProps,
106
+ });
107
+
108
+ export default connect(mapStateToProps)(RuleResult);
@@ -4,11 +4,9 @@ import PropTypes from "prop-types";
4
4
  import { useIntl } from "react-intl";
5
5
  import { connect } from "react-redux";
6
6
  import { useParams } from "react-router-dom";
7
- import { Header, Table, Icon } from "semantic-ui-react";
7
+ import { Table, Icon } from "semantic-ui-react";
8
8
  import { DateTime } from "@truedat/core/components";
9
- import { FormattedMessage } from "react-intl";
10
9
  import { selectColor } from "../functions/selectors";
11
- import RemediationPlan from "./RemediationPlan";
12
10
  import "../styles/executionDetails.less";
13
11
 
14
12
  const GeneralInformation = ({ ruleImplementation, ruleResult }) => {
@@ -84,11 +82,7 @@ const DetailRow = ({ details }) => {
84
82
 
85
83
  DetailRow.propTypes = { details: PropTypes.object };
86
84
 
87
- const TemplatesLoader = React.lazy(() =>
88
- import("@truedat/df/templates/components/TemplatesLoader")
89
- );
90
-
91
- export const ExecutionDetails = ({ ruleImplementation, ruleResultId }) => {
85
+ export const RuleResultDetails = ({ ruleImplementation, ruleResultId }) => {
92
86
  const { formatMessage } = useIntl();
93
87
  const { rule_result_id: paramsId } = useParams();
94
88
 
@@ -100,12 +94,6 @@ export const ExecutionDetails = ({ ruleImplementation, ruleResultId }) => {
100
94
 
101
95
  return _.isEmpty(ruleResult) ? null : (
102
96
  <>
103
- <Header as="h2">
104
- <Icon circular name="chart pie" />
105
- <Header.Content>
106
- <FormattedMessage id="ruleResult" />
107
- </Header.Content>
108
- </Header>
109
97
  <Table className="implementation-results medium">
110
98
  <Table.Header>
111
99
  <Table.Row>
@@ -141,16 +129,11 @@ export const ExecutionDetails = ({ ruleImplementation, ruleResultId }) => {
141
129
  </>
142
130
  ) : null}
143
131
  </Table>
144
- <TemplatesLoader scope="remediation" />
145
- <RemediationPlan
146
- className="execution-details-remediation"
147
- latestResultId={resultId}
148
- />
149
132
  </>
150
133
  );
151
134
  };
152
135
 
153
- ExecutionDetails.propTypes = {
136
+ RuleResultDetails.propTypes = {
154
137
  ruleImplementation: PropTypes.object,
155
138
  ruleResultId: PropTypes.number,
156
139
  };
@@ -159,4 +142,4 @@ const mapStateToProps = ({ ruleImplementation }) => ({
159
142
  ruleImplementation,
160
143
  });
161
144
 
162
- export default connect(mapStateToProps)(ExecutionDetails);
145
+ export default connect(mapStateToProps)(RuleResultDetails);