@truedat/dq 5.7.2 → 5.7.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/dq",
3
- "version": "5.7.2",
3
+ "version": "5.7.4",
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.5",
35
35
  "@testing-library/react": "^12.0.0",
36
36
  "@testing-library/user-event": "^13.2.1",
37
- "@truedat/test": "5.7.2",
37
+ "@truedat/test": "5.7.4",
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",
@@ -92,8 +92,8 @@
92
92
  },
93
93
  "dependencies": {
94
94
  "@apollo/client": "^3.7.1",
95
- "@truedat/core": "5.7.2",
96
- "@truedat/df": "5.7.2",
95
+ "@truedat/core": "5.7.4",
96
+ "@truedat/df": "5.7.4",
97
97
  "decode-uri-component": "^0.2.2",
98
98
  "graphql": "^15.5.3",
99
99
  "moment": "^2.29.4",
@@ -118,5 +118,5 @@
118
118
  "react-dom": ">= 16.8.6 < 17",
119
119
  "semantic-ui-react": ">= 2.0.3 < 2.2"
120
120
  },
121
- "gitHead": "4315abba2c52728150ce9b9044005eae1409cccf"
121
+ "gitHead": "ed86b1f89479bb65ed72915f7160bebbeacb084f"
122
122
  }
@@ -125,6 +125,7 @@ ImplementationSearchResults.propTypes = {
125
125
  role: PropTypes.string,
126
126
  loading: PropTypes.bool,
127
127
  ruleImplementations: PropTypes.array,
128
+ embedded: PropTypes.bool,
128
129
  };
129
130
 
130
131
  const mapStateToProps = (state, props) => ({
@@ -2,7 +2,15 @@ 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 { Table, Button, Grid, Segment, Header, Icon } from "semantic-ui-react";
5
+ import {
6
+ Button,
7
+ Grid,
8
+ Header,
9
+ Icon,
10
+ List,
11
+ Segment,
12
+ Table,
13
+ } from "semantic-ui-react";
6
14
  import { FormattedMessage } from "react-intl";
7
15
  import { Link } from "react-router-dom";
8
16
  import { linkTo } from "@truedat/core/routes";
@@ -18,6 +26,20 @@ ImplementationStructureDeleteDecorator.propTypes = {
18
26
  implementation_id: PropTypes.number,
19
27
  };
20
28
 
29
+ const DomainDecorator = (domains) => (
30
+ <List>
31
+ {domains.map(({ name, parents }, i) => (
32
+ <List.Item key={i}>
33
+ {_.flow(_.map("name"), _.union([name]), _.join(" > "))(parents)}
34
+ </List.Item>
35
+ ))}
36
+ </List>
37
+ );
38
+
39
+ DomainDecorator.propTypes = {
40
+ domains: PropTypes.array,
41
+ };
42
+
21
43
  const PathDecorator = (path) => (
22
44
  <span title={_.join(" › ")(path)}>
23
45
  {_.flow(_.join(" › "), _.truncate({ length: 90 }))(path)}
@@ -50,6 +72,11 @@ export const ImplementationStructures = ({ implementation, canCreateLink }) => {
50
72
  fieldSelector: _.path("data_structure"),
51
73
  fieldDecorator: ImplementationStructureLink,
52
74
  },
75
+ {
76
+ header: "structure.domain",
77
+ fieldSelector: _.path("data_structure.domains"),
78
+ fieldDecorator: DomainDecorator,
79
+ },
53
80
  {
54
81
  header: "structure.system",
55
82
  fieldSelector: _.path("data_structure.system.name"),
@@ -8,6 +8,7 @@ import { linkTo } from "@truedat/core/routes";
8
8
  import ConditionSummary, { empty, path } from "./ConditionSummary";
9
9
  import FieldSummary from "./FieldSummary";
10
10
  import InformationSummary from "./InformationSummary";
11
+ import TaxonomySummary from "./TaxonomySummary";
11
12
  import { JoinTypeIcon } from "./JoinTypeIcon";
12
13
  import "../styles/ImplementationSummary.less";
13
14
 
@@ -164,10 +165,16 @@ export const ImplementationSummary = ({ ruleImplementation, activeSteps }) => {
164
165
  const alias = _.map(_.propOr({}, "alias"))(dataset);
165
166
  return (
166
167
  <>
167
- {(_.includes("implementationKey")(steps) ||
168
- _.includes("executable")(steps)) && (
168
+ {_.includes("implementationKey")(steps) ||
169
+ _.includes("executable")(steps) ? (
169
170
  <InformationSummary ruleImplementation={ruleImplementation} />
170
- )}
171
+ ) : null}
172
+
173
+ {_.includes("dataset")(steps) &&
174
+ !_.isEmpty(ruleImplementation?.data_structures) ? (
175
+ <TaxonomySummary ruleImplementation={ruleImplementation} />
176
+ ) : null}
177
+
171
178
  {dataset && _.includes("dataset")(steps) && (
172
179
  <DatasetSummary rows={dataset} alias={alias} />
173
180
  )}
@@ -4,59 +4,64 @@ import PropTypes from "prop-types";
4
4
  import { connect } from "react-redux";
5
5
  import { Header, Icon, Grid, List } from "semantic-ui-react";
6
6
  import { FormattedMessage } from "react-intl";
7
+ import TaxonomySummary from "./TaxonomySummary";
7
8
 
8
- const empty = rows => rows && _.every(r => _.isEmpty(r) || _.isNil(r))(rows);
9
+ const empty = (rows) =>
10
+ rows && _.every((r) => _.isEmpty(r) || _.isNil(r))(rows);
9
11
 
10
- export const RawContent = ({ content }) => {
12
+ export const RawContent = ({ content, ruleImplementation }) => {
11
13
  const system = _.path("system.name")(content);
12
14
  const source = _.path("source.external_id")(content);
13
15
  const database = _.prop("database")(content);
14
16
 
15
17
  return empty(content) ? null : (
16
- <Grid>
17
- {!_.isEmpty(system) && (
18
- <Grid.Row>
19
- <Grid.Column>
20
- <Header as="h3">
21
- <FormattedMessage id="ruleImplementation.summary.system" />
22
- </Header>
23
- <List>
24
- <List.Item>{system}</List.Item>
25
- </List>
26
- </Grid.Column>
27
- </Grid.Row>
28
- )}
29
- {source && (
30
- <Grid.Row>
31
- <Grid.Column>
32
- <Header as="h3">
33
- <FormattedMessage id="ruleImplementation.summary.source" />
34
- </Header>
35
- <List>
36
- <List.Item>{source}</List.Item>
37
- </List>
38
- </Grid.Column>
39
- </Grid.Row>
40
- )}
41
- {!_.isEmpty(database) && (
42
- <Grid.Row>
43
- <Grid.Column>
44
- <Header as="h3">
45
- <FormattedMessage id="ruleImplementation.summary.database" />
46
- </Header>
47
- <List>
48
- <List.Item>{database}</List.Item>
49
- </List>
50
- </Grid.Column>
51
- </Grid.Row>
52
- )}
53
- {[
54
- { property: "dataset", icon: "database" },
55
- { property: "population", icon: "user" },
56
- { property: "validations", icon: "setting" }
57
- ].map(
58
- ({ property, icon }, i) =>
59
- _.prop(property)(content) && (
18
+ <>
19
+ {!_.isEmpty(ruleImplementation?.data_structures) ? (
20
+ <TaxonomySummary ruleImplementation={ruleImplementation} />
21
+ ) : null}
22
+ <Grid>
23
+ {!_.isEmpty(system) ? (
24
+ <Grid.Row>
25
+ <Grid.Column>
26
+ <Header as="h3">
27
+ <FormattedMessage id="ruleImplementation.summary.system" />
28
+ </Header>
29
+ <List>
30
+ <List.Item>{system}</List.Item>
31
+ </List>
32
+ </Grid.Column>
33
+ </Grid.Row>
34
+ ) : null}
35
+ {source ? (
36
+ <Grid.Row>
37
+ <Grid.Column>
38
+ <Header as="h3">
39
+ <FormattedMessage id="ruleImplementation.summary.source" />
40
+ </Header>
41
+ <List>
42
+ <List.Item>{source}</List.Item>
43
+ </List>
44
+ </Grid.Column>
45
+ </Grid.Row>
46
+ ) : null}
47
+ {!_.isEmpty(database) ? (
48
+ <Grid.Row>
49
+ <Grid.Column>
50
+ <Header as="h3">
51
+ <FormattedMessage id="ruleImplementation.summary.database" />
52
+ </Header>
53
+ <List>
54
+ <List.Item>{database}</List.Item>
55
+ </List>
56
+ </Grid.Column>
57
+ </Grid.Row>
58
+ ) : null}
59
+ {[
60
+ { property: "dataset", icon: "database" },
61
+ { property: "population", icon: "user" },
62
+ { property: "validations", icon: "setting" },
63
+ ].map(({ property, icon }, i) =>
64
+ _.prop(property)(content) ? (
60
65
  <Grid.Row key={i}>
61
66
  <Grid.Column>
62
67
  <Header as="h3">
@@ -76,18 +81,19 @@ export const RawContent = ({ content }) => {
76
81
  </List>
77
82
  </Grid.Column>
78
83
  </Grid.Row>
79
- )
80
- )}
81
- </Grid>
84
+ ) : null
85
+ )}
86
+ </Grid>
87
+ </>
82
88
  );
83
89
  };
84
90
 
85
91
  RawContent.propTypes = {
86
- content: PropTypes.object
92
+ content: PropTypes.object,
87
93
  };
88
94
 
89
95
  export const mapStateToProps = ({ ruleImplementationRaw: content }) => ({
90
- content
96
+ content,
91
97
  });
92
98
 
93
99
  export default connect(mapStateToProps)(RawContent);
@@ -73,7 +73,7 @@ export const RuleImplementationProperties = ({
73
73
  activeSteps={summarySteps}
74
74
  />
75
75
  ) : (
76
- <RawContent />
76
+ <RawContent ruleImplementation={ruleImplementation} />
77
77
  )}
78
78
  </Grid.Column>
79
79
  </Grid>
@@ -9,6 +9,7 @@ import { downloadImplementations } from "../routines";
9
9
  const staticHeaderLabels = [
10
10
  "implementation_key",
11
11
  "implementation_type",
12
+ "domain",
12
13
  "rule",
13
14
  "rule_template",
14
15
  "implementation_template",
@@ -20,6 +21,7 @@ const staticHeaderLabels = [
20
21
  "execution",
21
22
  "inserted_at",
22
23
  "executable",
24
+ "structure_domains",
23
25
  ];
24
26
 
25
27
  const staticContentLabels = [
@@ -0,0 +1,41 @@
1
+ import _ from "lodash/fp";
2
+ import React from "react";
3
+ import PropTypes from "prop-types";
4
+ import { FormattedMessage } from "react-intl";
5
+ import { Header, Icon, Segment, List } from "semantic-ui-react";
6
+
7
+ const domainDecorator = (domains) => (
8
+ <List>
9
+ {domains.map(({ name, parents }, key) => (
10
+ <List.Item key={key}>
11
+ {_.flow(_.map("name"), _.union([name]), _.join(" > "))(parents)}
12
+ </List.Item>
13
+ ))}
14
+ </List>
15
+ );
16
+
17
+ export default function TaxonomySummary({ ruleImplementation }) {
18
+ const dataStructures = ruleImplementation.data_structures || [];
19
+
20
+ const taxonomy = _.flow(
21
+ _.map((structure) => structure.data_structure.domains),
22
+ _.flatten,
23
+ _.uniqBy("name"),
24
+ _.orderBy(["name"], ["asc"])
25
+ )(dataStructures);
26
+
27
+ return (
28
+ <>
29
+ <Header as="h3">
30
+ <Icon name="sitemap" size="small" />
31
+ <Header.Content>
32
+ <FormattedMessage id="ruleImplementation.taxonomy" />
33
+ </Header.Content>
34
+ </Header>
35
+ <Segment>{domainDecorator(taxonomy)}</Segment>
36
+ </>
37
+ );
38
+ }
39
+ TaxonomySummary.propTypes = {
40
+ ruleImplementation: PropTypes.object.isRequired,
41
+ };
@@ -6,6 +6,7 @@ describe("<ImplementationStructures />", () => {
6
6
  const renderOpts = {
7
7
  messages: {
8
8
  en: {
9
+ "structure.domain": "domain",
9
10
  "structure.name": "name",
10
11
  "structure.system": "system",
11
12
  "structure.path": "path",
@@ -26,6 +27,7 @@ describe("<ImplementationStructures />", () => {
26
27
  id: 1,
27
28
  name: "foo",
28
29
  system: { name: "bar" },
30
+ domains: [{ name: "foo_domain", parents: [{ name: "bar" }] }],
29
31
  current_version: {
30
32
  name: "qux",
31
33
  path: ["baz"],
@@ -52,6 +54,7 @@ describe("<ImplementationStructures />", () => {
52
54
  data_structure: {
53
55
  id: 1,
54
56
  name: "foo",
57
+ domains: [{ name: "foo_domain", parents: [{ name: "bar" }] }],
55
58
  system: { name: "bar" },
56
59
  path: ["baz"],
57
60
  current_version: {
@@ -1,40 +1,82 @@
1
1
  import React from "react";
2
- import { shallow } from "enzyme";
2
+ import { render } from "@truedat/test/render";
3
3
  import { RawContent } from "../RawContent";
4
4
 
5
5
  describe("<RawContent />", () => {
6
- it("matches the latest snapshot", () => {
7
- const content = {
8
- source: { external_id: "source" },
9
- dataset: "client c join address a on c.address_id=a.id",
10
- population: "",
11
- validations: "c.city='MADRID'"
6
+ const content = {
7
+ source: { external_id: "external_id_source" },
8
+ dataset: "client c join address a on c.address_id=a.id",
9
+ population: "",
10
+ validations: "c.city='MADRID'",
11
+ system: { name: "foo" },
12
+ database: "bar",
13
+ };
14
+ const ruleImplementation = {
15
+ data_structures: [
16
+ {
17
+ data_structure: {
18
+ domains: [
19
+ {
20
+ id: 1,
21
+ name: "foo",
22
+ },
23
+ {
24
+ id: 2,
25
+ name: "bar",
26
+ },
27
+ ],
28
+ },
29
+ },
30
+ ],
31
+ };
32
+ it("matches the lastest snapshot", () => {
33
+ const props = { content, ruleImplementation };
34
+ const { container } = render(<RawContent {...props} />);
35
+ expect(container).toMatchSnapshot();
36
+ });
37
+
38
+ it("render when content is empty", () => {
39
+ const props = { content: {}, ruleImplementation };
40
+ const { container } = render(<RawContent {...props} />);
41
+ expect(container).toMatchSnapshot();
42
+ });
43
+
44
+ it("render when system is empty", () => {
45
+ const props = {
46
+ content: { ...content, system: {} },
47
+ ruleImplementation,
12
48
  };
49
+ const { container } = render(<RawContent {...props} />);
50
+ expect(container).toMatchSnapshot();
51
+ });
13
52
 
14
- const props = { content };
15
- const wrapper = shallow(<RawContent {...props} />);
16
- expect(wrapper).toMatchSnapshot();
53
+ it("render when database is empty", () => {
54
+ const props = {
55
+ content: { ...content, database: {} },
56
+ ruleImplementation,
57
+ };
58
+ const { container } = render(<RawContent {...props} />);
59
+ expect(container).toMatchSnapshot();
17
60
  });
18
61
 
19
- it("renders alias if present", () => {
20
- const content = {
21
- source: { external_id: "source" },
22
- dataset: "client c join address a on c.address_id=a.id",
23
- population: "",
24
- validations: "c.city='MADRID'"
62
+ it("render when source is empty", () => {
63
+ const props = {
64
+ content: { ...content, source: {} },
65
+ ruleImplementation,
25
66
  };
67
+ const { container } = render(<RawContent {...props} />);
68
+ expect(container).toMatchSnapshot();
69
+ });
70
+
71
+ it("render when data_structures is empty", () => {
72
+ const props = { content, ruleImplementation: {} };
73
+ const { container } = render(<RawContent {...props} />);
74
+ expect(container).toMatchSnapshot();
75
+ });
26
76
 
77
+ it("renders alias if present", async () => {
27
78
  const props = { content };
28
- const wrapper = shallow(<RawContent {...props} />);
29
- expect(wrapper).toMatchSnapshot();
30
- expect(
31
- wrapper
32
- .find("GridRow")
33
- .at(0)
34
- .find("ListItem")
35
- .children()
36
- .at(0)
37
- .text()
38
- ).toBe(content.source.external_id);
79
+ const { findByText } = render(<RawContent {...props} />);
80
+ expect(await findByText(/external_id_source/)).toBeInTheDocument();
39
81
  });
40
82
  });
@@ -0,0 +1,39 @@
1
+ import React from "react";
2
+ import { render } from "@truedat/test/render";
3
+ import messages from "@truedat/dq/messages";
4
+ import TaxonomySummary from "../TaxonomySummary";
5
+
6
+ describe("<TaxonomySummary />", () => {
7
+ const ruleImplementation = {
8
+ data_structures: [
9
+ {
10
+ data_structure: {
11
+ domains: [
12
+ {
13
+ id: 1,
14
+ name: "foo",
15
+ },
16
+ {
17
+ id: 2,
18
+ name: "bar",
19
+ },
20
+ ],
21
+ },
22
+ },
23
+ ],
24
+ };
25
+
26
+ it("matches the latest snapshot", () => {
27
+ const renderOpts = {
28
+ messages: {
29
+ en: {
30
+ ...messages.en,
31
+ },
32
+ },
33
+ };
34
+
35
+ const props = { ruleImplementation };
36
+ const { container } = render(<TaxonomySummary {...props} />, renderOpts);
37
+ expect(container).toMatchSnapshot();
38
+ });
39
+ });
@@ -25,6 +25,11 @@ exports[`<ImplementationStructures /> matches the latest snapshot 1`] = `
25
25
  >
26
26
  name
27
27
  </th>
28
+ <th
29
+ class=""
30
+ >
31
+ domain
32
+ </th>
28
33
  <th
29
34
  class=""
30
35
  >
@@ -60,6 +65,21 @@ exports[`<ImplementationStructures /> matches the latest snapshot 1`] = `
60
65
  qux
61
66
  </a>
62
67
  </td>
68
+ <td
69
+ class=""
70
+ >
71
+ <div
72
+ class="ui list"
73
+ role="list"
74
+ >
75
+ <div
76
+ class="item"
77
+ role="listitem"
78
+ >
79
+ bar &gt; foo_domain
80
+ </div>
81
+ </div>
82
+ </td>
63
83
  <td
64
84
  class=""
65
85
  >
@@ -121,6 +141,11 @@ exports[`<ImplementationStructures /> matches the latest snapshot without create
121
141
  >
122
142
  name
123
143
  </th>
144
+ <th
145
+ class=""
146
+ >
147
+ domain
148
+ </th>
124
149
  <th
125
150
  class=""
126
151
  >
@@ -153,6 +178,21 @@ exports[`<ImplementationStructures /> matches the latest snapshot without create
153
178
  qux
154
179
  </a>
155
180
  </td>
181
+ <td
182
+ class=""
183
+ >
184
+ <div
185
+ class="ui list"
186
+ role="list"
187
+ >
188
+ <div
189
+ class="item"
190
+ role="listitem"
191
+ >
192
+ bar &gt; foo_domain
193
+ </div>
194
+ </div>
195
+ </td>
156
196
  <td
157
197
  class=""
158
198
  >