@truedat/dq 4.33.8 → 4.33.9

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,9 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.33.9] 2021-11-29
4
+
5
+ - [TD-4306] Add `df_content` to execution groups
6
+
3
7
  ## [4.33.6] 2021-11-29
4
8
 
5
9
  ### Added
@@ -16,7 +20,7 @@
16
20
 
17
21
  ### Hotfix
18
22
 
19
- [TD-4327] Fix dropdown domain selector for glossay new quality rule
23
+ - [TD-4327] Fix dropdown domain selector for glossay new quality rule
20
24
 
21
25
  ## [4.31.4] 2021-10-25
22
26
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/dq",
3
- "version": "4.33.8",
3
+ "version": "4.33.9",
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.33.9",
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.33.9",
86
+ "@truedat/df": "4.33.9",
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": "f2635d86f1fc4efccf638aba8ebab749f39a9b1e"
107
107
  }
@@ -0,0 +1,105 @@
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
+ }) => {
29
+ const { formatMessage } = useIntl();
30
+ const [content, setContent] = useState({});
31
+
32
+ const handleContentChange = (content) => setContent(content);
33
+
34
+ const handleTemplateSelected = (e, { value }) =>
35
+ selectTemplate({ id: value });
36
+
37
+ const isInvalid = () =>
38
+ template && !_.isEmpty(validateContent(template)(content));
39
+
40
+ if (_.size(templates) == 1) {
41
+ const id = _.flow(_.head, _.prop("id"))(templates);
42
+ selectTemplate({ id });
43
+ }
44
+
45
+ return (
46
+ <>
47
+ <Header
48
+ as="h2"
49
+ content={formatMessage({
50
+ id: "implementations.actions.execution.confirmation.header",
51
+ })}
52
+ />
53
+ <Suspense fallback={null}>
54
+ <Form>
55
+ <TemplateLoader scope="qe" />
56
+ {_.size(templates) > 1 && (
57
+ <TemplateSelector
58
+ name="template"
59
+ selectedValue={_.prop("id")(template)}
60
+ onChange={handleTemplateSelected}
61
+ isOptional={true}
62
+ />
63
+ )}
64
+ {template && template.id && (
65
+ <>
66
+ <Header
67
+ as="h3"
68
+ content={formatMessage({
69
+ id: "implementations.actions.execution.confirmation.legend",
70
+ })}
71
+ />
72
+ <DynamicForm onChange={handleContentChange} content={content} />
73
+ </>
74
+ )}
75
+ <p>
76
+ {formatMessage(
77
+ { id: "implementations.actions.execution.confirmation.content" },
78
+ { implementations_count: count }
79
+ )}
80
+ </p>
81
+ <div className="actions">
82
+ <Button
83
+ primary
84
+ disabled={isInvalid()}
85
+ onClick={() => handleSubmit(content)}
86
+ content={formatMessage({ id: "actions.create" })}
87
+ />
88
+ </div>
89
+ </Form>
90
+ </Suspense>
91
+ </>
92
+ );
93
+ };
94
+
95
+ ExecutionForm.propTypes = {
96
+ count: PropTypes.number,
97
+ template: PropTypes.object,
98
+ templates: PropTypes.array,
99
+ selectTemplate: PropTypes.func,
100
+ handleSubmit: PropTypes.func,
101
+ };
102
+
103
+ const mapStateToProps = _.pick(["templates", "template"]);
104
+
105
+ export default connect(mapStateToProps, { selectTemplate })(ExecutionForm);
@@ -0,0 +1,54 @@
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={() => setOpen(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 count={count} handleSubmit={handleSubmit} />
41
+ </Popup>
42
+ );
43
+ };
44
+
45
+ ExecutionPopup.propTypes = {
46
+ count: PropTypes.number,
47
+ disabled: PropTypes.bool,
48
+ executionGroupLoading: PropTypes.bool,
49
+ handleSubmit: PropTypes.func,
50
+ };
51
+
52
+ const mapStateToProps = _.pick(["executionGroupLoading"]);
53
+
54
+ export default connect(mapStateToProps)(ExecutionPopup);
@@ -5,12 +5,22 @@ import ImplementationFiltersLoader from "./ImplementationFiltersLoader";
5
5
  import RuleImplementations from "./RuleImplementations";
6
6
  import RuleImplementationsLoader from "./RuleImplementationsLoader";
7
7
 
8
+ const TemplatesLoader = React.lazy(() =>
9
+ import("@truedat/df/templates/components/TemplatesLoader")
10
+ );
11
+
8
12
  const ImplementationsRoutes = () => (
9
- <>
10
- <Route path={IMPLEMENTATIONS} component={RuleImplementationsLoader} />
11
- <Route path={IMPLEMENTATIONS} component={ImplementationFiltersLoader} />
12
- <Route path={IMPLEMENTATIONS} component={RuleImplementations} exact />
13
- </>
13
+ <Route
14
+ path={IMPLEMENTATIONS}
15
+ render={() => (
16
+ <>
17
+ <RuleImplementationsLoader />
18
+ <ImplementationFiltersLoader />
19
+ <TemplatesLoader scope="qe" />
20
+ <RuleImplementations exact />
21
+ </>
22
+ )}
23
+ />
14
24
  );
15
25
 
16
26
  export default ImplementationsRoutes;
@@ -4,8 +4,6 @@ import PropTypes from "prop-types";
4
4
  import { connect } from "react-redux";
5
5
  import { Button, Checkbox } from "semantic-ui-react";
6
6
  import { useIntl } from "react-intl";
7
- import { FormattedMessage } from "react-intl";
8
- import { ConfirmModal } from "@truedat/core/components";
9
7
  import { downloadImplementations } from "../routines";
10
8
  import { getImplementationsExecution } from "../selectors";
11
9
  import {
@@ -14,6 +12,7 @@ import {
14
12
  removeImplementationFilter,
15
13
  createExecutionGroup,
16
14
  } from "../routines";
15
+ import ExecutionPopup from "./ExecutionPopup";
17
16
 
18
17
  const staticHeaderLabels = [
19
18
  "implementation_key",
@@ -39,20 +38,6 @@ const staticContentLabels = [
39
38
  "executable.false",
40
39
  ];
41
40
 
42
- const actions = (handleSubmit) => [
43
- {
44
- key: "no",
45
- secondary: true,
46
- content: <FormattedMessage id="confirmation.no" />,
47
- },
48
- {
49
- key: "yes",
50
- primary: true,
51
- content: <FormattedMessage id="confirmation.yes" />,
52
- onClick: handleSubmit,
53
- },
54
- ];
55
-
56
41
  export const RuleImplementationsActions = ({
57
42
  addImplementationFilter,
58
43
  canExecute,
@@ -60,7 +45,6 @@ export const RuleImplementationsActions = ({
60
45
  executeImplementationsOn,
61
46
  toggleImplementationFilterValue,
62
47
  removeImplementationFilter,
63
- executionGroupLoading,
64
48
  createExecutionGroup,
65
49
  selectedImplementations,
66
50
  implementationQuery,
@@ -99,11 +83,11 @@ export const RuleImplementationsActions = ({
99
83
  checked ? showExecutableInfo() : hideExecutableInfo();
100
84
  };
101
85
 
102
- const handleSubmit = () => {
86
+ const handleSubmit = (df_content) => {
103
87
  const query = _.isEmpty(selectedImplementations)
104
88
  ? implementationQuery
105
89
  : { filters: { id: selectedImplementations } };
106
- createExecutionGroup({ ...query });
90
+ createExecutionGroup({ ...query, df_content });
107
91
  };
108
92
  return (
109
93
  <div style={{ float: "right" }}>
@@ -117,32 +101,14 @@ export const RuleImplementationsActions = ({
117
101
  checked={executeImplementationsOn}
118
102
  style={{ top: "6px", marginRight: "7.5px" }}
119
103
  />
120
- <ConfirmModal
121
- actions={actions(handleSubmit)}
122
- trigger={
123
- <Button
124
- id="execute_button"
125
- secondary
126
- disabled={!executeImplementationsOn}
127
- loading={executionGroupLoading}
128
- content={
129
- <FormattedMessage id="implementations.actions.do_execution" />
130
- }
131
- />
132
- }
133
- header={
134
- <FormattedMessage id="implementations.actions.execution.confirmation.header" />
135
- }
136
- content={
137
- <FormattedMessage
138
- id="implementations.actions.execution.confirmation.content"
139
- values={{
140
- implementations_count: _.isEmpty(selectedImplementations)
141
- ? ruleImplementationCount
142
- : selectedImplementations.length,
143
- }}
144
- />
104
+ <ExecutionPopup
105
+ disabled={!executeImplementationsOn}
106
+ count={
107
+ _.isEmpty(selectedImplementations)
108
+ ? ruleImplementationCount
109
+ : selectedImplementations.length
145
110
  }
111
+ handleSubmit={handleSubmit}
146
112
  />
147
113
  </>
148
114
  )}
@@ -170,7 +136,6 @@ RuleImplementationsActions.propTypes = {
170
136
  canExecute: PropTypes.bool,
171
137
  createExecutionGroup: PropTypes.func,
172
138
  executeImplementationsOn: PropTypes.bool,
173
- executionGroupLoading: PropTypes.bool,
174
139
  implementationsExecution: PropTypes.bool,
175
140
  implementationQuery: PropTypes.object,
176
141
  removeImplementationFilter: PropTypes.func,
@@ -184,7 +149,6 @@ RuleImplementationsActions.propTypes = {
184
149
 
185
150
  const mapStateToProps = (state) => ({
186
151
  canExecute: _.propOr(false, "userImplementationsPermissions.execute")(state),
187
- executionGroupLoading: state.executionGroupLoading,
188
152
  ruleImplementationCount: state.ruleImplementationCount,
189
153
  implementationsExecution: getImplementationsExecution(state),
190
154
  ruleImplementationsDownloading: state.ruleImplementationsDownloading,
@@ -0,0 +1,24 @@
1
+ import React from "react";
2
+ import { render } from "@truedat/test/render";
3
+ import { ExecutionForm } from "../ExecutionForm";
4
+
5
+ describe("<ExecutionForm />", () => {
6
+ const handleSubmit = jest.fn();
7
+ const selectTemplate = jest.fn();
8
+ const props = { count: 1, templates: [], handleSubmit, selectTemplate };
9
+ const renderOpts = {
10
+ messages: {
11
+ en: {
12
+ "actions.create": "create",
13
+ "implementations.actions.execution.confirmation.content": "content",
14
+ "implementations.actions.execution.confirmation.header": "header",
15
+ "implementations.actions.execution.confirmation.legend": "legend",
16
+ },
17
+ },
18
+ };
19
+
20
+ it("matches the latest snapshot", () => {
21
+ const { container } = render(<ExecutionForm {...props} />, renderOpts);
22
+ expect(container).toMatchSnapshot();
23
+ });
24
+ });
@@ -0,0 +1,20 @@
1
+ import React from "react";
2
+ import { render } from "@truedat/test/render";
3
+ import { ExecutionPopup } from "../ExecutionPopup";
4
+
5
+ describe("<ExecutionPopup />", () => {
6
+ const handleSubmit = jest.fn();
7
+ const props = { count: 1, handleSubmit };
8
+ const renderOpts = {
9
+ messages: {
10
+ en: {
11
+ "implementations.actions.do_execution": "do_execution",
12
+ },
13
+ },
14
+ };
15
+
16
+ it("matches the latest snapshot", () => {
17
+ const { container } = render(<ExecutionPopup {...props} />, renderOpts);
18
+ expect(container).toMatchSnapshot();
19
+ });
20
+ });
@@ -24,7 +24,7 @@ describe("<RuleImplementationsActions />", () => {
24
24
  addImplementationFilter,
25
25
  executeImplementationsOn: false,
26
26
  setMode,
27
- removeImplementationFilter
27
+ removeImplementationFilter,
28
28
  };
29
29
  it("matches the latest snapshot", () => {
30
30
  const wrapper = shallow(<RuleImplementationsActions {...props} />);
@@ -43,11 +43,11 @@ describe("<RuleImplementationsActions />", () => {
43
43
  executionGroupLoading: false,
44
44
  ruleImplementationCount: 12,
45
45
  implementationsExecution: true,
46
- role: "user"
46
+ role: "user",
47
47
  };
48
48
  const wrapper = shallow(<RuleImplementationsActions {...props} />);
49
49
  expect(wrapper.find({ id: "execute_checkbox" }).length).toBe(1);
50
- expect(wrapper.find("ConfirmModal").length).toBe(1);
50
+ expect(wrapper.find("Connect(ExecutionPopup)").length).toBe(1);
51
51
  });
52
52
 
53
53
  it("as user I do not see execute rules actions if I have no permission", () => {
@@ -55,11 +55,11 @@ describe("<RuleImplementationsActions />", () => {
55
55
  canExecute: false,
56
56
  executionGroupLoading: false,
57
57
  ruleImplementationCount: 12,
58
- implementationsExecution: true
58
+ implementationsExecution: true,
59
59
  };
60
60
  const wrapper = shallow(<RuleImplementationsActions {...props} />);
61
61
  expect(wrapper.find("Checkbox").length).toBe(0);
62
- expect(wrapper.find("ConfirmModal").length).toBe(0);
62
+ expect(wrapper.find("Connect(ExecutionPopup)").length).toBe(0);
63
63
  expect(wrapper.find({ id: "execute_button" }).length).toBe(0);
64
64
  });
65
65
 
@@ -69,12 +69,12 @@ describe("<RuleImplementationsActions />", () => {
69
69
  executionGroupLoading: false,
70
70
  ruleImplementationCount: 12,
71
71
  implementationsExecution: true,
72
- executeImplementationsOn: true
72
+ executeImplementationsOn: true,
73
73
  };
74
74
  const wrapper = shallow(<RuleImplementationsActions {...props} />);
75
75
  expect(wrapper.find("Checkbox").length).toBe(1);
76
76
  expect(wrapper.find("Checkbox").props().checked).toBeTruthy();
77
- expect(wrapper.find("ConfirmModal").length).toBe(1);
77
+ expect(wrapper.find("Connect(ExecutionPopup)").length).toBe(1);
78
78
  });
79
79
 
80
80
  it("handles checkbox onChange", () => {
@@ -85,11 +85,11 @@ describe("<RuleImplementationsActions />", () => {
85
85
  toCheck.simulate("change");
86
86
  expect(setMode).toHaveBeenCalledWith(true);
87
87
  expect(addImplementationFilter).toHaveBeenCalledWith({
88
- filter: "executable"
88
+ filter: "executable",
89
89
  });
90
90
  expect(toggleImplementationFilterValue).toHaveBeenCalledWith({
91
91
  filter: "executable",
92
- value: true
92
+ value: true,
93
93
  });
94
94
  wrapper.setProps({ executeImplementationsOn: true });
95
95
  setMode.mockReset();
@@ -98,29 +98,7 @@ describe("<RuleImplementationsActions />", () => {
98
98
  toUncheck.simulate("change");
99
99
  expect(setMode).toHaveBeenCalledWith(false);
100
100
  expect(removeImplementationFilter).toHaveBeenCalledWith({
101
- filter: "executable"
102
- });
103
- });
104
-
105
- it("as user I can submit an execution", () => {
106
- const createExecutionGroup = jest.fn();
107
- const props = {
108
- canExecute: true,
109
- executionGroupLoading: false,
110
- ruleImplementationCount: 12,
111
- implementationsExecution: true,
112
- executeImplementationsOn: true,
113
- createExecutionGroup,
114
- selectedImplementations: [],
115
- implementationQuery: { filters: { concept: ["foo"] } }
116
- };
117
- const wrapper = shallow(<RuleImplementationsActions {...props} />);
118
- _.find({ key: "yes" })(
119
- wrapper.find("ConfirmModal").props().actions
120
- ).onClick({ preventDefault() {} });
121
- expect(props.createExecutionGroup.mock.calls.length).toBe(1);
122
- expect(props.createExecutionGroup).toHaveBeenCalledWith({
123
- filters: { concept: ["foo"] }
101
+ filter: "executable",
124
102
  });
125
103
  });
126
104
  });
@@ -0,0 +1,28 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`<ExecutionForm /> matches the latest snapshot 1`] = `
4
+ <div>
5
+ <h2
6
+ class="ui header"
7
+ >
8
+ header
9
+ </h2>
10
+ <form
11
+ class="ui form"
12
+ style="display: none;"
13
+ >
14
+ <p>
15
+ content
16
+ </p>
17
+ <div
18
+ class="actions"
19
+ >
20
+ <button
21
+ class="ui primary button"
22
+ >
23
+ create
24
+ </button>
25
+ </div>
26
+ </form>
27
+ </div>
28
+ `;
@@ -0,0 +1,11 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`<ExecutionPopup /> matches the latest snapshot 1`] = `
4
+ <div>
5
+ <button
6
+ class="ui secondary button"
7
+ >
8
+ do_execution
9
+ </button>
10
+ </div>
11
+ `;
@@ -22,55 +22,10 @@ exports[`<RuleImplementationsActions /> matches the latest snapshot 1`] = `
22
22
  toggle={true}
23
23
  type="checkbox"
24
24
  />
25
- <ConfirmModal
26
- actions={
27
- Array [
28
- Object {
29
- "content": <Memo(MemoizedFormattedMessage)
30
- id="confirmation.no"
31
- />,
32
- "key": "no",
33
- "secondary": true,
34
- },
35
- Object {
36
- "content": <Memo(MemoizedFormattedMessage)
37
- id="confirmation.yes"
38
- />,
39
- "key": "yes",
40
- "onClick": [Function],
41
- "primary": true,
42
- },
43
- ]
44
- }
45
- content={
46
- <Memo(MemoizedFormattedMessage)
47
- id="implementations.actions.execution.confirmation.content"
48
- values={
49
- Object {
50
- "implementations_count": 12,
51
- }
52
- }
53
- />
54
- }
55
- header={
56
- <Memo(MemoizedFormattedMessage)
57
- id="implementations.actions.execution.confirmation.header"
58
- />
59
- }
60
- trigger={
61
- <Button
62
- as="button"
63
- content={
64
- <Memo(MemoizedFormattedMessage)
65
- id="implementations.actions.do_execution"
66
- />
67
- }
68
- disabled={true}
69
- id="execute_button"
70
- loading={false}
71
- secondary={true}
72
- />
73
- }
25
+ <Connect(ExecutionPopup)
26
+ count={12}
27
+ disabled={true}
28
+ handleSubmit={[Function]}
74
29
  />
75
30
  <Button
76
31
  as="button"
@@ -48,6 +48,7 @@ export default {
48
48
  "implementations.actions.download.tooltip": "Download to csv",
49
49
  "implementations.actions.execution.confirmation.content": "{implementations_count} implementations will be executed. Are you sure?",
50
50
  "implementations.actions.execution.confirmation.header": "Implementations execution",
51
+ "implementations.actions.execution.confirmation.legend": "Template fields",
51
52
  "implementations.execute.filtered": "{count} implementations to execute",
52
53
  "implementations.search.placeholder": "Search implementations...",
53
54
  "navigation.quality": "Quality",
@@ -48,6 +48,7 @@ export default {
48
48
  "implementations.actions.download.tooltip": "Descargar en csv",
49
49
  "implementations.actions.execution.confirmation.content": "Se va a solicitar la ejecución de {implementations_count} implementaciones. ¿Estás seguro?",
50
50
  "implementations.actions.execution.confirmation.header": "Solicitar ejecución de implementaciones",
51
+ "implementations.actions.execution.confirmation.legend": "Campos de la plantilla",
51
52
  "implementations.execute.filtered": "{count} implementaciones a ejecutar",
52
53
  "implementations.search.placeholder": "Buscar implementaciones...",
53
54
  "navigation.quality": "Calidad",