@truedat/dq 4.46.9 → 4.46.13

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.46.13] 2022-06-21
4
+
5
+ ### Fixed
6
+
7
+ - [TD-4958]
8
+ - Maintain selected filters state
9
+ - Remove implementation status column
10
+
11
+ ## [4.46.12] 2022-06-20
12
+
13
+ ### Reverted
14
+
15
+ - [TD-4894] Multiple column operator in implementation creation
16
+
17
+ ## [4.46.10] 2022-06-20
18
+
19
+ ### Fixed
20
+
21
+ - [TD-4938] Avoid creating empty objects in `mapStateToProps`
22
+
3
23
  ## [4.46.9] 2022-06-20
4
24
 
5
25
  - [TD-4953] Implementation details view is not displaying the template fields
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/dq",
3
- "version": "4.46.9",
3
+ "version": "4.46.13",
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.46.9",
37
+ "@truedat/test": "4.46.12",
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.46.9",
92
- "@truedat/df": "4.46.9",
91
+ "@truedat/core": "4.46.13",
92
+ "@truedat/df": "4.46.13",
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": "e4b69516afe19d864531f507af8c7d0f17b2a064"
113
+ "gitHead": "89cd539e47e64a3e4a6f8bc30ea4d3b66fb0b666"
114
114
  }
@@ -8,41 +8,23 @@ import { linkTo } from "@truedat/core/routes";
8
8
 
9
9
  const concatValues = (values, link) => _.join(link)(values);
10
10
 
11
- const LinkToStructure = ({ value }) => {
12
- return value?.id ? (
11
+ const FormattedLink = ({ value, operator = {} }) =>
12
+ _.propEq("value_type", "field")(operator) ? (
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
- ) : null;
19
- };
20
-
21
- const FormattedLink = ({ value, operator = {} }) => {
22
- switch (operator?.value_type) {
23
- case "field":
24
- return <LinkToStructure value={value} />;
25
- case "field_list":
26
- return (
27
- <>
28
- {_.map.convert({ cap: false })((v, i) => (
29
- <LinkToStructure key={i} value={v} />
30
- ))(value)}
31
- </>
32
- );
33
- default:
34
- return (
35
- <span className="highlighted">
36
- <FormattedMessage
37
- id={`ruleImplementation.filtersField.${value.raw}`}
38
- defaultMessage={`"${
39
- _.isArray(value.raw) ? _.join(", ")(value.raw) : value.raw
40
- }"`}
41
- ></FormattedMessage>
42
- </span>
43
- );
44
- }
45
- };
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
+ );
46
28
 
47
29
  FormattedLink.propTypes = {
48
30
  value: PropTypes.object,
@@ -51,52 +33,26 @@ FormattedLink.propTypes = {
51
33
 
52
34
  const nilOrEmpty = (v) => _.isNil(v) || v === "";
53
35
 
54
- const filterNilOrEmpties = (values, keys) => {
55
- if ("kv" in values) {
56
- return _.every((k) => !nilOrEmpty(values.kv[k]))(keys) ? values : null;
57
- }
36
+ const filterNilOrEmpties = (values, keys) =>
37
+ _.filter((v) => _.every((k) => !nilOrEmpty(_.prop(k)(v.kv)))(keys))(values);
58
38
 
59
- return _.flow(
60
- _.map((v) => filterNilOrEmpties(v, keys)),
61
- _.filter((v) => !!v)
62
- )(values);
63
- };
64
-
65
- const pick = (value, keys, optionalKeys) => ({
66
- kv: _.pick(keys)(value),
67
- optv: _.pick(optionalKeys)(value),
68
- });
69
-
70
- const convert = (v, index, value_modifier) => {
71
- if (_.has("kv")(v)) {
72
- return { ...v.kv, ...v.optv, modifier: _.nth(index)(value_modifier) };
73
- }
74
-
75
- return _.map.convert({ cap: false })((v, i) => {
76
- return convert(v, i, value_modifier);
77
- })(v);
78
- };
79
-
80
- const valuesFromKeys = (values, keys, optionalKeys, value_modifier) => {
81
- return _.flow(
82
- _.map((value) => {
83
- return Array.isArray(value?.fields)
84
- ? _.map((innerValue) => pick(innerValue, keys, optionalKeys))(
85
- value?.fields
86
- )
87
- : pick(value, keys, optionalKeys);
39
+ const valuesFromKeys = (values, keys, optionalKeys, value_modifier) =>
40
+ _.flow(
41
+ _.map((v) => {
42
+ return { kv: _.pick(keys)(v), optv: _.pick(optionalKeys)(v) };
88
43
  }),
89
44
  (v) => filterNilOrEmpties(v, keys),
90
- (v) => convert(v, 0, value_modifier)
45
+ _.map.convert({ cap: false })((v, i) => {
46
+ return { ...v.kv, ...v.optv, modifier: _.nth(i)(value_modifier) };
47
+ })
91
48
  )(values);
92
- };
93
49
 
94
50
  export const empty = (rows) =>
95
51
  rows && _.every((r) => _.isEmpty(r) || _.isNil(r))(rows);
96
52
 
97
53
  export const getValues = ({ value = [], operator = {}, value_modifier }) => {
98
54
  const defaultOrValue = value || [];
99
- return ["field", "field_list"].includes(operator?.value_type)
55
+ return _.propEq("value_type", "field")(operator)
100
56
  ? valuesFromKeys(defaultOrValue, ["id", "name"], ["path"], value_modifier)
101
57
  : valuesFromKeys(defaultOrValue, ["raw"], [], value_modifier);
102
58
  };
@@ -7,6 +7,8 @@ import {
7
7
  fetchImplementationFilters,
8
8
  } from "../routines";
9
9
 
10
+ const EMPTY = {};
11
+
10
12
  const mapDispatchToProps = (dispatch) =>
11
13
  bindActionCreators(
12
14
  {
@@ -23,7 +25,7 @@ export const makeMapStateToProps = () => {
23
25
  const mapStateToProps = (state, props) => ({
24
26
  selectedFilter: state.ruleImplementationSelectedFilter,
25
27
  filters: activeFiltersSelector(state, props),
26
- defaultFilters: props?.defaultFilters || {},
28
+ defaultFilters: props?.defaultFilters || EMPTY,
27
29
  });
28
30
  return mapStateToProps;
29
31
  };
@@ -25,24 +25,6 @@ const updateDatasetKey = (data) =>
25
25
  {}
26
26
  )(data);
27
27
 
28
- // https://stackoverflow.com/a/38417085
29
- const updateValueKeyValue = (object) => {
30
- if (object?.id || object?.raw || object?.fields) {
31
- return object?.id
32
- ? _.pick(["id", "parent_index"])(object)
33
- : _.pick(["raw", "fields"])(object);
34
- }
35
-
36
- return Object.keys(object).reduce(
37
- (output, key) => {
38
- // eslint-disable-next-line fp/no-mutation
39
- output[key] = updateValueKeyValue(object[key]);
40
- return output;
41
- },
42
- Array.isArray(object) ? [] : {}
43
- );
44
- };
45
-
46
28
  const updateConditionValue = (acc, value, key) => {
47
29
  if (key === "structure") {
48
30
  return _.set(key, _.pick(["id", "parent_index"])(value))(acc);
@@ -67,10 +49,12 @@ const updateConditionValue = (acc, value, key) => {
67
49
  )
68
50
  )(acc);
69
51
  if (key == "value")
70
- return {
71
- ...acc,
72
- value: updateValueKeyValue(value),
73
- };
52
+ return _.set(
53
+ key,
54
+ _.map((v) =>
55
+ _.has("id")(v) ? _.pick(["id", "parent_index"])(v) : _.pick(["raw"])(v)
56
+ )(value)
57
+ )(acc);
74
58
  if (key === "population") return _.set(key, conditionAttributes(value))(acc);
75
59
 
76
60
  return acc;
@@ -119,7 +103,6 @@ const fieldTypeFromStructure = (row, structures, operators, scope) => {
119
103
  field_type,
120
104
  _.prop("operator")(row)
121
105
  );
122
-
123
106
  const updatedRow = {
124
107
  ...row,
125
108
  operator,
@@ -27,9 +27,12 @@ export const RuleImplementationProperties = ({
27
27
  <Grid.Row>
28
28
  <Grid.Column>
29
29
  <Label>
30
- <FormattedMessage
31
- id={`ruleImplementation.status.${ruleImplementation.status}`}
32
- />
30
+ {ruleImplementation.status ? (
31
+ <FormattedMessage
32
+ id={`ruleImplementation.status.${ruleImplementation.status}`}
33
+ defaultMessage={ruleImplementation.status}
34
+ />
35
+ ) : null}
33
36
  </Label>
34
37
  {ruleImplementation?.status == "published" ? (
35
38
  <Label color={ruleImplementation.executable ? "olive" : "teal"}>
@@ -42,14 +42,14 @@ RuleResult.propTypes = {
42
42
  ]),
43
43
  };
44
44
 
45
- const mapStateToProps = (
46
- { ruleImplementation, remediationLoading, templatesLoading },
47
- ownProps
48
- ) => ({
45
+ const mapStateToProps = ({
46
+ ruleImplementation,
47
+ remediationLoading,
48
+ templatesLoading,
49
+ }) => ({
49
50
  ruleImplementation,
50
51
  remediationLoading,
51
52
  templatesLoading,
52
- ...ownProps,
53
53
  });
54
54
 
55
55
  export default connect(mapStateToProps)(RuleResult);
@@ -138,8 +138,6 @@ RuleResultDetails.propTypes = {
138
138
  ruleResultId: PropTypes.number,
139
139
  };
140
140
 
141
- const mapStateToProps = ({ ruleImplementation }) => ({
142
- ruleImplementation,
143
- });
141
+ const mapStateToProps = ({ ruleImplementation }) => ({ ruleImplementation });
144
142
 
145
143
  export default connect(mapStateToProps)(RuleResultDetails);
@@ -33,8 +33,6 @@ RuleResultRemediations.propTypes = {
33
33
  ruleResultId: PropTypes.number,
34
34
  };
35
35
 
36
- const mapStateToProps = ({ ruleImplementation }) => ({
37
- ruleImplementation,
38
- });
36
+ const mapStateToProps = ({ ruleImplementation }) => ({ ruleImplementation });
39
37
 
40
38
  export default connect(mapStateToProps)(RuleResultRemediations);
@@ -14,13 +14,8 @@ describe("<RuleImplementationProperties />", () => {
14
14
  id: 10,
15
15
  executable: true,
16
16
  name: "NameRule2",
17
- system: "SYS",
18
17
  type: "integer_values_range",
19
- system: {
20
- external_id: "Microstrategy",
21
- id: 1,
22
- name: "Microstrategy",
23
- },
18
+ status: "published",
24
19
  system_params: {
25
20
  table: { name: "aaaxxx" },
26
21
  column: {
@@ -61,14 +56,8 @@ describe("<RuleImplementationProperties />", () => {
61
56
  id: 10,
62
57
  executable: true,
63
58
  name: "NameRule2",
64
- system: "SYS",
65
59
  type: "integer_values_range",
66
60
  status: "published",
67
- system: {
68
- external_id: "Microstrategy",
69
- id: 1,
70
- name: "Microstrategy",
71
- },
72
61
  system_params: {
73
62
  table: { name: "aaaxxx" },
74
63
  column: {
@@ -9,7 +9,15 @@ exports[`<RuleImplementationProperties /> matches the latest snapshot 1`] = `
9
9
  <GridColumn>
10
10
  <Label>
11
11
  <MemoizedFormattedMessage
12
- id="ruleImplementation.status.undefined"
12
+ defaultMessage="published"
13
+ id="ruleImplementation.status.published"
14
+ />
15
+ </Label>
16
+ <Label
17
+ color="olive"
18
+ >
19
+ <MemoizedFormattedMessage
20
+ id="ruleImplementation.props.executable.true"
13
21
  />
14
22
  </Label>
15
23
  </GridColumn>
@@ -27,11 +35,7 @@ exports[`<RuleImplementationProperties /> matches the latest snapshot 1`] = `
27
35
  "minimum": 1,
28
36
  "name": "NameRule2",
29
37
  "result_type": "percentage",
30
- "system": Object {
31
- "external_id": "Microstrategy",
32
- "id": 1,
33
- "name": "Microstrategy",
34
- },
38
+ "status": "published",
35
39
  "system_params": Object {
36
40
  "column": Object {
37
41
  "id": 2876,
@@ -74,11 +78,7 @@ exports[`<RuleImplementationProperties /> matches the latest snapshot 1`] = `
74
78
  "minimum": 1,
75
79
  "name": "NameRule2",
76
80
  "result_type": "percentage",
77
- "system": Object {
78
- "external_id": "Microstrategy",
79
- "id": 1,
80
- "name": "Microstrategy",
81
- },
81
+ "status": "published",
82
82
  "system_params": Object {
83
83
  "column": Object {
84
84
  "id": 2876,
@@ -48,24 +48,6 @@ export const FiltersField = ({
48
48
  const { value_type, value_type_filter, fixed_values } = operator;
49
49
 
50
50
  const modifierDef = _.find({ name: modifier?.name })(typeCastModifiers);
51
- const pickFromValue = _.pick(["data_structure_id", "name", "parent_index"]);
52
-
53
- const getVal = (value) => {
54
- return _.isNil(_.prop("parent_index")(value))
55
- ? _.prop("id")(value)
56
- : `${_.prop("id")(value)}/${_.prop("parent_index")(value)}`;
57
- };
58
-
59
- const getValue = (valueOrValues, operator) => {
60
- const getValueResultado =
61
- operator?.value_type === "field_list"
62
- ? (valueOrValues?.fields || []).map((v) => {
63
- return getVal(v);
64
- })
65
- : getVal(valueOrValues);
66
-
67
- return getValueResultado;
68
- };
69
51
 
70
52
  switch (value_type) {
71
53
  case "string":
@@ -107,7 +89,6 @@ export const FiltersField = ({
107
89
  case "timestamp":
108
90
  return <DateTimeField label={label} value={value} onChange={onChange} />;
109
91
  case "field":
110
- case "field_list":
111
92
  const structureFields = getStructureFields(parentStructures);
112
93
  return value_type_filter == "any" ? (
113
94
  <StructureSelectorInputField
@@ -130,30 +111,24 @@ export const FiltersField = ({
130
111
  ) : (
131
112
  <>
132
113
  <StructureFieldsDropdown
133
- multiple={value_type === "field_list"}
134
114
  label={label}
135
115
  inline={false}
136
116
  parentStructures={parentStructures}
137
117
  structureFields={structureFields}
138
118
  typeCastModifiers={typeCastModifiers}
139
- filters={
140
- value_type === "field_list" ? null : { field_type: [fieldType] }
141
- }
142
- onSelectField={(value, modifier) => {
119
+ filters={{ field_type: [fieldType] }}
120
+ onSelectField={(value, modifier) =>
143
121
  onChange(
144
122
  null,
145
- pickFromValue(value),
123
+ _.pick(["data_structure_id", "name", "parent_index"])(value),
146
124
  modifier ? { name: modifier.name } : null
147
- );
148
- }}
149
- onSelectFields={(values) => {
150
- onChange(
151
- null,
152
- values.map((value) => pickFromValue(value)),
153
- null
154
- );
155
- }}
156
- value={getValue(value, operator)}
125
+ )
126
+ }
127
+ value={
128
+ _.isNil(_.prop("parent_index")(value))
129
+ ? _.prop("id")(value)
130
+ : `${_.prop("id")(value)}/${_.prop("parent_index")(value)}`
131
+ }
157
132
  />
158
133
  {modifier && (
159
134
  <FieldModifier
@@ -65,9 +65,7 @@ export const FiltersFormGroup = ({
65
65
  inline={false}
66
66
  parentStructures={parentStructures}
67
67
  structureFields={structureFields}
68
- onSelectField={(value) => {
69
- return onStructureChange(index, value /*[0]*/);
70
- }}
68
+ onSelectField={(value) => onStructureChange(index, value)}
71
69
  value={
72
70
  _.isNil(_.prop("parent_index")(clause?.structure))
73
71
  ? _.prop("id")(clause?.structure)
@@ -124,9 +122,7 @@ export const FiltersFormGroup = ({
124
122
  })}
125
123
  options={operatorsOptions}
126
124
  value={getOperatorValue(clause)}
127
- onClick={(whatever) => {
128
- onOperatorChange(index, whatever.id);
129
- }}
125
+ onClick={({ id }) => onOperatorChange(index, id)}
130
126
  placeholder={formatMessage({
131
127
  id: "operator.dropdown.placeholder",
132
128
  })}
@@ -56,23 +56,13 @@ export const FiltersGrid = ({
56
56
  });
57
57
  };
58
58
 
59
- const composeFieldValue = (value) => {
60
- return {
61
- id: value.data_structure_id || value.id,
62
- name: value.name,
63
- path: value.path,
64
- parent_index: value.parent_index,
65
- };
66
- };
67
-
68
59
  const composeValue = (value_type, value) => {
69
60
  if (value_type == "field") {
70
- return composeFieldValue(value);
71
- } else if (value_type === "field_list") {
72
61
  return {
73
- fields: _.map((v) => {
74
- return composeFieldValue(v);
75
- })(value),
62
+ id: value.data_structure_id || value.id,
63
+ name: value.name,
64
+ path: value.path,
65
+ parent_index: value.parent_index,
76
66
  };
77
67
  } else {
78
68
  return { raw: value };
@@ -50,13 +50,7 @@ exports[`<FiltersFormGroup /> matches the latest snapshot 1`] = `
50
50
  <div
51
51
  class="menu transition"
52
52
  role="listbox"
53
- >
54
- <div
55
- class="message"
56
- >
57
- No results found.
58
- </div>
59
- </div>
53
+ />
60
54
  </div>
61
55
  </div>
62
56
  <div
@@ -56,13 +56,7 @@ exports[`<FiltersGroup /> matches the latest snapshot when siblings provided 1`]
56
56
  <div
57
57
  class="menu transition"
58
58
  role="listbox"
59
- >
60
- <div
61
- class="message"
62
- >
63
- No results found.
64
- </div>
65
- </div>
59
+ />
66
60
  </div>
67
61
  </div>
68
62
  <div
@@ -56,13 +56,7 @@ exports[`<ValueConditions /> matches the latest snapshot when siblings provided
56
56
  <div
57
57
  class="menu transition"
58
58
  role="listbox"
59
- >
60
- <div
61
- class="message"
62
- >
63
- No results found.
64
- </div>
65
- </div>
59
+ />
66
60
  </div>
67
61
  </div>
68
62
  <div
@@ -423,8 +423,7 @@ export default {
423
423
  "matches regular expression",
424
424
  "ruleImplementation.operator.starts_with": "starts with",
425
425
  "ruleImplementation.operator.starts_with.string": "starts with",
426
- "ruleImplementation.operator.unique": "unique",
427
- "ruleImplementation.operator.unique.field_list": "unique across fields",
426
+ "ruleImplementation.operator.unique": "has unique value",
428
427
  "ruleImplementation.operator.variation_on_count": "count variation",
429
428
  "ruleImplementation.operator.variation_on_count.string": "count variation",
430
429
  "ruleImplementation.props.esquema": "Structure",
@@ -435,8 +435,7 @@ export default {
435
435
  "ruleImplementation.operator.regex_format": "cumple la expresión regular",
436
436
  "ruleImplementation.operator.starts_with.string": "empieza por",
437
437
  "ruleImplementation.operator.starts_with": "empieza por",
438
- "ruleImplementation.operator.unique": "único",
439
- "ruleImplementation.operator.unique.field_list": "único en conjunto",
438
+ "ruleImplementation.operator.unique": "tiene valor único",
440
439
  "ruleImplementation.operator.variation_on_count.string": "variación conteo",
441
440
  "ruleImplementation.operator.variation_on_count": "variación conteo",
442
441
  "ruleImplementation.props.esquema.placeholder": "añade una estructura",
@@ -8,7 +8,8 @@ import RuleResultDecorator from "../components/RuleResultDecorator";
8
8
  import RuleImplementationLink from "../components/RuleImplementationLink";
9
9
  import RuleLink from "../components/RuleLink";
10
10
 
11
- const translateDecorator = (id) => <FormattedMessage id={id} />;
11
+ const translateDecorator = (id) =>
12
+ id ? <FormattedMessage id={id} defaultMessage={id} /> : null;
12
13
 
13
14
  const resultTypeDecorator = (result, result_type) =>
14
15
  result_type === "errors_number" ? formatNumber(result) : `${result}%`;
@@ -28,13 +29,6 @@ export const defaultImplementationColumns = [
28
29
  fieldDecorator: RuleLink,
29
30
  width: 2,
30
31
  },
31
- {
32
- name: "status",
33
- fieldDecorator: (value) =>
34
- translateDecorator(`ruleImplementation.status.${value}`),
35
- sort: { name: "status" },
36
- width: 2,
37
- },
38
32
  {
39
33
  name: "business_concept",
40
34
  fieldSelector: _.path("current_business_concept_version.name"),
@@ -5,7 +5,6 @@ const defaultOperators = {
5
5
  any: {
6
6
  operators: [
7
7
  { name: "unique", scope: "validation" },
8
- { name: "unique", value_type: "field_list" },
9
8
  { name: "not_empty" },
10
9
  { name: "empty" },
11
10
  {