@truedat/dq 4.47.3 → 4.47.6

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 (25) hide show
  1. package/CHANGELOG.md +20 -1
  2. package/package.json +5 -5
  3. package/src/api/queries.js +5 -0
  4. package/src/components/ConditionSummary.js +63 -21
  5. package/src/components/NewRuleImplementation.js +21 -46
  6. package/src/components/RuleImplementationResults.js +5 -3
  7. package/src/components/__test_samples__/newRuleImplementationHelper.js +1239 -0
  8. package/src/components/__tests__/NewRuleImplementation.spec.js +273 -6
  9. package/src/components/ruleImplementationForm/FiltersField.js +31 -11
  10. package/src/components/ruleImplementationForm/FiltersFormGroup.js +1 -1
  11. package/src/components/ruleImplementationForm/FiltersGrid.js +18 -6
  12. package/src/components/ruleImplementationForm/FiltersGroup.js +3 -3
  13. package/src/components/ruleImplementationForm/InformationForm.js +2 -0
  14. package/src/components/ruleImplementationForm/RuleImplementationForm.js +1 -1
  15. package/src/components/ruleImplementationForm/RuleImplementationRawForm.js +30 -1
  16. package/src/components/ruleImplementationForm/__tests__/RuleImplementationRawForm.spec.js +24 -24
  17. package/src/components/ruleImplementationForm/__tests__/__snapshots__/FiltersFormGroup.spec.js.snap +7 -1
  18. package/src/components/ruleImplementationForm/__tests__/__snapshots__/FiltersGroup.spec.js.snap +8 -1
  19. package/src/components/ruleImplementationForm/__tests__/__snapshots__/RuleImplementationRawForm.spec.js.snap +67 -0
  20. package/src/components/ruleImplementationForm/__tests__/__snapshots__/ValueConditions.spec.js.snap +7 -1
  21. package/src/messages/en.js +11 -2
  22. package/src/messages/es.js +12 -5
  23. package/src/selectors/__tests__/getParsedEvents.spec.js +31 -0
  24. package/src/selectors/getParsedEvents.js +10 -0
  25. package/src/selectors/getRuleImplementationOperators.js +1 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.47.6] 2022-07-01
4
+
5
+ ### Fixed
6
+
7
+ - [TD-4993]
8
+ - RuleImplementationForm visibility with correct permissions
9
+ - Show quality event errors on results view using graphql
10
+ - Add exclusive subscription events
11
+
12
+ ## [4.47.5] 2022-06-30
13
+
14
+ ### Added
15
+
16
+ - [TD-4894] Multiple column operator in implementation creation
17
+
18
+ ## [4.47.4] 2022-06-29
19
+
20
+ - [TD-4921] Add implementation workflow events
21
+
3
22
  ## [4.47.2] 2022-06-24
4
23
 
5
24
  ### Added
@@ -16,7 +35,7 @@
16
35
 
17
36
  ## [4.46.12] 2022-06-20
18
37
 
19
- ### Reverted
38
+ ### Removed
20
39
 
21
40
  - [TD-4894] Multiple column operator in implementation creation
22
41
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/dq",
3
- "version": "4.47.3",
3
+ "version": "4.47.6",
4
4
  "description": "Truedat Web Data Quality Module",
5
5
  "sideEffects": false,
6
6
  "jsnext:main": "src/index.js",
@@ -34,7 +34,7 @@
34
34
  "@testing-library/jest-dom": "^5.16.4",
35
35
  "@testing-library/react": "^12.0.0",
36
36
  "@testing-library/user-event": "^13.2.1",
37
- "@truedat/test": "4.47.3",
37
+ "@truedat/test": "4.47.6",
38
38
  "babel-jest": "^28.1.0",
39
39
  "babel-plugin-dynamic-import-node": "^2.3.3",
40
40
  "babel-plugin-lodash": "^3.3.4",
@@ -88,8 +88,8 @@
88
88
  },
89
89
  "dependencies": {
90
90
  "@apollo/client": "^3.6.4",
91
- "@truedat/core": "4.47.3",
92
- "@truedat/df": "4.47.3",
91
+ "@truedat/core": "4.47.6",
92
+ "@truedat/df": "4.47.6",
93
93
  "axios": "^0.19.2",
94
94
  "graphql": "^15.5.3",
95
95
  "path-to-regexp": "^1.7.0",
@@ -110,5 +110,5 @@
110
110
  "react-dom": ">= 16.8.6 < 17",
111
111
  "semantic-ui-react": ">= 0.88.2 < 2.1"
112
112
  },
113
- "gitHead": "f96f532d27f7104fbc50b6b0539593cec0d2039d"
113
+ "gitHead": "07210600d97244d32085d7166595ee030e6bb578"
114
114
  }
@@ -20,6 +20,11 @@ export const IMPLEMENTATION_RESULTS = gql`
20
20
  implementation(id: $id) {
21
21
  id
22
22
  implementation_key
23
+ last_quality_event {
24
+ inserted_at
25
+ message
26
+ type
27
+ }
23
28
  versions {
24
29
  id
25
30
  implementation_key
@@ -8,43 +8,85 @@ import { linkTo } from "@truedat/core/routes";
8
8
 
9
9
  const concatValues = (values, link) => _.join(link)(values);
10
10
 
11
- const FormattedLink = ({ value, operator = {} }) =>
12
- _.propEq("value_type", "field")(operator) ? (
11
+ const LinkToStructure = ({ value }) =>
12
+ value?.id ? (
13
13
  <Link to={linkTo.STRUCTURE({ id: value.id })}>
14
14
  <span className="highlighted">{`"${
15
15
  !_.isEmpty(value.path) ? path(value) : value.name
16
16
  }"`}</span>{" "}
17
17
  </Link>
18
- ) : (
19
- <span className="highlighted">
20
- <FormattedMessage
21
- id={`ruleImplementation.filtersField.${value.raw}`}
22
- defaultMessage={`"${
23
- _.isArray(value.raw) ? _.join(", ")(value.raw) : value.raw
24
- }"`}
25
- ></FormattedMessage>
26
- </span>
27
- );
18
+ ) : null;
19
+
20
+ const FormattedLink = ({ value, operator = {} }) => {
21
+ switch (operator?.value_type) {
22
+ case "field":
23
+ return <LinkToStructure value={value} />;
24
+ case "field_list":
25
+ return (
26
+ <>
27
+ {_.map.convert({ cap: false })((v, i) => (
28
+ <LinkToStructure key={i} value={v} />
29
+ ))(value)}
30
+ </>
31
+ );
32
+ default:
33
+ return (
34
+ <span className="highlighted">
35
+ <FormattedMessage
36
+ id={`ruleImplementation.filtersField.${value.raw}`}
37
+ defaultMessage={`"${
38
+ _.isArray(value.raw) ? _.join(", ")(value.raw) : value.raw
39
+ }"`}
40
+ ></FormattedMessage>
41
+ </span>
42
+ );
43
+ }
44
+ };
28
45
 
29
46
  FormattedLink.propTypes = {
30
- value: PropTypes.object,
47
+ value: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
31
48
  operator: PropTypes.object,
32
49
  };
33
50
 
34
51
  const nilOrEmpty = (v) => _.isNil(v) || v === "";
35
52
 
36
- const filterNilOrEmpties = (values, keys) =>
37
- _.filter((v) => _.every((k) => !nilOrEmpty(_.prop(k)(v.kv)))(keys))(values);
53
+ const filterNilOrEmpties = (values, keys) => {
54
+ if ("kv" in values) {
55
+ return _.every((k) => !nilOrEmpty(values.kv[k]))(keys) ? values : null;
56
+ }
57
+
58
+ return _.flow(
59
+ _.map((v) => filterNilOrEmpties(v, keys)),
60
+ _.filter((v) => !!v)
61
+ )(values);
62
+ };
63
+
64
+ const pick = (value, keys, optionalKeys) => ({
65
+ kv: _.pick(keys)(value),
66
+ optv: _.pick(optionalKeys)(value),
67
+ });
68
+
69
+ const convert = (v, index, value_modifier) => {
70
+ if (_.has("kv")(v)) {
71
+ return { ...v.kv, ...v.optv, modifier: _.nth(index)(value_modifier) };
72
+ }
73
+
74
+ return _.map.convert({ cap: false })((v, i) => {
75
+ return convert(v, i, value_modifier);
76
+ })(v);
77
+ };
38
78
 
39
79
  const valuesFromKeys = (values, keys, optionalKeys, value_modifier) =>
40
80
  _.flow(
41
- _.map((v) => {
42
- return { kv: _.pick(keys)(v), optv: _.pick(optionalKeys)(v) };
81
+ _.map((value) => {
82
+ return Array.isArray(value?.fields)
83
+ ? _.map((innerValue) => pick(innerValue, keys, optionalKeys))(
84
+ value?.fields
85
+ )
86
+ : pick(value, keys, optionalKeys);
43
87
  }),
44
88
  (v) => filterNilOrEmpties(v, keys),
45
- _.map.convert({ cap: false })((v, i) => {
46
- return { ...v.kv, ...v.optv, modifier: _.nth(i)(value_modifier) };
47
- })
89
+ (v) => convert(v, 0, value_modifier)
48
90
  )(values);
49
91
 
50
92
  export const empty = (rows) =>
@@ -52,7 +94,7 @@ export const empty = (rows) =>
52
94
 
53
95
  export const getValues = ({ value = [], operator = {}, value_modifier }) => {
54
96
  const defaultOrValue = value || [];
55
- return _.propEq("value_type", "field")(operator)
97
+ return ["field", "field_list"].includes(operator?.value_type)
56
98
  ? valuesFromKeys(defaultOrValue, ["id", "name"], ["path"], value_modifier)
57
99
  : valuesFromKeys(defaultOrValue, ["raw"], [], value_modifier);
58
100
  };
@@ -4,8 +4,6 @@ import PropTypes from "prop-types";
4
4
  import { connect } from "react-redux";
5
5
  import { Divider, Header, Grid } from "semantic-ui-react";
6
6
  import { FormattedMessage } from "react-intl";
7
- import { gql, useQuery } from "@apollo/client";
8
- import { Loading } from "@truedat/core/components";
9
7
  import { getFieldType } from "@truedat/core/services/fieldType";
10
8
  import {
11
9
  createRuleImplementation,
@@ -25,6 +23,19 @@ const updateDatasetKey = (data) =>
25
23
  {}
26
24
  )(data);
27
25
 
26
+ // object either field, raw value, list of fields, list of raw values
27
+ const updateValueKeyContent = (object) => {
28
+ if (object?.id || object?.raw || object?.fields) {
29
+ return object?.id
30
+ ? _.pick(["id", "parent_index"])(object)
31
+ : _.pick(["raw", "fields"])(object);
32
+ }
33
+
34
+ return (object || []).map((v) => {
35
+ return updateValueKeyContent(v);
36
+ });
37
+ };
38
+
28
39
  const updateConditionValue = (acc, value, key) => {
29
40
  if (key === "structure") {
30
41
  return _.set(key, _.pick(["id", "parent_index"])(value))(acc);
@@ -48,13 +59,9 @@ const updateConditionValue = (acc, value, key) => {
48
59
  _.pick(["name", "value_type", "value_type_filter"])(value)
49
60
  )
50
61
  )(acc);
51
- if (key == "value")
52
- return _.set(
53
- key,
54
- _.map((v) =>
55
- _.has("id")(v) ? _.pick(["id", "parent_index"])(v) : _.pick(["raw"])(v)
56
- )(value)
57
- )(acc);
62
+ if (key == "value") {
63
+ return { ...acc, value: updateValueKeyContent(value) };
64
+ }
58
65
  if (key === "population") return _.set(key, conditionAttributes(value))(acc);
59
66
 
60
67
  return acc;
@@ -103,6 +110,7 @@ const fieldTypeFromStructure = (row, structures, operators, scope) => {
103
110
  field_type,
104
111
  _.prop("operator")(row)
105
112
  );
113
+
106
114
  const updatedRow = {
107
115
  ...row,
108
116
  operator,
@@ -238,8 +246,6 @@ export const NewRuleImplementation = ({
238
246
  edition,
239
247
  rule,
240
248
  ruleImplementationProps,
241
- sources,
242
- sourcesLoading,
243
249
  structuresFields,
244
250
  structuresSiblings,
245
251
  operators,
@@ -448,8 +454,9 @@ export const NewRuleImplementation = ({
448
454
  const setImplementationKey = (implementationKey) =>
449
455
  setRuleImplementation({ ...ruleImplementation, implementationKey });
450
456
 
451
- const setImplementationRawContent = (rawContent) =>
457
+ const setImplementationRawContent = (rawContent) => {
452
458
  setRuleImplementation({ ...ruleImplementation, rawContent });
459
+ };
453
460
 
454
461
  const doSubmit = (props = {}) => {
455
462
  const populations = _.reject(_.isEmpty)(ruleImplementation.populations);
@@ -457,8 +464,6 @@ export const NewRuleImplementation = ({
457
464
  const segments = _.reject(_.isEmpty)(ruleImplementation.segments);
458
465
 
459
466
  const raw_content = _.prop("rawContent")(ruleImplementation);
460
- const source_id = _.prop("source_id")(raw_content);
461
- const source = _.find({ id: source_id })(sources);
462
467
 
463
468
  const rule_implementation =
464
469
  ruleImplementation.implementationType == "raw"
@@ -469,7 +474,7 @@ export const NewRuleImplementation = ({
469
474
  df_name: ruleImplementation?.dfName,
470
475
  df_content: ruleImplementation?.dfContent,
471
476
  rule_id: rule ? rule.id : ruleImplementation.rule_id,
472
- raw_content: { ...raw_content, source },
477
+ raw_content: { ...raw_content },
473
478
  result_type: ruleImplementation.result_type,
474
479
  minimum: ruleImplementation.minimum,
475
480
  goal: ruleImplementation.goal,
@@ -536,8 +541,6 @@ export const NewRuleImplementation = ({
536
541
  ruleImplementation={ruleImplementation}
537
542
  onChange={onChange}
538
543
  onSubmit={doSubmit}
539
- sources={sources}
540
- sourcesLoading={sourcesLoading}
541
544
  />
542
545
  ) : (
543
546
  <RuleImplementationForm
@@ -573,39 +576,11 @@ NewRuleImplementation.propTypes = {
573
576
  operators: PropTypes.object,
574
577
  rule: PropTypes.object,
575
578
  ruleImplementationProps: PropTypes.object,
576
- sources: PropTypes.array,
577
- sourcesLoading: PropTypes.bool,
578
579
  structuresFields: PropTypes.object,
579
580
  structuresSiblings: PropTypes.object,
580
581
  updateRuleImplementation: PropTypes.func,
581
582
  };
582
583
 
583
- export const SOURCES_WITH_CONFIG = gql`
584
- query SOURCES_WITH_CONFIG($jobTypes: String) {
585
- sources(jobTypes: $jobTypes) {
586
- id
587
- externalId
588
- config
589
- }
590
- }
591
- `;
592
-
593
- export const NewRuleImplementationLoader = (props) => {
594
- const { data, error, loading } = useQuery(SOURCES_WITH_CONFIG, {
595
- variables: { jobTypes: "quality" },
596
- });
597
- if (error) return null;
598
- if (loading) return <Loading />;
599
- const sources = data?.sources || [];
600
- return (
601
- <NewRuleImplementation
602
- sources={sources}
603
- sourcesLoading={loading}
604
- {...props}
605
- />
606
- );
607
- };
608
-
609
584
  const mapStateToProps = (state) => ({
610
585
  rule: state.rule,
611
586
  ruleImplementationProps: {
@@ -621,4 +596,4 @@ const mapStateToProps = (state) => ({
621
596
  export default connect(mapStateToProps, {
622
597
  createRuleImplementation,
623
598
  updateRuleImplementation,
624
- })(NewRuleImplementationLoader);
599
+ })(NewRuleImplementation);
@@ -46,9 +46,11 @@ export const RuleImplementationResults = ({
46
46
  formatMessage,
47
47
  };
48
48
 
49
+ const { last_quality_event } = ruleImplementation;
50
+
49
51
  return (
50
52
  <>
51
- {ruleImplementation.event_type === "FAILED" ? (
53
+ {last_quality_event?.type === "FAILED" ? (
52
54
  <Message negative style={{ marginTop: "14px" }}>
53
55
  <Message.Header>
54
56
  {formatMessage({
@@ -63,7 +65,7 @@ export const RuleImplementationResults = ({
63
65
  right: "21px",
64
66
  }}
65
67
  locale={locale}
66
- date={ruleImplementation.event_inserted_at}
68
+ date={last_quality_event.inserted_at}
67
69
  format="YYYY-MM-DD HH:mm"
68
70
  />
69
71
  <p
@@ -71,7 +73,7 @@ export const RuleImplementationResults = ({
71
73
  whiteSpace: "pre-wrap",
72
74
  }}
73
75
  >
74
- {ruleImplementation.event_message}
76
+ {last_quality_event.message}
75
77
  </p>
76
78
  </Message>
77
79
  ) : null}