@truedat/qx 8.5.1 → 8.5.2

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 (52) hide show
  1. package/package.json +3 -3
  2. package/src/components/common/expressions/Clauses.js +5 -9
  3. package/src/components/common/expressions/Condition.js +36 -37
  4. package/src/components/common/expressions/__tests__/Clauses.spec.js +87 -0
  5. package/src/components/common/expressions/__tests__/Condition.spec.js +220 -1
  6. package/src/components/common/expressions/__tests__/__snapshots__/Clauses.spec.js.snap +22 -21
  7. package/src/components/common/expressions/__tests__/__snapshots__/Condition.spec.js.snap +212 -214
  8. package/src/components/dataViews/queryableProperties/GroupBy.js +4 -2
  9. package/src/components/dataViews/queryableProperties/__tests__/GroupBy.spec.js +134 -28
  10. package/src/components/qualityControls/ControlProperties.js +32 -16
  11. package/src/components/qualityControls/ControlPropertiesForm.js +3 -3
  12. package/src/components/qualityControls/ControlPropertiesSummary.js +127 -104
  13. package/src/components/qualityControls/ControlPropertiesView.js +48 -74
  14. package/src/components/qualityControls/InformationForm.js +181 -180
  15. package/src/components/qualityControls/ScoreCriteria.js +0 -4
  16. package/src/components/qualityControls/ScoreCriteriaView.js +6 -9
  17. package/src/components/qualityControls/__tests__/ControlProperties.spec.js +47 -16
  18. package/src/components/qualityControls/__tests__/ControlPropertiesForm.spec.js +100 -0
  19. package/src/components/qualityControls/__tests__/ControlPropertiesSummary.spec.js +141 -0
  20. package/src/components/qualityControls/__tests__/ControlPropertiesView.spec.js +102 -11
  21. package/src/components/qualityControls/__tests__/EditQualityControl.spec.js +27 -3
  22. package/src/components/qualityControls/__tests__/InformationForm.spec.js +342 -0
  23. package/src/components/qualityControls/__tests__/NewDraftQualityControl.spec.js +26 -6
  24. package/src/components/qualityControls/__tests__/NewQualityControl.spec.js +66 -20
  25. package/src/components/qualityControls/__tests__/QualityBadge.spec.js +30 -3
  26. package/src/components/qualityControls/__tests__/QualityControlEditor.spec.js +282 -45
  27. package/src/components/qualityControls/__tests__/ScoreCriteria.spec.js +25 -3
  28. package/src/components/qualityControls/__tests__/ScoreCriteriaView.spec.js +19 -3
  29. package/src/components/qualityControls/__tests__/__fixtures__/qualityControlHelper.js +1 -1
  30. package/src/components/qualityControls/__tests__/__snapshots__/ControlProperties.spec.js.snap +13 -1
  31. package/src/components/qualityControls/__tests__/__snapshots__/ControlPropertiesView.spec.js.snap +70 -40
  32. package/src/components/qualityControls/__tests__/__snapshots__/EditQualityControl.spec.js.snap +118 -132
  33. package/src/components/qualityControls/__tests__/__snapshots__/NewDraftQualityControl.spec.js.snap +118 -132
  34. package/src/components/qualityControls/__tests__/__snapshots__/NewQualityControl.spec.js.snap +0 -13
  35. package/src/components/qualityControls/__tests__/__snapshots__/QualityBadge.spec.js.snap +15 -5
  36. package/src/components/qualityControls/__tests__/__snapshots__/QualityControlEditor.spec.js.snap +488 -125
  37. package/src/components/qualityControls/__tests__/__snapshots__/ScoreCriteria.spec.js.snap +13 -5
  38. package/src/components/qualityControls/__tests__/qualityByControlMode.spec.js +65 -14
  39. package/src/components/qualityControls/controlProperties/{Ratio.js → ResourceWithValidation.js} +19 -10
  40. package/src/components/qualityControls/controlProperties/__tests__/ResourceWithValidation.spec.js +192 -0
  41. package/src/components/qualityControls/qualityByControlMode.js +6 -30
  42. package/src/components/qualityControls/scoreCriterias/ErrorCount.js +0 -1
  43. package/src/components/qualityControls/scoreCriterias/__tests__/ErrorCount.spec.js +4 -4
  44. package/src/components/dataViews/queryableProperties/__tests__/__snapshots__/GroupBy.spec.js.snap +0 -604
  45. package/src/components/qualityControls/controlProperties/Count.js +0 -56
  46. package/src/components/qualityControls/controlProperties/__tests__/Count.spec.js +0 -66
  47. package/src/components/qualityControls/controlProperties/__tests__/Ratio.spec.js +0 -95
  48. package/src/components/qualityControls/controlProperties/__tests__/__snapshots__/Count.spec.js.snap +0 -67
  49. package/src/components/qualityControls/controlProperties/__tests__/__snapshots__/Ratio.spec.js.snap +0 -161
  50. package/src/components/qualityControls/scoreCriterias/Count.js +0 -88
  51. package/src/components/qualityControls/scoreCriterias/__tests__/Count.spec.js +0 -62
  52. package/src/components/qualityControls/scoreCriterias/__tests__/__snapshots__/Count.spec.js.snap +0 -58
@@ -1,49 +1,155 @@
1
1
  import userEvent from "@testing-library/user-event";
2
+ import { waitFor } from "@testing-library/react";
2
3
  import { render, waitForLoad } from "@truedat/test/render";
3
4
  import TestFormWrapper from "@truedat/qx/components/common/TestFormWrapper";
4
5
  import GroupBy from "../GroupBy";
5
6
 
7
+ jest.mock("../SelectField", () => {
8
+ const React = require("react");
9
+ const { use } = React;
10
+ const QxContextMock = require("@truedat/qx/components/QxContext").default;
11
+
12
+ const MockSelectField = ({ onDelete }) => {
13
+ const { field } = use(QxContextMock);
14
+ const isAggregate = field.includes("aggregate_fields");
15
+
16
+ return (
17
+ <button type="button" onClick={onDelete}>
18
+ {isAggregate ? "delete-aggregate" : "delete-group"}
19
+ </button>
20
+ );
21
+ };
22
+
23
+ return {
24
+ __esModule: true,
25
+ default: MockSelectField,
26
+ newSelectField: (id) => ({
27
+ id,
28
+ alias: "",
29
+ expression: {},
30
+ }),
31
+ };
32
+ });
33
+
34
+ const renderGroupBy = (defaultValues) =>
35
+ render(
36
+ <TestFormWrapper
37
+ context={{
38
+ field: "queryables[0].properties",
39
+ functions: [{ class: "aggregator", name: "func", type: "number" }],
40
+ }}
41
+ defaultValues={defaultValues}
42
+ >
43
+ <GroupBy />
44
+ </TestFormWrapper>
45
+ );
46
+
6
47
  describe("<GroupBy />", () => {
7
- it("matches the latest snapshot", async () => {
48
+ it("renders existing group and aggregate fields", async () => {
49
+ const rendered = renderGroupBy({
50
+ queryables: [
51
+ {
52
+ id: 0,
53
+ type: "group_by",
54
+ properties: {
55
+ group_fields: [{ alias: "group_alias", expression: {}, id: 1 }],
56
+ aggregate_fields: [
57
+ { alias: "aggregate_alias", expression: {}, id: 2 },
58
+ ],
59
+ },
60
+ },
61
+ ],
62
+ });
63
+ await waitForLoad(rendered);
64
+
65
+ expect(
66
+ rendered.getAllByRole("button", { name: /delete-group/i })
67
+ ).toHaveLength(1);
68
+ expect(
69
+ rendered.getAllByRole("button", { name: /delete-aggregate/i })
70
+ ).toHaveLength(1);
71
+ });
72
+
73
+ it("adds group and aggregate fields", async () => {
8
74
  const user = userEvent.setup({ delay: null });
9
- const rendered = render(
10
- <TestFormWrapper
11
- context={{
12
- field: "queryables[0].properties",
13
- functions: [{ class: "aggregator", name: "func", type: "number" }],
14
- }}
15
- defaultValues={{
16
- queryables: [
17
- {
18
- id: 0,
19
- type: "group_by",
20
- properties: {
21
- group_fields: [{ name: "abc", id: 1 }],
22
- aggregate_fields: [{ name: "def", id: 2 }],
23
- },
24
- },
25
- ],
26
- }}
27
- >
28
- <GroupBy />
29
- </TestFormWrapper>
30
- );
75
+ const rendered = renderGroupBy({
76
+ queryables: [
77
+ {
78
+ id: 0,
79
+ type: "group_by",
80
+ properties: {
81
+ group_fields: [{ alias: "abc", expression: {}, id: 1 }],
82
+ aggregate_fields: [{ alias: "def", expression: {}, id: 2 }],
83
+ },
84
+ },
85
+ ],
86
+ });
31
87
  await waitForLoad(rendered);
32
88
 
33
89
  await user.click(
34
90
  rendered.getByRole("button", { name: /add_group_field/i })
35
91
  );
92
+ expect(
93
+ rendered.getAllByRole("button", { name: /delete-group/i })
94
+ ).toHaveLength(2);
95
+
96
+ await user.click(
97
+ rendered.getByRole("button", { name: /add_aggregate_field/i })
98
+ );
99
+ await waitFor(() =>
100
+ expect(
101
+ rendered.getAllByRole("button", { name: /delete-aggregate/i })
102
+ ).toHaveLength(2)
103
+ );
104
+ });
36
105
 
37
- await user.hover(rendered.getAllByRole("textbox")[2]);
38
- await user.click(rendered.getByRole("button", { name: /delete/i }));
106
+ it("deletes group and aggregate fields", async () => {
107
+ const user = userEvent.setup({ delay: null });
108
+ const rendered = renderGroupBy({
109
+ queryables: [
110
+ {
111
+ id: 0,
112
+ type: "group_by",
113
+ properties: {
114
+ group_fields: [{ alias: "abc", expression: {}, id: 1 }],
115
+ aggregate_fields: [{ alias: "def", expression: {}, id: 2 }],
116
+ },
117
+ },
118
+ ],
119
+ });
120
+ await waitForLoad(rendered);
39
121
 
122
+ await user.click(
123
+ rendered.getByRole("button", { name: /add_group_field/i })
124
+ );
40
125
  await user.click(
41
126
  rendered.getByRole("button", { name: /add_aggregate_field/i })
42
127
  );
128
+ await waitFor(() =>
129
+ expect(
130
+ rendered.getAllByRole("button", { name: /delete-group/i })
131
+ ).toHaveLength(2)
132
+ );
133
+ expect(
134
+ rendered.getAllByRole("button", { name: /delete-aggregate/i })
135
+ ).toHaveLength(2);
43
136
 
44
- await user.hover(rendered.getAllByRole("textbox")[3]);
45
- await user.click(rendered.getByRole("button", { name: /delete/i }));
137
+ await user.click(
138
+ rendered.getAllByRole("button", { name: /delete-group/i })[1]
139
+ );
140
+ await waitFor(() =>
141
+ expect(
142
+ rendered.getAllByRole("button", { name: /delete-group/i })
143
+ ).toHaveLength(1)
144
+ );
46
145
 
47
- expect(rendered.container).toMatchSnapshot();
146
+ await user.click(
147
+ rendered.getAllByRole("button", { name: /delete-aggregate/i })[1]
148
+ );
149
+ await waitFor(() =>
150
+ expect(
151
+ rendered.getAllByRole("button", { name: /delete-aggregate/i })
152
+ ).toHaveLength(1)
153
+ );
48
154
  });
49
155
  });
@@ -2,14 +2,26 @@ import { use, lazy } from "react";
2
2
  import { Controller, useFormContext } from "react-hook-form";
3
3
  import { Form, Segment } from "semantic-ui-react";
4
4
  import QxContext from "@truedat/qx/components/QxContext";
5
- import Count from "./controlProperties/Count";
6
- import Ratio from "./controlProperties/Ratio";
5
+ import ResourceWithValidation from "./controlProperties/ResourceWithValidation";
7
6
  import { useIntl } from "react-intl";
8
7
 
9
8
  const SourceSelector = lazy(
10
- () => import("@truedat/cx/sources/components/SourceSelector")
9
+ () => import("@truedat/cx/sources/components/SourceSelector"),
11
10
  );
12
11
 
12
+ const countControlProps = {
13
+ resourceKey: "errors_resource",
14
+ resourceLabelId:
15
+ "quality_control.form.control_properties.count.errors_resource",
16
+ validationLabelId: "quality_control.form.control_properties.count.validation",
17
+ };
18
+
19
+ const ratioControlProps = {
20
+ resourceKey: "resource",
21
+ resourceLabelId: "quality_control.form.control_properties.ratio.resource",
22
+ validationLabelId: "quality_control.form.control_properties.ratio.validation",
23
+ };
24
+
13
25
  export default function ControlProperties({ isModification }) {
14
26
  const { control, watch } = useFormContext();
15
27
  const { formatMessage } = useIntl();
@@ -18,10 +30,9 @@ export default function ControlProperties({ isModification }) {
18
30
  const { control_mode: controlMode } = watch();
19
31
 
20
32
  const componentForMode = {
21
- count: <Count />,
22
- deviation: <Ratio />,
23
- error_count: <Ratio />,
24
- percentage: <Ratio />,
33
+ deviation: <ResourceWithValidation {...ratioControlProps} />,
34
+ error_count: <ResourceWithValidation {...countControlProps} />,
35
+ percentage: <ResourceWithValidation {...ratioControlProps} />,
25
36
  };
26
37
 
27
38
  return controlMode ? (
@@ -33,9 +44,12 @@ export default function ControlProperties({ isModification }) {
33
44
  required: {
34
45
  value: true,
35
46
  message: formatMessage({ id: "quality_control.form.required" }),
36
- }
47
+ },
37
48
  }}
38
- render={({ field: { onChange, onBlur, value }, fieldState: { error } }) => (
49
+ render={({
50
+ field: { onChange, onBlur, value },
51
+ fieldState: { error },
52
+ }) => (
39
53
  <Form.Field required>
40
54
  <label>{formatMessage({ id: "dataViews.form.source" })}</label>
41
55
  <SourceSelector
@@ -55,18 +69,20 @@ export default function ControlProperties({ isModification }) {
55
69
  ) : null;
56
70
  }
57
71
 
72
+ const defaultValidation = [
73
+ {
74
+ expressions: [{ shape: "function", value: { isCondition: true } }],
75
+ },
76
+ ];
77
+
58
78
  export const defaultForMode = (controlMode) => {
59
79
  switch (controlMode) {
60
- case "count":
61
- return { errors_resource: null };
80
+ case "error_count":
81
+ return { errors_resource: null, validation: defaultValidation };
62
82
  default:
63
83
  return {
64
84
  resource: null,
65
- validation: [
66
- {
67
- expressions: [{ shape: "function", value: { isCondition: true } }],
68
- },
69
- ],
85
+ validation: defaultValidation,
70
86
  };
71
87
  }
72
88
  };
@@ -10,15 +10,15 @@ const ControlPropertiesForm = ({
10
10
  stepInformation,
11
11
  }) => {
12
12
  const { watch } = useFormContext();
13
+ const { control_mode: controlMode } = watch();
14
+
13
15
  const fieldNames = [
14
16
  "source_id",
15
- "control_properties.errors_resource",
16
17
  "control_properties.resource",
18
+ "control_properties.errors_resource",
17
19
  "control_properties.validation",
18
20
  ];
19
21
 
20
- const { control_mode: controlMode } = watch();
21
-
22
22
  useEffect(() => {
23
23
  if (!_.isEqual(stepInformation?.fieldNames, fieldNames))
24
24
  setStepInformation(1, { ...stepInformation, fieldNames });
@@ -6,126 +6,149 @@ import ClauseViewer from "@truedat/qx/components/common/ClauseViewer";
6
6
  import { getColorById } from "../dataViews/queryableFunctions";
7
7
 
8
8
  export default function ControlPropertiesSummary({ qualityControl }) {
9
- const { control_properties, control_mode } = qualityControl;
9
+ const { control_properties, control_mode } = qualityControl;
10
10
 
11
- if (!control_properties?.resource?.id && !control_properties?.errors_resource?.id) return null;
11
+ if (
12
+ !control_properties?.resource?.id &&
13
+ !control_properties?.errors_resource?.id
14
+ )
15
+ return null;
12
16
 
13
- const controlPropertiesForMode = {
14
- percentage: (
15
- <ControlPropertiesRatioSummary controlProperties={control_properties} />
16
- ),
17
- deviation: (
18
- <ControlPropertiesRatioSummary controlProperties={control_properties} />
19
- ),
20
- count: (
21
- <ControlPropertiesCountSummary controlProperties={control_properties} />
22
- ),
23
- error_count: (
24
- <ControlPropertiesRatioSummary controlProperties={control_properties} />
25
- ),
26
- };
17
+ const controlPropertiesForMode = {
18
+ percentage: (
19
+ <ControlPropertiesRatioSummary controlProperties={control_properties} />
20
+ ),
21
+ deviation: (
22
+ <ControlPropertiesRatioSummary controlProperties={control_properties} />
23
+ ),
24
+ error_count: (
25
+ <ControlPropertiesCountSummary controlProperties={control_properties} />
26
+ ),
27
+ };
27
28
 
28
- return (
29
- <>
30
- <Header as="h5">
31
- <Icon name="puzzle piece" size="small" />
32
- <Header.Content>
33
- <FormattedMessage id="quality_control.form.control_properties" />
34
- </Header.Content>
35
- </Header>
36
- <Segment>
37
- {controlPropertiesForMode[control_mode] || (
38
- <FormattedMessage id="quality_control.control_properties.empty" />
39
- )}
40
- </Segment>
41
- </>
42
- );
29
+ return (
30
+ <>
31
+ <Header as="h5">
32
+ <Icon name="puzzle piece" size="small" />
33
+ <Header.Content>
34
+ <FormattedMessage id="quality_control.form.control_properties" />
35
+ </Header.Content>
36
+ </Header>
37
+ <Segment>
38
+ {controlPropertiesForMode[control_mode] || (
39
+ <FormattedMessage id="quality_control.control_properties.empty" />
40
+ )}
41
+ </Segment>
42
+ </>
43
+ );
43
44
  }
44
45
 
45
46
  const ControlPropertiesRatioSummary = ({ controlProperties }) => {
46
- const parentResource = { id: 0, embedded: controlProperties.resource?.embedded };
47
- return (
48
- <List>
49
- <List.Item>
50
- <List.Header>
51
- <FormattedMessage id="quality_control.ratio.resource" />
52
- </List.Header>
53
- <List.Content>
54
- {controlProperties.resource ? (
55
- <List.Description>
56
- <Label horizontal>
57
- <FormattedMessage
58
- id={`queryables.resource.selector.${controlProperties.resource?.type}`}
59
- />
60
- </Label>
61
- <Label color={getColorById(parentResource?.id)}>
62
- {_.prop("resource.embedded.name")(controlProperties)}
63
- </Label>
64
- </List.Description>
65
- ) : (
66
- <FormattedMessage id="quality_control.ratio.resource.empty" />
67
- )}
68
- </List.Content>
69
- </List.Item>
70
- <List.Item>
71
- <List.Header>
72
- <FormattedMessage id="quality_control.ratio.validation" />
73
- </List.Header>
74
- <List.Content>
75
- {controlProperties.validation ? (
76
- <List.Description>
77
- <ClauseViewer
78
- clause={controlProperties.validation}
79
- parentResource={parentResource}
80
- />
81
- </List.Description>
82
- ) : (
83
- <FormattedMessage id="quality_control.ratio.validation.empty" />
84
- )}
85
- </List.Content>
86
- </List.Item>
87
- </List>
88
- );
47
+ const parentResource = {
48
+ id: 0,
49
+ embedded: controlProperties.resource?.embedded,
50
+ };
51
+ return (
52
+ <List>
53
+ <List.Item>
54
+ <List.Header>
55
+ <FormattedMessage id="quality_control.ratio.resource" />
56
+ </List.Header>
57
+ <List.Content>
58
+ {controlProperties.resource ? (
59
+ <List.Description>
60
+ <Label horizontal>
61
+ <FormattedMessage
62
+ id={`queryables.resource.selector.${controlProperties.resource?.type}`}
63
+ />
64
+ </Label>
65
+ <Label color={getColorById(parentResource?.id)}>
66
+ {_.prop("resource.embedded.name")(controlProperties)}
67
+ </Label>
68
+ </List.Description>
69
+ ) : (
70
+ <FormattedMessage id="quality_control.ratio.resource.empty" />
71
+ )}
72
+ </List.Content>
73
+ </List.Item>
74
+ <List.Item>
75
+ <List.Header>
76
+ <FormattedMessage id="quality_control.ratio.validation" />
77
+ </List.Header>
78
+ <List.Content>
79
+ {controlProperties.validation ? (
80
+ <List.Description>
81
+ <ClauseViewer
82
+ clause={controlProperties.validation}
83
+ parentResource={parentResource}
84
+ />
85
+ </List.Description>
86
+ ) : (
87
+ <FormattedMessage id="quality_control.ratio.validation.empty" />
88
+ )}
89
+ </List.Content>
90
+ </List.Item>
91
+ </List>
92
+ );
89
93
  };
90
94
 
91
95
  const ControlPropertiesCountSummary = ({ controlProperties }) => {
92
- return (
93
- <List>
94
- <List.Item>
95
- <List.Header>
96
- <FormattedMessage id="quality_control.count.errors_resource" />
97
- </List.Header>
98
- <List.Content>
99
- {controlProperties.errors_resource ? (
100
- <List.Description>
101
- <Label horizontal>
102
- <FormattedMessage
103
- id={`queryables.resource.selector.${controlProperties.errors_resource?.type}`}
104
- />
105
- </Label>
106
- <Label
107
- color={getColorById(0)}
108
- >
109
- {_.prop("errors_resource.embedded.name")(controlProperties)}
110
- </Label>
111
- </List.Description>
112
- ) : (
113
- <FormattedMessage id="quality_control.count.errors_resource.empty" />
114
- )}
115
- </List.Content>
116
- </List.Item>
117
- </List>
118
- );
96
+ const parentResource = {
97
+ id: 0,
98
+ embedded: controlProperties.errors_resource?.embedded,
99
+ };
100
+ return (
101
+ <List>
102
+ <List.Item>
103
+ <List.Header>
104
+ <FormattedMessage id="quality_control.count.errors_resource" />
105
+ </List.Header>
106
+ <List.Content>
107
+ {controlProperties.errors_resource ? (
108
+ <List.Description>
109
+ <Label horizontal>
110
+ <FormattedMessage
111
+ id={`queryables.resource.selector.${controlProperties.errors_resource?.type}`}
112
+ />
113
+ </Label>
114
+ <Label color={getColorById(0)}>
115
+ {_.prop("errors_resource.embedded.name")(controlProperties)}
116
+ </Label>
117
+ </List.Description>
118
+ ) : (
119
+ <FormattedMessage id="quality_control.count.errors_resource.empty" />
120
+ )}
121
+ </List.Content>
122
+ </List.Item>
123
+ <List.Item>
124
+ <List.Header>
125
+ <FormattedMessage id="quality_control.ratio.validation" />
126
+ </List.Header>
127
+ <List.Content>
128
+ {controlProperties.validation ? (
129
+ <List.Description>
130
+ <ClauseViewer
131
+ clause={controlProperties.validation}
132
+ parentResource={parentResource}
133
+ />
134
+ </List.Description>
135
+ ) : (
136
+ <FormattedMessage id="quality_control.ratio.validation.empty" />
137
+ )}
138
+ </List.Content>
139
+ </List.Item>
140
+ </List>
141
+ );
119
142
  };
120
143
 
121
144
  ControlPropertiesSummary.propTypes = {
122
- qualityControl: PropTypes.object,
145
+ qualityControl: PropTypes.object,
123
146
  };
124
147
 
125
148
  ControlPropertiesRatioSummary.propTypes = {
126
- controlProperties: PropTypes.object,
149
+ controlProperties: PropTypes.object,
127
150
  };
128
151
 
129
152
  ControlPropertiesCountSummary.propTypes = {
130
- controlProperties: PropTypes.object,
153
+ controlProperties: PropTypes.object,
131
154
  };